本文是基于R代码分支编写,S暂时未涉。
手机导航栏是手机系统的一个重要功能,导航栏随着系统功能的不同会有不同状态,熟悉他们的创建和状态改变有助于我们遇到类似问题的总结。
Navigationbar 绘制流程涉及代码路径:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
为Navigationbar的入口函数,通过执行StatusBar.java 中的start() 方法来创建Navigationbar。
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@Override
public void start() {
//省略代码
createAndAddWindows(result);
//省略代码
}
createAndAddWindows 方法调用makeStatusBarView() 。
public void createAndAddWindows(@Nullable RegisterStatusBarResult result) {
makeStatusBarView(result);
mNotificationShadeWindowController.attach();
mStatusBarWindowController.attach();
}
makeStatusBarView() 方法中包含提前加载更新使用资源文件,以及更新显示尺寸,需要在
那些设备显示等,最主要的是调用createNavigationBar创建导航栏。
protected void makeStatusBarView(@Nullable RegisterStatusBarResult result) {
final Context context = mContext;
//更新尺寸
updateDisplaySize(); // populates mDisplayMetrics
//更新资源
updateResources();
//更新主题
updateTheme();
//获取View
inflateStatusBarWindow();
// 省略代码
//创建导航栏
createNavigationBar(result);
// 省略代码
}
createNavigationBar方法调用NavigationBarController.java的createNavigationBars遍历显示设备进行创建。
protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
mNavigationBarController.createNavigationBars(true /* includeDefaultDisplay */, result);
}
下面我们进入到NavigationBarController.java进行查看。
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
public void createNavigationBars(final boolean includeDefaultDisplay,
RegisterStatusBarResult result) {
//获取当前的displays的显示数据
Display[] displays = mDisplayManager.getDisplays();
for (Display display : displays) {
//根据Display 数据创建 NavigationBar
if (includeDefaultDisplay || display.getDisplayId() != DEFAULT_DISPLAY) {
createNavigationBar(display, result);
}
}
}
createNavigationBar() 方法主要做的事情
1.查看系统的config_showNavigationBar 值是否需要显示导航栏
2.创建NavigationBar 其实也是fragment
3.设置 NavigationBarFragment.create创建原始Fragment
void createNavigationBar(Display display, RegisterStatusBarResult result) {
//判断display的有效性
if (display == null) {
return;
}
final int displayId = display.getDisplayId();
final boolean isOnDefaultDisplay = displayId == DEFAULT_DISPLAY;
//获取WindowManagerService 句柄
final IWindowManager wms = WindowManagerGlobal.getWindowManagerService();
try {
// 通过WindowMangerService 获取到 DisPlayPolicy.java 的属性值
// DisPlayPolicy.java 通过getResources().getBoolean(R.bool.config_showNavigationBar);
// 决定是否显示NavigationBar
if (!wms.hasNavigationBar(displayId)) {
return;
}
} catch (RemoteException e) {
return;
}
final Context context = isOnDefaultDisplay
? mContext
: mContext.createDisplayContext(display);
//看到这里可以看出 NavigationBar 其实就是 Framegement
//NavigationBarFragment.create 里面加载布局
//设置 传递 FragmentListener
NavigationBarFragment.create(context, (tag, fragment) -> {
NavigationBarFragment navBar = (NavigationBarFragment) fragment;
//创建 LightBarController
LightBarController lightBarController = isOnDefaultDisplay
? Dependency.get(LightBarController.class)
: new LightBarController(context,
Dependency.get(DarkIconDispatcher.class),
Dependency.get(BatteryController.class),
Dependency.get(NavigationModeController.class));
navBar.setLightBarController(lightBarController);
AutoHideController autoHideController = isOnDefaultDisplay
? Dependency.get(AutoHideController.class)
: new AutoHideController(context, mHandler,
Dependency.get(IWindowManager.class));
navBar.setAutoHideController(autoHideController);
navBar.restoreAppearanceAndTransientState();
//SparseArray 对 displayId 和 NavigationBar 进行集合管理
mNavigationBars.append(displayId, navBar);
if (result != null) {
//显示 NativeBar
navBar.setImeWindowStatus(display.getDisplayId(), result.mImeToken,
result.mImeWindowVis, result.mImeBackDisposition,
result.mShowImeSwitcher);
}
});
}
接下来查看一下NavigationBarFragment.java中的onCreate方法方法里面主要做的是
给View设置LayoutParams属性,Inflater navigation_bar_window布局文件
在onViewAttachedToWindow的时候将 fragment 替换navigation_bar_frame
navigation_bar_frame也是自定义控件,可以查看到navigation_bar_frame 对应的是
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
public static View create(Context context, FragmentListener listener) {
// 创建View的时候给 LayoutParams 设置属性
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_SLIPPERY,
PixelFormat.TRANSLUCENT);
lp.token = new Binder();
lp.setTitle("NavigationBar" + context.getDisplayId());
lp.accessibilityTitle = context.getString(R.string.nav_bar);
lp.windowAnimations = 0;
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COLOR_SPACE_AGNOSTIC;
//navigationBarView 布局文件 navigation_bar_window 其实为自定义控件
// TODO 此处并不是 navigationBar 根布局 ,真正布局 在本类 onCreateView 方法中加载 R.layout.navigation_bar
View navigationBarView = LayoutInflater.from(context).inflate(
R.layout.navigation_bar_window, null);
if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
if (navigationBarView == null) return null;
final NavigationBarFragment fragment = FragmentHostManager.get(navigationBarView)
.create(NavigationBarFragment.class);
navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
final FragmentHostManager fragmentHost = FragmentHostManager.get(v);
// 使用 FragmentHostManager 属性 对 fragment也就是 NavigationBarFragment
// 进行替换 成为id 为 navigation_bar_frame的控件
fragmentHost.getFragmentManager().beginTransaction()
.replace(R.id.navigation_bar_frame, fragment, TAG)
.commit();
fragmentHost.addTagListener(TAG, listener);
}
@Override
public void onViewDetachedFromWindow(View v) {
FragmentHostManager.removeAndDestroy(v);
navigationBarView.removeOnAttachStateChangeListener(this);
}
});
context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
//返回创建的 navigationBarView
return navigationBarView;
}
因NavigationBarFragment.java是framework,在创建完成的时候会回调 onViewCreated 方法。在onViewCreated中注册图标的点击事件,监听亮灭屏变化以及用户身份切换等操作。
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//TODO View 创建回调
//省略代码
//桌面 返回键 任务栏按键的 click 点击事件入口方法
prepareNavigationBarView();
checkNavBarModes();
//监听 亮灭屏 用户身份切换等状态变化
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_USER_SWITCHED);
mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter,
Handler.getMain(), UserHandle.ALL);
notifyNavigationBarScreenOn();
//省略代码
initSecondaryHomeHandleForRotation();
}
prepareNavigationBarView 为具体的点击事件注册
private void prepareNavigationBarView() {
//设置avigationBar 图标以及背景
mNavigationBarView.reorient();
// 设置任务栏按键的点击事件监听
ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
recentsButton.setOnClickListener(this::onRecentsClick);
recentsButton.setOnTouchListener(this::onRecentsTouch);
recentsButton.setLongClickable(true);
recentsButton.setOnLongClickListener(this::onLongPressBackRecents);
//设置发明返回键的点击事件
ButtonDispatcher backButton = mNavigationBarView.getBackButton();
backButton.setLongClickable(true);
//设置桌面的点击事件
ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
homeButton.setOnTouchListener(this::onHomeTouch);
homeButton.setOnLongClickListener(this::onHomeLongClick);
//设置无障碍模式的点击事件
ButtonDispatcher accessibilityButton = mNavigationBarView.getAccessibilityButton();
accessibilityButton.setOnClickListener(this::onAccessibilityClick);
accessibilityButton.setOnLongClickListener(this::onAccessibilityLongClick);
updateAccessibilityServicesState(mAccessibilityManager);
updateScreenPinningGestures();
}
R.layout.navigation_bar 中的navigation_bar为自定义控件,根据自定义控件属性对应的类是NavigationBarInflaterView.java从构造方法中可以看出调用createInflaters创建布局
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
public NavigationBarInflaterView(Context context, AttributeSet attrs) {
super(context, attrs);
//根据构造方法 可以查看到 更新 ORIENTATION 创建子view
createInflaters();
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
}
创建 横屏和竖屏的Inflater
void createInflaters() {
//创建 LayoutInflater
mLayoutInflater = LayoutInflater.from(mContext);
Configuration landscape = new Configuration();
landscape.setTo(mContext.getResources().getConfiguration());
landscape.orientation = Configuration.ORIENTATION_LANDSCAPE;
//创建 Landscape LayoutInflater
mLandscapeInflater = LayoutInflater.from(mContext.createConfigurationContext(landscape));
}
view的生命周期中调用Inflater 之后调用的 onFinishInflate 确定点击范围
protected void onFinishInflate() {
super.onFinishInflate();
// View 的生命周期,Inflater 之后调用的 onFinishInflate
// 更新确定点击范围
inflateChildren();
// 清除View
clearViews();
// 加载 任务栏 桌面 以及 返回按钮 布局文件
inflateLayout(getDefaultLayout());
}
通过getDefaultLayout字符串来确定将要加载的按钮布局的位置和大小。
protected String getDefaultLayout() {
final int defaultResource = QuickStepContract.isGesturalMode(mNavBarMode)
? R.string.config_navBarLayoutHandle//手势下显示的字符结构
: mOverviewProxyService.shouldShowSwipeUpUI() // 是否显示上滑动的显示字符结构
? R.string.config_navBarLayoutQuickstep
//config_navBarLayout 为
// <string name="config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]</string>
: R.string.config_navBarLayout;
return getContext().getString(defaultResource);
}
inflateLayout根据getDefaultLayout 返回的字符串进行分割,并插入空格以及将控件添加到父布局
protected void inflateLayout(String newLayout) {
mCurrentLayout = newLayout;
if (newLayout == null) {
newLayout = getDefaultLayout();
}
//根据";" 字符来分割上一个 config_navBarLayout 字符串
String[] sets = newLayout.split(GRAVITY_SEPARATOR, 3);
if (sets.length != 3) {
Log.d(TAG, "Invalid layout.");
newLayout = getDefaultLayout();
sets = newLayout.split(GRAVITY_SEPARATOR, 3);
}
// 根据"," 再对每个分隔符进行分割
// 分割后 eft[.5W]和back[1WC]
String[] start = sets[0].split(BUTTON_SEPARATOR);
// 分割后 home
String[] center = sets[1].split(BUTTON_SEPARATOR);
// 分割后 recent[1WC]和right[.5W]
String[] end = sets[2].split(BUTTON_SEPARATOR);
inflateButtons(start, mHorizontal.findViewById(R.id.ends_group),
false /* landscape */, true /* start */);
inflateButtons(start, mVertical.findViewById(R.id.ends_group),
true /* landscape */, true /* start */);
inflateButtons(center, mHorizontal.findViewById(R.id.center_group),
false /* landscape */, false /* start */);
inflateButtons(center, mVertical.findViewById(R.id.center_group),
true /* landscape */, false /* start */);
// 插入空格字符串
addGravitySpacer(mHorizontal.findViewById(R.id.ends_group));
// 插入空格字符串
addGravitySpacer(mVertical.findViewById(R.id.ends_group));
//加载图标到到父布局
inflateButtons(end, mHorizontal.findViewById(R.id.ends_group),
false /* landscape */, false /* start */);
//加载图标到到父布局
inflateButtons(end, mVertical.findViewById(R.id.ends_group),
true /* landscape */, false /* start */);
updateButtonDispatchersCurrentView();
}
inflateButtons遍历添加Butoon
private void inflateButtons(String[] buttons, ViewGroup parent, boolean landscape,
boolean start) {
//遍历加载 inflateButton
for (int i = 0; i < buttons.length; i++) {
inflateButton(buttons[i], parent, landscape, start);
}
}
inflateButton根据不同的buttonSpec 加载不同的布局文件,确定buttonSpec的布局大小,以及控件大小真正的添加到父布局中进行显示。 判断横竖屏显示导航栏。
protected View inflateButton(String buttonSpec, ViewGroup parent, boolean landscape,
boolean start) {
LayoutInflater inflater = landscape ? mLandscapeInflater : mLayoutInflater;
//根据 buttonSpec 加载不同的布局文件
//createView 方法 加载了桌面 返回键 任务栏按键 通过自定义 KeyButtonView 类
View v = createView(buttonSpec, parent, inflater);
if (v == null) return null;
//确定 buttonSpec 布局的大小
v = applySize(v, buttonSpec, landscape, start);
//添加到父布局
parent.addView(v);
addToDispatchers(v);
//横屏 & 竖屏显示
View lastView = landscape ? mLastLandscape : mLastPortrait;
View accessibilityView = v;
if (v instanceof ReverseRelativeLayout) {
accessibilityView = ((ReverseRelativeLayout) v).getChildAt(0);
}
if (lastView != null) {
accessibilityView.setAccessibilityTraversalAfter(lastView.getId());
}
if (landscape) {
mLastLandscape = accessibilityView;
} else {
mLastPortrait = accessibilityView;
}
return v;
}
查看NavigationBarInflaterView.java中的createView方法可以看到,加载的都是 inflate("R.layout.各种布局")查看“R.layout.各种布局” 发现各种布局文件都是KeyButtonView自定义控件。
private View createView(String buttonSpec, ViewGroup parent, LayoutInflater inflater) {
View v = null;
String button = extractButton(buttonSpec);
if (LEFT.equals(button)) {
button = extractButton(NAVSPACE);
} else if (RIGHT.equals(button)) {
button = extractButton(MENU_IME_ROTATE);
}
if (HOME.equals(button)) {
//R.layout.home自定义控件
v = inflater.inflate(R.layout.home, parent, false);
} else if (BACK.equals(button)) {
//省略代码
}
return v;
}
自定与控件对应的KeyButtonView文件为KeyButtonView.javaKeyButtonView.java类中有个方法sendEvent 是处理按键事件并且是按键生效的地方。
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
private void sendEvent(int action, int flags, long when) {
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
.setType(MetricsEvent.TYPE_ACTION)
.setSubtype(mCode)
.addTaggedData(MetricsEvent.FIELD_NAV_ACTION, action)
.addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
logSomePresses(action, flags);
//处理back按键的地方
if (mCode == KeyEvent.KEYCODE_BACK && flags != KeyEvent.FLAG_LONG_PRESS) {
Log.i(TAG, "Back button event: " + KeyEvent.actionToString(action));
if (action == MotionEvent.ACTION_UP) {
mOverviewProxyService.notifyBackAction((flags & KeyEvent.FLAG_CANCELED) == 0,
-1, -1, true /* isButton */, false /* gestureSwipeLeft */);
}
}
//创建 KeyEvent 对象 KeyEvent
final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
int displayId = INVALID_DISPLAY;
if (getDisplay() != null) {
displayId = getDisplay().getDisplayId();
}
// Bubble controller will give us a valid display id if it should get the back event
BubbleController bubbleController = Dependency.get(BubbleController.class);
int bubbleDisplayId = bubbleController.getExpandedDisplayId(mContext);NavigationBarFragment.java
if (mCode == KeyEvent.KEYCODE_BACK && bubbleDisplayId != INVALID_DISPLAY) {
displayId = bubbleDisplayId;
}
if (displayId != INVALID_DISPLAY) {
ev.setDisplayId(displayId);
}
//使按键生效
mInputManager.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
查看NavigationBarInflaterView布局的时候发现NavigationBarInflaterView外面又包含了一层NavigationBarView ,NavigationBarView也是自定义控件对应的是NavigationBarView.java ,才是真正控制导航栏显示的地方。
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
NavigationBarView构造函数主要功能
1.上面滑后出现的底部界面
2.方向获取
3.pin页面的提示类
4.管理 桌面、任务栏,以及返回键图标,传递自己的child到 NavigationBarInflaterView
5.获取范围类的RegionSampling来变化显示是light/dark
public NavigationBarView(Context context, AttributeSet attrs) {
super(context, attrs);
mIsVertical = false;
mLongClickableAccessibilityButton = false;
mNavBarMode = Dependency.get(NavigationModeController.class).addListener(this);
boolean isGesturalMode = isGesturalMode(mNavBarMode);
mSysUiFlagContainer = Dependency.get(SysUiState.class);
mPluginManager = Dependency.get(PluginManager.class);
// Set up the context group of buttons
mContextualButtonGroup = new ContextualButtonGroup(R.id.menu_container);
final ContextualButton imeSwitcherButton = new ContextualButton(R.id.ime_switcher,
R.drawable.ic_ime_switcher_default);
final RotationContextButton rotateSuggestionButton = new RotationContextButton(
R.id.rotate_suggestion, R.drawable.ic_sysbar_rotate_button);
final ContextualButton accessibilityButton =
new ContextualButton(R.id.accessibility_button,
R.drawable.ic_sysbar_accessibility_button);
mContextualButtonGroup.addButton(imeSwitcherButton);
if (!isGesturalMode) {
mContextualButtonGroup.addButton(rotateSuggestionButton);
}
mContextualButtonGroup.addButton(accessibilityButton);
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
//此类主要功能是底部往上面滑后出现的底部界面
mRecentsOnboarding = new RecentsOnboarding(context, mOverviewProxyService);
mFloatingRotationButton = new FloatingRotationButton(context);
mRotationButtonController = new RotationButtonController(context,
R.style.RotateButtonCCWStart90,
isGesturalMode ? mFloatingRotationButton : rotateSuggestionButton);
//方向获取
mConfiguration = new Configuration();
mTmpLastConfiguration = new Configuration();
//更新方向获取
mConfiguration.updateFrom(context.getResources().getConfiguration());
//pin页面的提示类
mScreenPinningNotify = new ScreenPinningNotify(mContext);
//NavigationBar 的颜色改变控制类
mBarTransitions = new NavigationBarTransitions(this, Dependency.get(CommandQueue.class));
//管理 桌面、任务栏,以及返回键图标,传递自己的child到 NavigationBarInflaterView
mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
mButtonDispatchers.put(R.id.home_handle, new ButtonDispatcher(R.id.home_handle));
mButtonDispatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps));
mButtonDispatchers.put(R.id.ime_switcher, imeSwitcherButton);
mButtonDispatchers.put(R.id.accessibility_button, accessibilityButton);
mButtonDispatchers.put(R.id.rotate_suggestion, rotateSuggestionButton);
mButtonDispatchers.put(R.id.menu_container, mContextualButtonGroup);
mDeadZone = new DeadZone(this);
mNavColorSampleMargin = getResources()
.getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin);
mEdgeBackGestureHandler = new EdgeBackGestureHandler(context, mOverviewProxyService,
mSysUiFlagContainer, mPluginManager, this::updateStates);
//获取范围类的RegionSampling来变化显示是light/dark
mRegionSamplingHelper = new RegionSamplingHelper(this,
new RegionSamplingHelper.SamplingCallback() {
// 省略代码
});
}
View加载完成回调onAttachedToWindow 函数 调用reorient(); 方法控制和更新icon
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
//自定义View 创建完成回调 onAttachedToWindow 方法
requestApplyInsets();
//设置图标的入口方法 隐藏对应的图标,以及更新Button的图标
reorient();
//模式变化时 各类对应 onNavigationModeChanged的处理
onNavigationModeChanged(mNavBarMode);
setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
if (mRotationButtonController != null) {
mRotationButtonController.registerListeners();
}
mEdgeBackGestureHandler.onNavBarAttached();
getViewTreeObserver().addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
}
reorient 隐藏布局,更新ICON
public void reorient() {
//更新隐藏布局
updateCurrentView();
// 省略代码
//更新navButtonIcon图标
updateNavButtonIcons();
getHomeButton().setVertical(mIsVertical);
}
updateNavButtonIcons控制icon是否显示以及图标大小更新。
public void updateNavButtonIcons() {
// We have to replace or restore the back and home button icons when exiting or entering
// carmode, respectively. Recents are not available in CarMode in nav bar so change
// to recent icon is not required.
final boolean useAltBack =
(mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
KeyButtonDrawable backIcon = mBackIcon;
orientBackButton(backIcon);
KeyButtonDrawable homeIcon = mHomeDefaultIcon;
if (!mUseCarModeUi) {
orientHomeButton(homeIcon);
}
//设置 桌面、返回键的图标
getHomeButton().setImageDrawable(homeIcon);
getBackButton().setImageDrawable(backIcon);
//根据是否分屏状态来决定显示 Recents图标
updateRecentsIcon();
// Update IME button visibility, a11y and rotate button always overrides the appearance
mContextualButtonGroup.setButtonVisibility(R.id.ime_switcher,
(mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0);
mBarTransitions.reapplyDarkIntensity();
//是否隐藏桌面图标
boolean disableHome = isGesturalMode(mNavBarMode)
|| ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
//是否隐藏任务栏图标
boolean disableRecent = isRecentsButtonDisabled();
//是否隐藏桌面事件
boolean disableHomeHandle = disableRecent
&& ((mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
//是否隐藏任务栏返回键
boolean disableBack = !useAltBack && (mEdgeBackGestureHandler.isHandlingGestures()
|| ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0));
//判断当前状态是否是pinning状态
final boolean pinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive();
if (mOverviewProxyService.isEnabled()) {
// Force disable recents when not in legacy mode
disableRecent |= !QuickStepContract.isLegacyMode(mNavBarMode);
if (pinningActive && !QuickStepContract.isGesturalMode(mNavBarMode)) {
disableBack = disableHome = false;
}
} else if (pinningActive) {
//pinning状态禁用 返回键 和 桌面按键
disableBack = disableRecent = false;
}
ViewGroup navButtons = getCurrentView().findViewById(R.id.nav_buttons);
if (navButtons != null) {
LayoutTransition lt = navButtons.getLayoutTransition();
if (lt != null) {
if (!lt.getTransitionListeners().contains(mTransitionListener)) {
lt.addTransitionListener(mTransitionListener);
}
}
}
//根据是否禁用来显示对应的button
getBackButton().setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
getHomeButton().setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
getHomeHandle().setVisibility(disableHomeHandle ? View.INVISIBLE : View.VISIBLE);
}