SystemUIOverlayWindow
관리 시스템은 SystemUIOverlayWindow
에서 뷰를 표시하고 관리하는 방법을 제공합니다. 현재 이 창은 전체 화면 사용자 전환기와 알림 패널, 키가드를 비롯하여 뷰에 사용됩니다. 이 페이지에서 하지 않는 작업:
- OEM이 창에 추가할 수 있는 항목에 관한 제한사항을 만듭니다.
- 이 페이지에 설명된 추상화를 사용하도록 강제합니다.
개요
SystemUIOverlayWindow
관리 시스템을 사용하여 법적 고지, 전체 화면 사용자 전환기, 후방 카메라, HVAC 컨트롤, 키가드와 같은 뷰를 표시할 수 있습니다. 이 창은 앱 공간 외부에 있으며 이 창을 통해 뷰의 Z-순서, 표시/숨기기 트리거, 전반적인 맞춤설정(뷰 배치, 크기, 투명도, 색상 등)을 제어할 수 있습니다. 동시에, 각 뷰가 숨겨지거나 표시될 때 숨겨지거나 표시되어야 하는 시스템 표시줄이나 기타 시스템 UI 객체의 상태를 걱정하지 않아도 됩니다.
SystemUIOverlayWindow
를 활용하려면 뷰 미디에이터를 위한 뷰 컨트롤러를 만듭니다. 미디에이터는 창의 전역 상태 컨트롤러에 전달됩니다. 이러한 뷰 미디에이터에 관한 내용은 다음과 같습니다.
- 뷰 컨트롤러 간에 조정합니다.
- 뷰 컨트롤러의 비즈니스 로직을 보관합니다.
다음은 뷰 컨트롤러(뷰 미디에이터에서 조정됨)에 관한 내용입니다.
- 뷰를 소유합니다.
OverlayViewsMediator
가 비즈니스 로직을 연결할 수 있는 setter를 만듭니다.- 뷰의 표시 및 숨기기 애니메이션을 만듭니다.
SystemUI 구성요소인 SystemUIOverlayWindow
Manager는 전역 상태 컨트롤러로 미디에이터를 초기화하고 등록하는 진입점 역할을 하지만 전역 상태 컨트롤러는 미디에이터가 직접 뷰 컨트롤러를 호출하여 창에서 뷰를 표시하거나 숨길 수 있는 방식으로 뷰 컨트롤러에 연결됩니다.
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
가 전체 화면을 덮으면 창 아래의 모든 요소는 터치 이벤트를 등록하지 않습니다. 따라서 창이 전체 화면을 차지하지만 콘텐츠가 네거티브 스페이스를 남기면 네거티브 스페이스를 흐리게 처리하고 네거티브 스페이스에 리스너를 연결하여 창의 콘텐츠를 닫을 수 있습니다.