zoukankan      html  css  js  c++  java
  • 如何控制android系统中NavigationBar 的显示与隐藏

     

    我们使用的大多数android手机上的Home键,返回键以及menu键都是实体触摸感应按键。如果你用Google的Nexus4或Nexus5话,你会发现它们并没有实体按键或触摸感应按键,取而代之的是在屏幕的下方加了一个小黑条,在这个黑条上有3个按钮控件,这种设置无疑使得手机的外观的设计更加简约。但我遇到身边用Nexus 4手机的人都吐槽这种设计,原因很简单:好端端的屏幕,被划出一块区域用来显示3个按钮(如下图所示):Back, Home, Recent。并且它一直用在那里占用着。

    在android源码中,那一块区域被叫做NavigationBar。同时,google在代码中也预留了标志,用来控制它的显示与隐藏。NavigationBar的显示与隐藏的控制是放在SystemU中的,具体的路径是:frameworksasepackagesSystemUI。对android4.0以上的手机而言,SystemUi包含两部分:StatusBar和NavigationBar。在SystemUI的工程下有一个类PhoneStatusBar.java,在该类中可以发现关于控制NavigationBar的相关代码:

    在start()方法里可以看到NavigationBar是在那时候被添加进来,但只是添加,决定它显示还是隐藏是在后面控制的。

    1.  
      <span style="font-size:18px;">@Override
    2.  
      public void start() {
    3.  
      mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
    4.  
      .getDefaultDisplay();
    5.  
      updateDisplaySize();
    6.  
       
    7.  
      /// M: Support Smartbook Feature.
    8.  
      if (SIMHelper.isMediatekSmartBookSupport()) {
    9.  
      /// M: [ALPS01097705] Query the plug-in state as soon as possible.
    10.  
      mIsDisplayDevice = SIMHelper.isSmartBookPluggedIn(mContext);
    11.  
      Log.v(TAG, "start, mIsDisplayDevice=" + mIsDisplayDevice);
    12.  
      }
    13.  
       
    14.  
      super.start(); // calls createAndAddWindows()
    15.  
       
    16.  
      addNavigationBar();
    17.  
       
    18.  
      // Lastly, call to the icon policy to install/update all the icons.
    19.  
      mIconPolicy = new PhoneStatusBarPolicy(mContext);
    20.  
       
    21.  
      mHeadsUpObserver.onChange(true); // set up
    22.  
      if (ENABLE_HEADS_UP) {
    23.  
      mContext.getContentResolver().registerContentObserver(
    24.  
      Settings.Global.getUriFor(SETTING_HEADS_UP), true,
    25.  
      mHeadsUpObserver);
    26.  
      }
    27.  
      }</span>

    其中的addNavigationBar()具体的实现方法如下:

    1.  
      <span style="font-size:18px;"> // For small-screen devices (read: phones) that lack hardware navigation buttons
    2.  
      private void addNavigationBar() {
    3.  
      if (DEBUG) Slog.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
    4.  
      if (mNavigationBarView == null) return;
    5.  
       
    6.  
      prepareNavigationBarView();
    7.  
       
    8.  
      mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
    9.  
      }</span>
    可以看到Navigationbar实际上windowmanager向window窗口里添加一个view。在调用addNavigationBar()方法之前会回调start()的父方法super.start()来判断是否要添加NavigationBar。在super.start()的调用父类方法里会调用createAndAddWindows(),该方法内会判断是否需要添加显示NavigationBar,然后决定是否要实例化NavigationBarView.
    1.  
      <span style="font-size:18px;">try {
    2.  
      boolean showNav = mWindowManagerService.hasNavigationBar();
    3.  
      if (DEBUG) Slog.v(TAG, "hasNavigationBar=" + showNav);
    4.  
      if (showNav) {
    5.  
      mNavigationBarView =
    6.  
      (NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
    7.  
       
    8.  
      mNavigationBarView.setDisabledFlags(mDisabled);
    9.  
      mNavigationBarView.setBar(this);
    10.  
      }
    11.  
      } catch (RemoteException ex) {
    12.  
      // no window manager? good luck with that
    13.  
      }</span>

    WindowManagerService类实现了WindowManagerPolicy的接口,所以WindowManagerService会回调WindowManagerPolicy 的hasNavigationBar()接口,

    1.  
      <span style="font-size:18px;"> @Override
    2.  
      public boolean hasNavigationBar() {
    3.  
      return mPolicy.hasNavigationBar();
    4.  
      }</span>

    Policy向下调用实际上调用的是PhoneWindowManager实现的hasNavigationBar方法,下面代码是PhoneWindowManager中的hasNavigationBar()方法。
    1.  
      <span style="font-size:18px;">// Use this instead of checking config_showNavigationBar so that it can be consistently
    2.  
      // overridden by qemu.hw.mainkeys in the emulator.
    3.  
      public boolean hasNavigationBar() {
    4.  
      return mHasNavigationBar;
    5.  
      }</span>

    而mHasNavigationBar的赋值可以在PhoneWindowManager中的setInitialDisplaySize(Display display, int width, int height, int density)方法中找到,

    1.  
      <span style="font-size:18px;"> if (!mHasSystemNavBar) {
    2.  
      mHasNavigationBar = mContext.getResources().getBoolean(
    3.  
      com.android.internal.R.bool.config_showNavigationBar);
    4.  
      // Allow a system property to override this. Used by the emulator.
    5.  
      // See also hasNavigationBar().
    6.  
      String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
    7.  
      if (! "".equals(navBarOverride)) {
    8.  
      if (navBarOverride.equals("1")) mHasNavigationBar = false;
    9.  
      else if (navBarOverride.equals("0")) mHasNavigationBar = true;
    10.  
      }
    11.  
      } else {
    12.  
      mHasNavigationBar = false;
    13.  
      }</span>
    从上面代码可以看到mHasNavigationBar的值的设定是由两处决定的:
    1.首先从系统的资源文件中取设定值config_showNavigationBar, 这个值的设定的文件路径是frameworks/base/core/res/res/values/config.xml
    1.  
      <!-- Whether a software navigation bar should be shown. NOTE: in the future this may be
    2.  
      autodetected from the Configuration. -->
    3.  
      <bool name="config_showNavigationBar">false</bool>
    2.然后系统要获取“qemu.hw.mainkeys”的值,这个值可能会覆盖上面获取到的mHasNavigationBar的值。如果“qemu.hw.mainkeys”获取的值不为空的话,不管值是true还是false,都要依据后面的情况来设定。

    所以上面的两处设定共同决定了NavigationBar的显示与隐藏。

  • 相关阅读:
    《Orange'S:一个操作系统的实现》与上一版之比较
    IPC
    末日帝国——Agile公司的困境 (2)
    取经学道真经验——你听过这么享受的培训吗
    数据库设计指南(五)数据库小技巧
    软件项目开发典型风险一览
    数据库设计指南(四)保证数据的完整性
    官网的Ext direct包中.NET版的问题
    软件项目开发应写的13类文档
    面试EJB常考题
  • 原文地址:https://www.cnblogs.com/xgjblog/p/9579500.html
Copyright © 2011-2022 走看看