SystemUIOverlayWindow 관리 시스템은 SystemUIOverlayWindow에서 뷰를 표시하고 관리하는 방법을 제공합니다. 현재 이 창은 전체 화면 사용자 전환기와 알림 패널, 키가드를 비롯하여 뷰에 사용됩니다. 이 페이지에서 하지 않는 작업:
- OEM이 창에 추가할 수 있는 항목에 관한 제한사항을 만듭니다.
- 이 페이지에 설명된 추상화를 사용하도록 강제합니다.
개요
SystemUIOverlayWindow 관리 시스템을 사용하여 법적 고지, 전체 화면 사용자 전환기, 후방 카메라, HVAC 컨트롤, 키가드와 같은 뷰를 표시할 수 있습니다. 이 창은 앱 공간 외부에 있으며 이 창을 통해 뷰의 Z-순서, 표시/숨기기 트리거, 전반적인 맞춤설정(뷰 배치, 크기, 투명도, 색상 등)을 제어할 수 있습니다. 동시에, 각 뷰가 숨겨지거나 표시될 때 숨겨지거나 표시되어야 하는 시스템 표시줄이나 기타 시스템 UI 객체의 상태를 걱정하지 않아도 됩니다.
SystemUIOverlayWindow를 활용하려면 뷰 미디에이터를 위한 뷰 컨트롤러를 만듭니다. 미디에이터는 창의 전역 상태 컨트롤러에 전달됩니다. 이러한 뷰 미디에이터에 관한 내용은 다음과 같습니다.
- 뷰 컨트롤러 간에 조정합니다.
- 뷰 컨트롤러의 비즈니스 로직을 보관합니다.
다음은 뷰 컨트롤러(뷰 미디에이터에서 조정됨)에 관한 내용입니다.
- 뷰를 소유합니다.
OverlayViewsMediator가 비즈니스 로직을 연결할 수 있는 setter를 만듭니다.- 뷰의 표시 및 숨기기 애니메이션을 만듭니다.
SystemUI 구성요소인 SystemUIOverlayWindowManager는 전역 상태 컨트롤러로 미디에이터를 초기화하고 등록하는 진입점 역할을 하지만 전역 상태 컨트롤러는 미디에이터가 직접 뷰 컨트롤러를 호출하여 창에서 뷰를 표시하거나 숨길 수 있는 방식으로 뷰 컨트롤러에 연결됩니다.
OverlayViewController
OverlayViewController는 SystemUIOverlayWindow에 표시되는 뷰를 담당하고 뷰가 표시되고 숨겨지는 방식을 제어합니다. 비즈니스 로직에 연결될 수 있도록 필수 리스너를 연결할 수도 있습니다.
중요한 메서드 서명
/**
* Owns a {@link View} that is present in SystemUIOverlayWindow.
*/
public class OverlayViewController {
/**
* Shows content of {@link OverlayViewController}.
*
* Should be used to show view externally and in particular by {@link OverlayViewMediator}.
*/
public final void start();
/**
* Hides content of {@link OverlayViewController}.
*
* Should be used to hide view externally and in particular by {@link OverlayViewMediator}.
*/
public final void stop();
/**
* Inflate layout owned by controller.
*/
public final void inflate(ViewGroup baseLayout);
/**
* Called once inflate finishes.
*/
protected void onFinishInflate();
/**
* Returns {@code true} if layout owned by controller has been inflated.
*/
public final boolean isInflated();
/**
* Subclasses should override this method to implement reveal animations and implement logic
* specific to when the layout owned by the controller is shown.
*
* Should only be overridden by Superclass but not called by any {@link OverlayViewMediator}.
*/
protected void showInternal();
/**
* Subclasses should override this method to implement conceal animations and implement logic
* specific to when the layout owned by the controller is hidden.
*
* Should only be overridden by Superclass but not called by any {@link OverlayViewMediator}.
*/
protected void hideInternal();
/**
* Provides access to layout owned by controller.
*/
protected final View getLayout();
/** Returns the {@link OverlayViewGlobalStateController}. */
protected final OverlayViewGlobalStateController getOverlayViewGlobalStateController();
/** Returns whether the view controlled by this controller is visible. */
public final boolean isVisible();
/**
* Returns the ID of the focus area that should receive focus when this view is the
* topmost view or {@link View#NO_ID} if there is no focus area.
*/
@IdRes
protected int getFocusAreaViewId();
/** Returns whether the view controlled by this controller has rotary focus. */
protected final boolean hasRotaryFocus();
/**
* Sets whether this view allows rotary focus. This should be set to {@code true} for the
* topmost layer in the overlay window and {@code false} for the others.
*/
public void setAllowRotaryFocus(boolean allowRotaryFocus);
/**
* Refreshes the rotary focus in this view if we are in rotary mode. If the view already has
* rotary focus, it leaves the focus alone. Returns {@code true} if a new view was focused.
*/
public boolean refreshRotaryFocusIfNeeded();
/**
* Returns {@code true} if heads up notifications should be displayed over this view.
*/
protected boolean shouldShowHUN();
/**
* Returns {@code true} if navigation bar insets should be displayed over this view. Has no
* effect if {@link #shouldFocusWindow} returns {@code false}.
*/
protected boolean shouldShowNavigationBarInsets();
/**
* Returns {@code true} if status bar insets should be displayed over this view. Has no
* effect if {@link #shouldFocusWindow} returns {@code false}.
*/
protected boolean shouldShowStatusBarInsets();
/**
* Returns {@code true} if this view should be hidden during the occluded state.
*/
protected boolean shouldShowWhenOccluded();
/**
* Returns {@code true} if the window should be focued when this view is visible. Note that
* returning {@code false} here means that {@link #shouldShowStatusBarInsets} and
* {@link #shouldShowNavigationBarInsets} will have no effect.
*/
protected boolean shouldFocusWindow();
/**
* Returns {@code true} if the window should use stable insets. Using stable insets means that
* even when system bars are temporarily not visible, inset from the system bars will still be
* applied.
*
* NOTE: When system bars are hidden in transient mode, insets from them will not be applied
* even when the system bars become visible. Setting the return value to {@true} here can
* prevent the OverlayView from overlapping with the system bars when that happens.
*/
protected boolean shouldUseStableInsets();
/**
* Returns the insets types to fit to the sysui overlay window when this
* {@link OverlayViewController} is in the foreground.
*/
@WindowInsets.Type.InsetsType
protected int getInsetTypesToFit();
/**
* Optionally returns the sides of enabled system bar insets to fit to the sysui overlay window
* when this {@link OverlayViewController} is in the foreground.
*
* For example, if the bottom and left system bars are enabled and this method returns
* WindowInsets.Side.LEFT, then the inset from the bottom system bar will be ignored.
*
* NOTE: By default, this method returns {@link #INVALID_INSET_SIDE}, so insets to fit are
* defined by {@link #getInsetTypesToFit()}, and not by this method, unless it is overridden
* by subclasses.
*
* NOTE: {@link #NO_INSET_SIDE} signifies no insets from any system bars will be honored. Each
* {@link OverlayViewController} can first take this value and add sides of the system bar
* insets to honor to it.
*
* NOTE: If getInsetSidesToFit is overridden to return {@link WindowInsets.Side}, it always
* takes precedence over {@link #getInsetTypesToFit()}. That is, the return value of {@link
* #getInsetTypesToFit()} will be ignored.
*/
@WindowInsets.Side.InsetsSide
protected int getInsetSidesToFit();
}
OverlayPanelViewController
OverlayPanelViewController 컨트롤러는 OverlayViewController를 확장하고 슈퍼클래스에 추가 드래그 애니메이션 기능을 제공합니다.
OverlayViewMediator
OverlayViewMediator에는 여러 OverlayViewController 인스턴스를 표시하거나 숨기는 비즈니스 로직이 포함되어 있으므로 뷰 컨트롤러 간의 조정을 관리할 수도 있습니다.
/**
* Controls when to show and hide {@link OverlayViewController}(s).
*/
public interface OverlayViewMediator {
/**
* Register listeners that could use ContentVisibilityAdjuster to show/hide content.
*
* Note that we do not unregister listeners because SystemUI components are expected to live
* for the lifecycle of the device.
*/
void registerListeners();
/**
* Allows for post-inflation callbacks and listeners to be set inside required {@link
* OverlayViewController}(s).
*/
void setupOverlayContentViewControllers();
}
SystemUIOverlayWindowManager
SystemUIOverlayWindowManager는 SystemUIOverlayWindow 관리 시스템이 OverlayViewGlobalStateController로 OverlayViewMediator 인스턴스를 초기화하고 등록하는 진입점으로 기능하는 SystemUI 객체 역할을 담당합니다.

