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

在android源码中,那一块区域被叫做NavigationBar。同时,google在代码中也预留了标志,用来控制它的显示与隐藏。NavigationBar的显示与隐藏的控制是放在SystemU中的,具体的路径是:\frameworks\base\packages\SystemUI。对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的显示与隐藏。

如何控制android系统中NavigationBar 的显示与隐藏的更多相关文章

  1. 控制input输入框中提示信息的显示和隐藏的方法

    在运用html+css+javascrpt进行页面制作时,我们往往会遇到一些影响用户体验,而又容易被我们忽视的小细节.比如,input输入框中的提示信息,怎样才能根据对象获得和失去焦点而实现其显示和隐 ...

  2. Android系统中设置TextView的行间距(非行高)

    Android系统中TextView默认显示中文时会比较紧凑,不是很美观.为了让每行保持一定的行间距,可以设置属性android:lineSpacingExtra或android:lineSpacin ...

  3. Android系统中的广播(Broadcast)机制简要介绍和学习计划

    在Android系统中,广播(Broadcast)是在组件之间传播数据(Intent)的一种机制:这些组件甚至是可以位于不同的进程中,这样它就像Binder机制一样,起到进程间通信的作用:本文通过一个 ...

  4. Android系统中 setprop,getprop,watchprops命令的使用

    如:在frameworks/opt/net/ims/src/java/com/android/ims/ImsManager.java if (SystemProperties.get("pe ...

  5. 用adb pull命令从android系统中读取文件失败的原因及解决办法

    问题:使用adb pull命令从android系统中读取文件失败.显示:Permission denied   原因:是由于文件权限原因引起.       使用ls -l命令查看android系统中的 ...

  6. Android系统中setprop,getprop,watchprops命令的使用(转载)

    转自:http://blog.csdn.net/yao_guet/article/details/6531241 在android系统中,有一些初始化的配置文件,例如: /init.rc /defau ...

  7. 在Android系统中修改Android.mk使其同时编译rgb2565和rgb2888(向out/host/linux-x86/bin/下新增加一个工具命令)【转】

    本文转载自:http://blog.csdn.net/mu0206mu/article/details/7514559 在Android系统中修改android.mk使其同时编译rgb2565和rgb ...

  8. AIDL在android系统中的作用

    AIDL,Android Interface definition language的缩写,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口.最近看了下AIDL在A ...

  9. Android系统中的6种模式

    Android系统中的6种模式 1:一般启动模式(normal mode):    功能是正常启动手机,方法为关机状态下按电源键启动. 2:安全模式(safe mode):    此模式和正常启动一样 ...

随机推荐

  1. 【转】Java抽象类与接口的区别

    很多常见的面试题都会出诸如抽象类和接口有什么区别,什么情况下会使用抽象类和什么情况你会使用接口这样的问题.本文我们将仔细讨论这些话题. 在讨论它们之间的不同点之前,我们先看看抽象类.接口各自的特性. ...

  2. javascript数组操作大全,数组方法总汇

    1. shift:删除原数组第一项,并返回删除元素的值:如果数组为空则返回undefined var a = [1,2,3,4,5]; var b = a.shift(); //a:[2,3,4,5] ...

  3. WinForm 之 程序启动不显示主窗体

    在 WinForm 程序启动时,不显示主窗体的实现方法主要有以下5种,第五种最简单,而且效果也不错,第四种方法也值得推荐. 实例代码如下: //隐藏窗体的方法1/5:不指定任何窗体为主窗体 //注意: ...

  4. Go语言中使用MySql数据库

    Go语言中使用MySql数据库 1.MySQL驱动 Go中支持MySQL的驱动目前比较多,有如下几种,有些是支持database/sql标准,而有些是采用了自己的实现接口,常用的有如下几种: http ...

  5. SHELL字符串使用总结

    1.获取字符串的长度,${#str} #设置字符串 $ str="liqiu" #打印字符串 $ echo $str liqiu #继续打印字符串 $ echo ${str} li ...

  6. NGINX源代码自我总结(一)

    查看源代码入门 这是一篇关于NGINX的MAIN()函数入门说明文章,相比其他这篇十分枯燥,其实写的时候更是无聊,不过学了这么长时间的WEB开发,连NGINX源代码都没有读下来,总是觉得有些缺憾,希望 ...

  7. Android Webservices 返回多行多列数据(Dataset)

    对于之前从事.net或者java开发人员,习惯了从后台获取网格数据(多行多列DataTable),但转行从事android开发,难免会不习惯 Android调用Webservice时,如果返回值是一个 ...

  8. mysql主从备份功能配置与測试

    在高訪问量服务环境下,单机配置mysql服务将无法满足频繁快速的数据读写操作. 一旦mysql出现故障造成数据丢失.无法恢复. 因此.在mysql服务上启用主从备份功能,支持读写分离技术.最靠可的是搭 ...

  9. selenium 定制启动 chrome 的选项

    序 使用 selenium 时,我们可能需要对 chrome 做一些特殊的设置,以完成我们期望的浏览器行为,比如阻止图片加载,阻止JavaScript执行 等动作.这些需要 selenium的 Chr ...

  10. 【转】UIAutomator源码分析之启动和运行

    我们可以看到UiAutomator其实就是使用了UiAutomation这个新框架,通过调用AccessibilitService APIs来获取窗口界面控件信息已经注入用户行为事件,那么今天开始我们 ...