Flou de fenêtre

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

Les flous de fenêtre, ou flous entre fenêtres, sont utilisés pour rendre flou l'écran derrière la fenêtre donnée. Il existe deux types de flous de fenêtre, qui peuvent être utilisés pour obtenir différents effets visuels :

  • Le flou d'arrière-plan vous permet de créer des fenêtres avec des arrière-plans flous, créant un effet de verre dépoli.

  • Flou derrière vous permet de rendre flou tout 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 le montre la figure suivante :

flou d'arrière-plan uniquement

un

flou derrière seulement

b

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

c

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

La fonction de flou de fenêtre fonctionne sur toutes les fenêtres, ce qui signifie qu'elle fonctionne également lorsqu'il y a une autre application derrière votre fenêtre. Cet effet n'est pas le même que l' effet de rendu flou , qui rend flou le contenu à l'intérieur de la même fenêtre. Les flous de fenêtre sont utiles pour les boîtes de dialogue, les feuilles de fond et autres fenêtres flottantes.

Mise en œuvre

Développeurs d'applications

Les développeurs d'applications doivent fournir un rayon de flou pour créer un effet de flou. Le rayon de flou contrôle la densité du flou, c'est-à-dire que plus le rayon est élevé, plus le flou est dense. Un flou de 0 px signifie pas de flou. Pour le flou derrière, un rayon de 20 px crée un bon effet de profondeur de champ, tandis qu'un rayon de flou d'arrière-plan de 80 px crée un bon effet de verre dépoli. Évitez les rayons de flou supérieurs à 150 px, car cela aurait un impact significatif sur les performances.

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

Flou d'arrière-plan

Utilisez le flou d'arrière-plan sur les fenêtres flottantes pour créer un effet d'arrière-plan de fenêtre qui est une image floue 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 flou d’arrière-plan. Ou, dans le thème de la fenêtre, définissez R.attr.windowBackgroundBlurRadius .

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

  3. Facultativement, appelez Window#setBackgroundDrawableResource(int) pour ajouter un arrière-plan de fenêtre rectangulaire pouvant être dessiné avec une couleur translucide. Ou, dans le thème de la fenêtre, définissez R.attr.windowBackground .

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

  5. Gérez les états de flou activés et désactivés. Reportez-vous à la section Directives pour utiliser le flou de fenêtre dans les applications pour plus d'informations.

Flou derrière

Le flou derrière rend flou tout l'écran derrière la fenêtre. Cet effet est utilisé pour diriger l'attention de l'utilisateur vers le contenu de la fenêtre en rendant flou tout ce qui se trouve sur 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 drapeaux de la fenêtre, pour activer le flou derrière. Ou, dans le thème de la fenêtre, définissez R.attr.windowBlurBehindEnabled .

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

  3. En option, choisissez un montant variable complémentaire.

  4. Gérez les états de flou activés et désactivés. Reportez-vous à la section Directives pour utiliser le flou de fenêtre dans les applications pour plus d'informations.

Lignes directrices pour utiliser le flou de fenêtre dans les applications

La prise en charge du flou Windows dépend des éléments suivants :

  • Version Android : les API de flou Windows sont disponibles uniquement sur Android 12 et versions ultérieures. Vérifiez le SDK de l'appareil pour la version Android.

  • Performances graphiques : les appareils dotés de GPU moins performants peuvent choisir de ne pas prendre en charge le flou des fenêtres.

  • État du système : le serveur système peut désactiver temporairement le flou des fenêtres au moment de l'exécution, par exemple pendant le mode d'économie de batterie, lors de la lecture de certains types de contenu vidéo ou en raison d'une dérogation du développeur.

Afin de rendre votre application compatible avec toutes les versions d'Android, les appareils et les états du système, suivez ces directives :

  • Ajoutez un écouteur via WindowManager#addCrossWindowBlurEnabledListener , pour vous avertir lorsque les flous de fenêtre sont activés ou désactivés. De plus, utilisez WindowManager#isCrossWindowBlurEnabled pour demander si le flou de fenêtre est actuellement activé.

  • Implémentez deux versions pour l'arrière-plan de la fenêtre, afin de s'adapter à l'état activé ou désactivé du flou de fenêtre.

    Lorsque les flous sont activés, l'arrière-plan de la fenêtre doit être translucide pour rendre le flou visible. Dans cet état, lorsque les flous sont désactivés, le contenu de la fenêtre chevauche directement le contenu de la fenêtre sous-jacente, rendant la fenêtre superposée moins lisible. Pour éviter un tel effet, lorsque le flou des fenêtres est désactivé, adaptez l'interface utilisateur de l'application comme suit :

    • Pour le flou d'arrière-plan, augmentez l'alpha de l'arrière-plan de la fenêtre pouvant être dessiné, le rendant plus opaque.

    • Pour flouter derrière, ajoutez un calque sombre avec une quantité de luminosité plus élevée.

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

