窗口模糊

在 Android 12 中,公共 API 可用於實現窗口模糊效果(例如背景模糊和背後模糊)。請注意,儘管您可能會在代碼、開發人員文檔或 UI 表示法中看到窗口模糊也稱為交叉窗口模糊,但交叉窗口模糊與窗口模糊相同。

使用這些 API,您可以模糊自己窗口後面的任何內容。您可以創建背景模糊的窗口,創建磨砂玻璃效果,或顯示窗口,使其後面的整個屏幕模糊,創建景深效果。您也可以將這兩種效果結合起來。

僅背景模糊

1

只在後面模糊

2

背後和背景模糊

3

圖 1. Background blur only (1), blur only behind (2), background blur and blur behind (3)

窗口模糊功能適用於整個窗口,這意味著當您正在查看的窗口後面有另一個應用程序時,它也可以工作。這與模糊渲染效果不同,後者會模糊同一應用程序中窗口內的內容。窗口模糊對於對話框和底部工作表以及其他浮動窗口很有用。

請務必注意,此功能使用大量 GPU 資源。因此,儘管它適用於所有 Android 設備,但僅支持那些具有足夠 GPU 能力的設備。

執行

原始設備製造商和合作夥伴

默認情況下禁用窗口模糊。要在設備上啟用模糊功能,請執行以下操作:

  • 確保設備可以處理額外的 GPU 負載 - 模糊操作很昂貴,並且在低端設備上,它可能會導致丟幀。僅在具有足夠 GPU 能力的設備上啟用此功能。
  • 確保您的librenderengine實現了模糊邏輯 - 默認的 Android 12 渲染引擎會這樣做,但任何自定義渲染引擎都必須自己實現模糊邏輯。
  • 通過設置以下surface flinger sysprop來啟用模糊:
# enable surface flinger window blurs
PRODUCT_PROPERTY_OVERRIDES += \
       ro.surface_flinger.supports_background_blur=1

第三方開發商

請參閱示例和源代碼部分以查看示例代碼。系統服務器可以在運行時禁用窗口模糊。因此,應用程序必須提供一個後備的、無模糊的版本。否則,如果模糊因為被禁用而未渲染,則窗口背景可能非常透明,以至於窗口內的內容變得難以辨認。如果您的應用不提供後備應用版本,請確保您的 UI 在啟用模糊和禁用模糊的情況下都能正常工作。以下是可以隨時禁用模糊的三種情況:

  1. 該設備運行的是 Android 11 或更低版本。由於窗口模糊僅在 Android 12 及更高版本的設備上可用,因此應用必須為運行 Android 11 及更低版本的設備實現備用的模糊體驗替代方案。
  2. 該設備不支持窗口模糊,因為它們很昂貴,因此低端設備在渲染它們時可能會丟幀。對於這種情況,應用程序必須提供回退的模糊體驗。
  3. 系統服務器(例如,在省電模式期間,或由於開發人員設置或隧道模式)在運行時禁用模糊。

上面的第2點和第 3點都由使用WindowManager.addCrossWindowBlurEnabledListener註冊的偵聽器報告。如果您的應用程序使用模糊 API,請註冊此偵聽器並在調用該偵聽器時更新您的 UI,如果您想為啟用模糊和禁用模糊狀態使用不同的 UI。註冊後,立即調用偵聽器以報告當前是否啟用了模糊。

使用以下方法實現模糊功能:

示例和來源

public class BlurActivity extends Activity {
   private final int mBackgroundBlurRadius = 150;
   private final Drawable mBackgroundDrawableWithBlur;
   private final Drawable mBackgroundDrawableNoBlur;

   private final int mBlurBehindRadius = 50;
   private final float mDimAmountWithBlur = 0.1f;
   private final float mDimAmountNoBlur = 0.6f;


