Android R Navigationbar的创建,图标更新,加载流程

本文是基于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);
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值