Cette section fournit un exemple concret d'activité qui utilise à la fois le flou 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. Il a des coins arrondis, définis en XML dans l'arrière-plan de la fenêtre dessinable. Il gère correctement différentes versions d'Android, différents appareils (qui ne prennent potentiellement pas en charge le flou de fenêtre) et les modifications activées ou désactivées lors de l'exécution. Il garantit que le contenu de la boîte de dialogue est lisible dans n'importe laquelle de ces conditions en ajustant l'alpha dessinable de l'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 coins arrondis pour la fenêtre, nous définissons l'arrière-plan de la fenêtre dans res/drawable/window_background.xml comme un ShapeDrawable avec des coins arrondis avec un rayon 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>

Les flous de fenêtre brouillent le contenu de la fenêtre située sous l'activité. L'image floue est dessinée sous cette fenêtre d'activité, celle-ci doit donc être translucide pour permettre au flou d'être visible. Pour rendre la fenêtre translucide, nous définissons R.attr.windowIsTranslucent dans le thème d'activité comme suit :

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

OEM et partenaires

Pour que les fenêtres soient floues sur un appareil, l'OEM doit déclarer que l'appareil prend en charge le flou des fenêtres.

Pour vérifier si votre appareil peut prendre en charge le flou des fenêtres, procédez comme suit :

  • Assurez-vous que l'appareil peut gérer la charge GPU supplémentaire. Les appareils bas de gamme peuvent ne pas être en mesure de gérer la charge supplémentaire, ce qui peut entraîner des pertes d'images. N'activez le flou de fenêtre que sur les appareils testés dotés d'une puissance GPU suffisante.

  • Si vous disposez d'un moteur de rendu personnalisé, assurez-vous que votre moteur de rendu implémente la logique de flou. Le moteur de rendu Android 12 par défaut implémente la logique de flou dans BlurFilter.cpp .

Une fois que vous vous êtes assuré que votre appareil peut prendre en charge le flou de fenêtre, 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 flou activé et de flou désactivé, procédez comme suit :

  1. Ouvrez l'interface utilisateur floue.

  2. Activez ou désactivez le flou de fenêtre en activant et en désactivant le flou de fenêtre .

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

Activer et désactiver le flou de la fenêtre

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

  • Depuis les options du développeur :

    Paramètres -> Système -> Options du développeur -> Rendu accéléré par le matériel -> Autoriser les flous au niveau de la fenêtre

  • Depuis le terminal sur un appareil rooté :

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

Pour vérifier si votre appareil Android 12+ prend en charge le flou de fenêtre et si le flou de fenêtre est actuellement activé, exécutez adb shell wm disable-blur sur un appareil rooté.

Dépannage

Utilisez ce qui suit comme guide pour le dépannage 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. Reportez-vous à Activer et désactiver le flou de la fenêtre .

  • Assurez-vous de définir une couleur d’arrière-plan de fenêtre translucide. Une couleur d'arrière-plan de fenêtre opaque masque la zone floue.

L'appareil de test ne prend pas en charge le flou des fenêtres

  • Testez votre application sur l'émulateur Android 12. Pour configurer un émulateur Android, reportez-vous à Configurer un émulateur Android . Tout appareil virtuel Android que vous créez avec l'émulateur prend en charge le flou de fenêtre.

Pas de coins arrondis

La mise à jour de l'option développeur n'active pas les flous

  • Vérifiez si l'appareil est en mode d'économie de batterie ou s'il utilise le tunneling multimédia . Sur certains appareils TV, le flou des fenêtres peut également être désactivé pendant la lecture vidéo.

Flou d'arrière-plan dessiné en plein écran, hors des 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 bonne mise à jour de l'écouteur.