上一篇介绍了屏幕手势滑动流程,下面介绍下setSystemUiVisibility()流程,代码依然是基于Android11介绍,网上有关这部分的介绍大部分的view处理逻辑还是在PhonewindowManager类中,Android11已经分离这部分,可参考下本篇。
上一篇连接:systemui中动态禁用虚拟导航栏(一)
当我们想要在activity层级隐藏显示导航栏或状态栏时,会通过类似下面设置不同flag方式实现功能
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
代码流程:
view->setSystemUiVisibility;
ViewRootImpl->recomputeViewAttributes->scheduleTraversals->doTraversal->performTraversals->relayoutWindow->mWindowSession.relayout;
WindowSession->WindowManagerGlobal.getWindowSession()->WindowManagerService
@UnsupportedAppUsage
public static IWindowManager getWindowManagerService() {
synchronized (WindowManagerGlobal.class) {
if (sWindowManagerService == null) {
sWindowManagerService = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
try {
if (sWindowManagerService != null) {
ValueAnimator.setDurationScale(
sWindowManagerService.getCurrentAnimatorScale());
sUseBLASTAdapter = sWindowManagerService.useBLAST();
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowManagerService;
}
}
@UnsupportedAppUsage
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
// Emulate the legacy behavior. The global instance of InputMethodManager
// was instantiated here.
// TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
WindowManagerGlobal类中推断session来自WindowManagerService的openSession()方法,Session是IWindowSession.Stub的实现。
Session->relayout(ViewRootImpl中的relayout()方法)->mService.relayoutWindow回到WindowManagerService类中;
WindowManagerService->relayoutWindow()->updateFocusedWindowLocked()->mRoot.updateFocusedWindowLocked();
RootWindowContainer->dc.updateFocusedWindowLocked();
DisplayContent->updateFocusedWindowLocked()->performLayout()->performLayoutNoTrace()->mDisplayPolicy.beginLayoutLw()
DisplayPolicy->layoutNavigationBar()-mNavigationBarController.setBarShowingLw();
BarController->updateStateLw()->statusbar.setWindowState(mDisplayId, mStatusBarManagerId, state);
又回到上篇的逻辑
private boolean updateStateLw(@StatusBarManager.WindowVisibleState final int state) {
if (mWin != null && state != mState) {
mState = state;
if (DEBUG) Slog.d(mTag, "mState: " + StatusBarManager.windowStateToString(state));
mHandler.post(new Runnable() {
@Override
public void run() {
StatusBarManagerInternal statusbar = getStatusBarInternal();
if (statusbar != null) {
statusbar.setWindowState(mDisplayId, mStatusBarManagerId, state);
}
}
});
return true;
}
return false;
}
CommandQueue是接口StatusBarManagerInternal的实现操作类,可以看上篇了解
最终会调用NavigationBarFragment类中setWindowState()方法。
至于想要如何动态监听禁用导航栏,可以按照上篇的方法,也可以在本章中某个流程禁用