창 흐림

Android 12에서 공개 API는 창 흐림 효과(예: 배경 흐림 및 뒤 흐림)를 구현하는 데 사용할 수 있습니다. 코드, 개발자 문서 또는 UI 표기법에서 창 간 흐림이라고도 하는 창 흐림을 볼 수 있지만 창 간 흐림은 창 흐림과 동일합니다.

이러한 API를 사용하면 자신의 창 뒤에 있는 모든 것을 흐리게 처리할 수 있습니다. 배경이 흐려진 창을 만들어 젖빛 유리 효과를 만들거나 뒤의 전체 화면이 흐려진 창을 표시하여 피사계 심도 효과를 만들 수 있습니다. 두 가지 효과를 결합할 수도 있습니다.

배경 흐림만

1

뒤에만 흐리게

2

뒤 및 배경 흐림

그림 1. 배경 흐림만(1), 뒤에만 흐림(2), 배경 흐림 및 뒤 흐림(3)

창 흐림 기능은 창 전체에서 작동하므로 보고 있는 창 뒤에 다른 앱이 있는 경우에도 작동합니다. 이는 동일한 앱 내에서 창 내부의 콘텐츠를 흐리게 하는 흐림 렌더링 효과 와 다릅니다. 창 흐림 효과는 대화 상자, 하단 시트 및 기타 부동 창에 유용합니다.

이 기능은 상당한 GPU 리소스를 사용한다는 점에 유의해야 합니다. 따라서 모든 Android 기기에서 사용할 수 있지만 GPU 성능이 충분한 기기에서만 지원됩니다.

구현

OEM 및 파트너

창 흐림은 기본적으로 비활성화되어 있습니다. 장치에서 흐림 기능을 활성화하려면 다음을 수행하십시오.

  • 장치가 추가 GPU 로드를 처리할 수 있는지 확인합니다. 블러 작업은 비용이 많이 들고 저가형 장치에서는 프레임이 떨어질 수 있습니다. GPU 전원이 충분한 장치에서만 이 기능을 활성화하십시오.
  • librenderengine 이 흐림 로직을 구현하는지 확인하십시오. 기본 Android 12 렌더 엔진은 하지만 모든 사용자 지정 렌더 엔진은 흐림 로직 자체를 구현해야 합니다.
  • 다음 표면 플링거 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. UI에서:

    설정 -> 시스템 -> 개발자 옵션 -> 하드웨어 가속 렌더링 -> 창 수준 흐림 허용

  2. 터미널에서(기기가 루팅되어야 함):

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

장치에 흐림 기능을 지원하는 기능이 있는 경우에만 창 흐림 기능을 켜거나 끌 수 있습니다. (윈도우 블러를 지원하지 않는 장치는 이 기능을 활성화할 수 없습니다.) 기본적으로 블러를 지원하는 장치에서는 블러가 활성화됩니다.

장치에 대해 흐림 효과를 활성화할 때 배터리 절약 모드 또는 멀티미디어 터널링과 같은 다른 요소가 블러를 비활성화할 수 있음을 고려하십시오. 블러는 필요한 모든 조건이 충족될 때 활성화됩니다. 블러는 지원 되며 비활성화할 수 있는 것은 없습니다. 흐림 기능의 현재 상태가 "활성화"되었는지 확인하려면 adb shell wm disable-blur 명령을 사용하십시오.

확인

블러 기능 버전이 의도한 대로 작동하도록 하려면 blurEnabled 가 변경될 때마다 UI 요소를 다시 그리도록 UI 로직을 구현하십시오( addCrossWindowBlurEnabledListener 에서 보고한 대로).

  1. 블러가 있는 UI를 엽니다.
  2. UI 또는 CLI에서 창 흐림 효과 켜기 및 끄기에 대해 제공된 단계를 사용합니다.
  3. UI가 예상대로 흐릿한 UI로 변경되는지 확인합니다.

문제 해결

유효성 검사 중 문제 해결을 위한 지침으로 다음을 사용하십시오.

흐림 효과 없음

  • CLI를 사용하거나 설정 으로 이동하여 현재 흐림 효과가 활성화되어 있고 하드웨어에서 이를 지원하는지 확인합니다.

    1. adb shell wm disable-blur 명령을 사용하면 해당 장치에서 흐림이 지원되는지 여부와 현재 활성화되어 있는지 여부를 인쇄합니다.
    2. 설정 -> 시스템 -> 개발자 옵션 -> 하드웨어 가속 렌더링 -> 창 수준 블러 허용으로 이동합니다. 옵션을 찾을 수 없으면 기기에서 흐림 효과가 지원되지 않는 것입니다.
  • 반투명 창 배경색을 설정했는지 확인하십시오. 불투명한 창 배경색은 흐릿한 영역을 숨깁니다(덮음).

테스트 장치는 창 흐림 효과를 지원하지 않습니다.

  • Android 12 에뮬레이터에서 애플리케이션을 테스트합니다. Android 에뮬레이터를 설정하려면 Android 에뮬레이터 설정 지침을 참조하세요. 에뮬레이터로 만든 모든 Android 가상 장치는 창 흐림 효과를 지원합니다.

둥근 모서리 없음

  • 창 배경 드로어블 - Window#setBackgroundDrawable 을 설정하여 둥근 모서리를 정의합니다. 이것은 흐림 영역의 윤곽을 결정합니다.

개발자 옵션을 업데이트해도 흐림 효과가 활성화되지 않습니다.

  • 장치가 배터리 절약 모드인지, 멀티미디어 터널링(TV용)을 사용 중인지 또는 다른 것이 흐림 기능을 비활성화하는지 확인하십시오.

창 경계가 아닌 전체 화면으로 배경 흐림 처리됨

  • 창이 부동으로 표시되어 있는지 확인하십시오. - android:windowIsFloating
  • 창 배경 드로어블 - Window#setBackgroundDrawable 을 설정했는지 확인하십시오. 이것은 흐림 영역의 윤곽을 결정합니다.

리스너의 업데이트가 화면에 적용되지 않습니다.

  • 리스너가 운영하는 인스턴스가 업데이트 되지 않는 동안 윈도우가 소멸되고 재생성되는지 확인합니다. 리스너 업데이트가 이전 창 인스턴스에 적용될 수 있습니다.