OverlayViewGlobalStateController
OverlayViewGlobalStateController는 OverlayViewController 인스턴스에서 호출을 수신하여 자신을 표시하거나 숨깁니다. 따라서 SystemUIOverlayWindow에 표시되거나 숨겨지는 대상의 상태도 유지합니다.
뷰 표시 흐름은 다음과 같습니다.

뷰 숨기기 흐름
뷰 숨기기 흐름은 다음과 같습니다.

공개 메서드 서명
공개 메서드 서명은 다음과 같이 인코딩됩니다.
/**
* This controller is responsible for the following:
* <p><ul>
* <li>Holds the global state for SystemUIOverlayWindow.
* <li>Allows {@link SystemUIOverlayWindowManager} to register {@link OverlayViewMediator}(s).
* <li>Enables {@link OverlayViewController)(s) to reveal/conceal themselves while respecting the
* global state of SystemUIOverlayWindow.
* </ul>
*/
@SysUISingleton
public class OverlayViewGlobalStateController {
/**
* Register {@link OverlayViewMediator} to use in SystemUIOverlayWindow.
*/
public void registerMediator(OverlayViewMediator overlayViewMediator);
/**
* Show content in Overlay Window using {@link OverlayPanelViewController}.
*
* This calls {@link OverlayViewGlobalStateController#showView(OverlayViewController, Runnable)}
* where the runnable is nullified since the actual showing of the panel is handled by the
* controller itself.
*/
public void showView(OverlayPanelViewController panelViewController);
/**
* Show content in Overlay Window using {@link OverlayViewController}.
*/
public void showView(OverlayViewController viewController, @Nullable Runnable show);
/**
* Hide content in Overlay Window using {@link OverlayPanelViewController}.
*
* This calls {@link OverlayViewGlobalStateController#hideView(OverlayViewController, Runnable)}
* where the runnable is nullified since the actual hiding of the panel is handled by the
* controller itself.
*/
public void hideView(OverlayPanelViewController panelViewController);
/**
* Hide content in Overlay Window using {@link OverlayViewController}.
*/
public void hideView(OverlayViewController viewController, @Nullable Runnable hide);
/** Returns {@code true} is the window is visible. */
public boolean isWindowVisible();
/**
* Sets the {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flag of the
* sysui overlay window.
*/
public void setWindowNeedsInput(boolean needsInput);
/** Returns {@code true} if the window is focusable. */
public boolean isWindowFocusable();
/** Sets the focusable flag of the sysui overlawy window. */
public void setWindowFocusable(boolean focusable);
/** Inflates the view controlled by the given view controller. */
public void inflateView(OverlayViewController viewController);
/**
* Return {@code true} if OverlayWindow is in a state where HUNs should be displayed above it.
*/
public boolean shouldShowHUN();
/**
* Set the OverlayViewWindow to be in occluded or unoccluded state. When OverlayViewWindow is
* occluded, all views mounted to it that are not configured to be shown during occlusion will
* be hidden.
*/
public void setOccluded(boolean occluded);
}
SysUIOverlayWindow에 뷰를 추가하는 방법
자세한 내용은 Codelab을 참고하세요.
1단계: SysUIOverlayWindow에 ViewStub 추가
2단계: OverlayViewController 만들기
새 ViewStub을 사용하여 삽입할 수 있는 새 OverlayViewController를 만듭니다.
3단계: OverlayViewMediator
삽입할 수 있는 새 OverlayViewMediator를 만들거나 기존 OverlayViewMediator를 사용하고(4단계 건너뛰기) 리스너를 등록하여 새 OverlayViewController를 숨기거나 표시합니다.
4단계: 새 OverlayViewMediator 구성
새 OverlayViewMediator를
OverlayWindowModule과 config_carSystemUIOverlayViewsMediator에 추가합니다.
주의사항
SysUIPrimaryWindow가 전체 화면을 덮으면 창 아래의 모든 요소는 터치 이벤트를 등록하지 않습니다. 따라서 창이 전체 화면을 차지하지만 콘텐츠가 네거티브 스페이스를 남기면 네거티브 스페이스를 흐리게 처리하고 네거티브 스페이스에 리스너를 연결하여 창의 콘텐츠를 닫을 수 있습니다.