   private Consumer<Boolean> mCrossWindowBlurEnabledListener = enabled -> {
       getWindow().setBackgroundDrawable(
               enabled ? mBackgroundDrawableWithBlur : mBackgroundDrawableNoBlur);
       getWindow().setDimAmount(enabled ? mDimAmountWithBlur : mDimAmountNoBlur);
   };

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.blur_activity);

       mBackgroundDrawableWithBlur = getContext().getResources().getDrawable(
               R.drawable.window_background_with_blur);
       mBackgroundDrawableNoBlur = getContext().getResources().getDrawable(
               R.drawable.window_background_no_blur);

       if (Android version >= Android S) {
           getWindow().addFlags(
                   WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
           window.getAttributes().setBlurBehindRadius(mBlurBehindRadius);
           window.setBackgroundBlurRadius(mBackgroundBlurRadius);
           getWindow().getDecorView().addOnAttachStateChangeListener(
                                         new View.OnAttachStateChangeListener() {
                    @Override
                    public void onViewAttachedToWindow(View v) {
                        getWindowManager().addCrossWindowBlurEnabledListener(
                                                     blurEnabledListener);
                    }

                       @Override
                   public void onViewDetachedFromWindow(View v) {
                       getWindowManager().removeCrossWindowBlurEnabledListener(
                                                      blurEnabledListener);
                     }
           });
       }
       getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
   }

打開和關閉窗口模糊

有兩種方法可以允許和禁止窗口模糊。

  1. 從用戶界面:

    設置 -> 系統 -> 開發者選項 -> 硬件加速渲染 -> 允許窗口級模糊

  2. 從終端(設備必須植根):

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

如果您的設備能夠支持模糊,您只能打開或關閉窗口模糊功能。 (不支持窗口模糊的設備無法啟用該功能。)默認情況下,在支持它們的設備上啟用模糊。

當您為設備啟用模糊時,請考慮諸如省電模式或多媒體隧道之類的其他功能可以禁用它們。當滿足所有必要條件時啟用模糊 - 它們受到支持,並且沒有任何東西禁用它們。要查看模糊功能的當前狀態是否為“啟用”,請使用adb shell wm disable-blur命令。

驗證

為確保您的模糊功能版本按預期工作,請實現 UI 邏輯,以便在blurEnabled更改時重繪 UI 元素(如addCrossWindowBlurEnabledListener報告的那樣)。

  1. 打開有模糊的 UI。
  2. 使用從 UI 或 CLI打開和關閉窗口模糊給出的步驟。
  3. 驗證 UI 是否按預期更改為模糊的。

故障排除

使用以下內容作為驗證期間故障排除的指南。

沒有畫模糊

  • 通過使用 CLI 或導航到Settings來驗證當前是否啟用了模糊(並且您的硬件支持它們)。

    1. 使用adb shell wm disable-blur命令,該命令會打印出該設備是否支持模糊以及當前是否啟用。
    2. 導航到設置 -> 系統 -> 開發人員選項 -> 硬件加速渲染 -> 允許窗口級模糊。如果您在此處找不到該選項,則您的設備不支持模糊。
  • 確保設置半透明的窗口背景顏色;不透明的窗口背景顏色隱藏(覆蓋)模糊區域。

測試設備不支持窗口模糊

  • 在 Android 12 模擬器上測試您的應用程序。要設置 Android 模擬器,請參閱設置 Android 模擬器說明。您使用模擬器創建的任何 Android 虛擬設備都將支持窗口模糊。

沒有圓角

  • 通過設置窗口背景可繪製對象 - Window#setBackgroundDrawable來定義圓角。這決定了模糊區域的輪廓。

更新開發者選項不會啟用模糊

  • 檢查設備是否處於省電模式,是否使用多媒體隧道(用於電視),或者是否有其他原因禁用模糊功能。

背景模糊繪製全屏,不在窗口範圍內

  • 確保您的窗口被標記為浮動 - android:windowIsFloating
  • 確保您已設置窗口背景可繪製對象 - Window#setBackgroundDrawable 。這決定了模糊區域的輪廓。

來自監聽器的更新不會應用到屏幕上

  • 檢查窗口是否被銷毀並重新創建,而偵聽器正在操作的實例沒有更新。偵聽器更新可能會應用於舊窗口實例。