Android TV 通常是用遥控器操作的,系统导航栏都是关闭的,但带触摸的TV就很有必要加上导航栏了。

1. 修改base/core/res/res/values/config.xml 

base/core/res/res/values/config.xml

-    <bool name="config_showNavigationBar">false</bool>
+    <bool name="config_showNavigationBar">true</bool>

但是在TV 上屏通常是横屏的,手机上是竖屏的,仅仅打开上面这个设置,在TV 右边屏幕就会有一个黑条的导航栏,但没有图标,这时候就要把导航栏想办法改到屏幕下面,

2. base/services/core/java/com/android/server/policy/PhoneWindowManager.java

mNavigationBarOnBottom这个值决定导航条的位置,从名字就看的出来,true 的时候是底部,false在垂直右边,在TV 屏的1920x1080分辨率上这个值 为false,所以直接改为true

主要代码在setInitialDisplaySize, 和beginLayoutLw 这两个函数里,包括导航栏的位置,其实X,Y 坐标,长宽等到

   

public void setInitialDisplaySize(Display display, int width, int height, int density) {
         ......................................
         mNavigationBarCanMove = width != height && shortSizeDp < 600; 这个值在setInitialDisplaySize函数里                  ........................................
            public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
                               int displayRotation) {...................................................
         mNavigationBarOnBottom = true;//(!mNavigationBarCanMove || displayWidth < displayHeight);
                 if (mNavigationBarOnBottom) {
                     // It's a system nav bar or a portrait screen; nav bar goes on bottom.
                     int top = displayHeight - overscanBottom //计算底部显示的 Y 坐标
                             - 100; //mNavigationBarHeightForRotation[displayRotation]; 这个值是导航栏的宽度,在setInitialDisplaySize计算出来是0,实际Y 坐标top就是1080了,这样看不到了导航栏了,这里直接改成100
                     mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom); //设置导航栏位置大小
                  ................................
                 } else { 
                     // Landscape screen; nav bar goes to the right.
                     int left = displayWidth - overscanRight //计算在右边显示 X 坐标
                             - mNavigationBarWidthForRotation[displayRotation];
                     mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);
                    ................................

这样导航栏的三个图标就出来了

3. 修改base/packages/SystemUI/res/layout/navigation_bar.xml 实现自定义布局


<FrameLayout android:id="@+id/rot0" 和 <FrameLayout android:id="@+id/rot90" 代表导航栏在底部和右边垂直的布局,TV 不肯能像手机那样只有三个小图标,并且不会像手机那样翻转的,所以只在其中一个修改即可


在base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java 文件的函数

public void onFinishInflate() {
         mRotatedViews[Surface.ROTATION_0] = 
         mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);        mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
        mRotatedViews[Surface.ROTATION_270] = mRotatedViews[Surface.ROTATION_90];

mCurrentView = mRotatedViews[Surface.ROTATION_0]; TV 实际用的这个,所以布局里就只修改<FrameLayout android:id="@+id/rot0 即可,如果要在图标下添加文字,例子如下,把上图改为下图

<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
                android:layout_width="@dimen/navigation_key_width"
                android:layout_height="match_parent"
                android:src="@drawable/ic_sysbar_back"
                android:scaleType="center"
                systemui:keyCode="3"
                systemui:keyRepeat="false"
                android:layout_weight="0"
                android:contentDescription="@string/accessibility_back"
                />
<LinearLayout
                android:layout_width="@dimen/navigation_key_width"
                android:layout_height="match_parent"
                android:orientation="vertical">
                <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:src="@drawable/ic_sysbar_back"
                    systemui:keyCode="4"
                    android:layout_weight="2"
                    android:scaleType="fitCenter"
                    android:contentDescription="@string/accessibility_back"
                    />
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="@string/accessibility_back"
                    android:textColor="@color/navigation_bar_icon_color"
                    android:layout_weight="1"
                    android:textSize="10dp"
                    android:gravity="center"/>
            </LinearLayout>

注意:原来的返回,主页,任务的三个图标,代码里面还会引用图片的名字。如果要替换,最好把要换的图片名字改成原来的一样,直接覆盖替换,否则代码里还要同步修改。

4. 修改按钮事件

layout 文件里每个KeyButtonView 下有一个systemui:keyCode="4",对应按键映射码,最终会在KeyButtonView 里取出来赋值给mCode = a.getInteger(R.styleable.KeyButtonView_keyCode, 0); 在sendEvent 里虚拟一个按键事件把这个按键发送出去。对于其他新增加的按钮事件,可以找一个没用到的按键当作该按钮的按键,比如定义为KEYCODE_F1, 在navigation_bar.xml  里修改systemui:keyCode="131",再在PhoneWindow.java 的onKeyDown里添加下面代码,就可以在任何界面都能打开该activity了

case KeyEvent.KEYCODE_F1: {
                Intent itent = new Intent();
                itent.setClassName("com.supera.board", "com.supera.board.MainActivity");
                mContext.startActivity(itent);
                return true;
            }

最终的自定义导航栏就如下面的效果

android tv 不显示不出来 android tv guide_xml

5. 修改导航栏的背景色

在navigation_bar.xml  里有 android:background="@drawable/system_bar_background" 这一行,实际光修改这里是不起作用的,参考 这篇文章,屏蔽掉一行

android tv 不显示不出来 android tv guide_android_02

再修改 android:background="@drawable/system_bar_background" 就可以自定义背景颜色了

6. 修改导航栏的动态隐藏显示

参考 修改后,隐藏没有问题,但手势滑不出来导航栏,经过查找发现SystemGesturesPointerEventListener.java 文件里的screenWidth ,screenHeight ,mSwipeStartThreshold 这是三个值都是0,导致在下面函数返回SWIPE_NONE

android tv 不显示不出来 android tv guide_android_03

添加如下一段代码功能就正常手势滑开了

public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
       ..................
		WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); 
		screenWidth = wm.getDefaultDisplay().getWidth(); 
		screenHeight = wm.getDefaultDisplay().getHeight(); 

        mSwipeStartThreshold = 20;//checkNull("context", context).getResources()
................

这样改完后,还有个问题:导航栏滑出来的时候,上面的部分是缩上去的,而不是导航栏重叠在原画面上面。如果哪位高人有解决办法,分享一下,万分感谢