前言

关于Android系统的导航栏,不同的客户有不同的需求: 有些客户需要永久隐藏导航栏,有些客户需要在设置显示中添加按钮可自行选择是否显示和隐藏,有些客户需要给出调用接口供APP去调用设置等;


一、创建全局变量

1、创建全局变量保存导航栏状态,是为了系统级应用和整个框架层都能获取到该变量值,该变量值在掉电或者重启都不会丢失(除了恢复出厂设置Q 或者重刷系统固件之外) ;

2、创建全局变量
配置路径: frameworks/base/core/java/android/provider/Settings.java
定义了一个SYSTEM_HIDE_NAVIGATION全局变量: SYSTEM_HIDE_NAVIGATION =“hide_navigation”
这个是需要放在 public static final class System extends NameValueTable {
里面的哦

/**
* add by LQX at 20230818
*/
public static final String SYSTEM_HIDE_NAVIGATION = "hide_navigation";

3、定义全局变量的默认值
配置路径: frameworks/base/packages/SettingsProvider/res/values/defaults.xml
设置引用的名称格式为: def_ + SYSTEM_HIDE_NAVIGATION的字符值 = def_hide_navigation,值为bool类型;
值为true: 隐藏导航栏;
值为false: 显示导航栏;

<!-- add by LQX -->
	<bool name="def_hide_navigation">true</bool>
<!-- end, add by LQX -->

二、设置应用添加隐藏导航栏按钮

1、在 设置->显示 里添加导航栏按钮;
2、按钮标题为“隐藏导航栏”
这里以英文和中文字体为例,其他字体需要的话也同理添加;
英文字体(系统为英文语言时显示) : packages/apps/Settings/res/values/strings.xml

<!-- add by LQX-->
<string name="hide_navigation">Hide Navigation</string>
<!-- end, add by LQX-->

中文字体: packages/apps/Settings/res/values-zh-rCN/strings.xml

<!-- add by LQX-->
<string name="hide_navigation">隐藏导航栏</string>
<!-- end, add by LQX-->

3、添加按钮布局
(1) 选择在 设置->显示 里面添加
对应的布局文件: packages/apps/Settings/res/xml/display_settings.xml
对应的按钮类型,这里选择为: SwitchPreference

(2)在对应的位置添加按钮控件
这里选择是在“屏幕超时”后面添加:
android:key=“hide navigation” ===>按钮控制健值
android:title=“@string/hide navigation”= = >标题,使用上面2中配置好的

<!-- add by LQX-->
<SwitchPreference
	android:key="hide_navigation"
	android:title="@string/hide_navigation" />
	
<!-- end,add by LQX-->

4、这样按钮就能在 设置->显示 中,显示出来了
但此时点击按钮是没有作用的,对应的按钮功能还没有添加进去:

三、添加按钮功能

1、添加功能代码
创建一个java文件:
目录路径: packages/apps/Settings/src/com/android/settings/display/
创建一个java文件: HideNavigationPreferenceController.java
功能代码如下:

package com.android.settings.display;
import android.content.Context;
import android.provider.Settings;
import androidx.preference.SwitchPreference;
import androidx.preference.Preference;
 
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import android.content.Intent;
import android.util.Log;
 
public class HideNavigationPreferenceController extends AbstractPreferenceController implements
        PreferenceControllerMixin, Preference.OnPreferenceChangeListener {    
    private static final String TAG = "HideNavigationPreferenceController";
    private static final boolean DEBUG = true;
    private static final String KEY_HIDE_NAVIGATION = "hide_navigation"; //按钮键值
	public static final String ACTION_HIDE_NAVIGATION = "action.ACTION_HIDE_NAVIGATION"; //广播,用于实现导航栏隐藏和显示功能;
    public HideNavigationPreferenceController(Context context) {
        super(context);
    }
    @Override
    public String getPreferenceKey() {
        return KEY_HIDE_NAVIGATION;
    }
    @Override
    public boolean isAvailable() {
        return true;
    }
    @Override
    public void updateState(Preference preference) {  //当进入设置->显示界面时,获取导航栏状态,然后更新按钮状态
        int value = Settings.System.getInt(
                mContext.getContentResolver(), Settings.System.SYSTEM_HIDE_NAVIGATION, 0);
        ((SwitchPreference) preference).setChecked(value != 0);
    }
    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) { //点击按钮时,响应函数
        boolean value = (Boolean) newValue;
		
		if(DEBUG) {
			Log.d(TAG, "key value " + value);
		}	
        Settings.System.putInt(
                mContext.getContentResolver(), Settings.System.SYSTEM_HIDE_NAVIGATION, value ? 1 : 0); //保存设置的导航栏状态;
		
        Intent intent = new Intent(ACTION_HIDE_NAVIGATION); //发送广播,实现导航栏隐藏和显示功能
        mContext.sendBroadcast(intent);
        return true;
    }
}

2、把该class类添加到Settings调用list中
文件路径: packages/apps/Settings/src/com/android/settings/DisplaySettings.java

import com.android.settings.display.HideNavigationPreferenceController; //add by LQX

@@ -93,6 +94,7 @0 public class DisplaySettings extends DashboardFragment {
controllers.add(new ThemePreferenceController(context));
controllers.add(new BrightnessLevelpreferenceController(context, lifecycle));
controllers.add(new HdmisettingsPreferenceController(context, KET_HDMI_SETTINGS));
controllers.add(new HideNavigationPreferenceController(context)); //add by LQX
return controllers;

四、动态隐藏还有显示功能

1、相关修改代码文件:

frameworks/base/packages/SystemUI\src\com/android/systemui/statusbar/phone/StatusBar.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java

2、主要修改代码
路径:frameworks/base/packages/SystemUl/src/com/android/systemui/lstatusbar/phone/StatusBar.java

--- a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -259,6 +259,8 @@ public class StatusBar extends SystemUI implements DemoMode,
     public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
     static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot";
 
+	public static final String ACTION_HIDE_NAVIGATION = "action.ACTION_HIDE_NAVIGATION"; //add by LQX广播
+	
     private static final String BANNER_ACTION_CANCEL =
             "com.android.systemui.statusbar.banner_action_cancel";
     private static final String BANNER_ACTION_SETUP =
@@ -1099,7 +1101,20 @@ public class StatusBar extends SystemUI implements DemoMode,
         mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
         mNotificationLogger.setHeadsUpManager(mHeadsUpManager);
 
-        createNavigationBar(result);
+        //createNavigationBar(result);
+
+		try {
+            boolean hideNavStatus = Settings.System.getInt(mContext.getContentResolver(),Settings.System.SYSTEM_HIDE_NAVIGATION,0) != 0;
+
+            //Log.d(TAG, "====== Navigation ====== " + hideNavStatus);
+            if (!hideNavStatus) {
+                 createNavigationBar(result);
+            }
+        } catch (Exception e) {
+            Log.d(TAG, "====== Navigation ====== " + e);
+        }
+
+		setNavigationStatus(); //add by LQX开机设置导航栏状态
 
         if (ENABLE_LOCKSCREEN_WALLPAPER && mWallpaperSupported) {
             mLockscreenWallpaper = mLockscreenWallpaperLazy.get();
@@ -1288,6 +1303,7 @@ public class StatusBar extends SystemUI implements DemoMode,
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
+		 filter.addAction(ACTION_HIDE_NAVIGATION); //add by LQX接收设置应用发送出来的广播
         mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, null, UserHandle.ALL);
     }
 
@@ -1362,6 +1378,45 @@ public class StatusBar extends SystemUI implements DemoMode,
         }
     }
+//add by LQX
+	private boolean mHideNavStatus = true;
+	private static final int MSG_HIDE_NAVIGATION_STATUS = 1060;
+	
+    private void setNavigationStatus() {
+        boolean hideNavStatus = Settings.System.getInt(mContext.getContentResolver(),Settings.System.SYSTEM_HIDE_NAVIGATION,0) != 0;
+        if(hideNavStatus)
+            hideNavigation();
+        else{
+            showNavigation();
+        }
+    }
+
+    private void showNavigation() {
+        boolean hideNavStatus = Settings.System.getInt(mContext.getContentResolver(),Settings.System.SYSTEM_HIDE_NAVIGATION,0) != 0;
+        if (!mHideNavStatus && !hideNavStatus){
+            Log.d(TAG,"====== show Navigation ======");
+            NavigationBarView mNavigationBarView = mNavigationBarController.getDefaultNavigationBarView();
+
+            if (mNavigationBarView == null)
+                mNavigationBarController.createNavigationBars(true,null);
+			
+            mHideNavStatus = true;
+        }
+    }
+
+    private void hideNavigation() {
+        if (mHideNavStatus){
+            Log.d(TAG,"====== hide Navigation ======");
+            NavigationBarView mNavigationBarView = mNavigationBarController.getDefaultNavigationBarView();
+
+            if (mNavigationBarView != null)
+                mNavigationBarController.hideNavigationBar();
+
+            mHideNavStatus = false;
+        }
+    }
+//end,add by LQX
+
     // TODO(b/117478341): This was left such that CarStatusBar can override this method.
     // Try to remove this.
     protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
@@ -1974,6 +2029,9 @@ public class StatusBar extends SystemUI implements DemoMode,
                 case MSG_LAUNCH_TRANSITION_TIMEOUT:
                     onLaunchTransitionTimeout();
                     break;
+				case MSG_HIDE_NAVIGATION_STATUS: //add by LQX接收到广播后,执行隐藏或者显示导航栏功能;
+					setNavigationStatus();
+					break;
             }
         }
     }
@@ -2804,6 +2862,10 @@ public class StatusBar extends SystemUI implements DemoMode,
             }
             else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
                 mQSPanel.showDeviceMonitoringDialog();
+            } 
+			else if(ACTION_HIDE_NAVIGATION.equals(action)) {    //接收广播
+                mHandler.removeMessages(MSG_HIDE_NAVIGATION_STATUS);
+                mHandler.sendEmptyMessageDelayed(MSG_HIDE_NAVIGATION_STATUS, 350); //使用Handler来延时执行隐藏和显示功能,防止反复快速点击导航栏按钮导致异常;
             }
         }
     };

3、修改NavigationBarControllerjava
文件: frameworks/base/packages/SystemU/src/com/android/systemui/statusbar/NavigationBarController.java

--- a/frameworks/base/packages/SystemuI/src/com/android/systemui/statusbar/NavigationBarController,java
+++ b/frameworks/base/packages/SystenuI/src/com/android/systemui/statusbar/NavigationBarController.java3
 @ -178,6 +178,13 @@ public class NavigationBarController implements Callbacks {
		}
	}
	public void hideNavigationBar()  {//add by LQX
		Display[] displays = mDisplayManager.getDisplays();
		for (Display display : displays) {
			removeNavigationBar(display.getDisplayId());
			}
		}
		/** @see NavigationBarFragment#checkNavBarModes() */

4、现在系统默认是隐藏导航栏,如需默认显示导航栏,请按下面的设置即可
文件:frameworks/base/packages/SettingsProvider/res/values/defaults.xm
值为true: 隐藏导航栏:
值为false: 显示导航栏

<bool name="def_hide_navigation">true</bool>

五、创建系统导航栏广播接口

1、定义导航栏显示与隐藏的广播

 public static final String ACTION_API_HIDE_NAVIGATION = "action.ACTION_API_HIDE_NAVIGATION"; //隐藏导航栏广播
 public static final String ACTION_API_SHOW_NAVIGATION ="action.ACTION_API_SHOW_NAVIGATION"; //显示导航栏广播

2、系统代码实现
文件路径:frameworks/base/packages/SystemUl/src/com/android/systemui/statusbar/phone/StatusBar.java
创建了两个接收广播,待应用发送这两个广播来实现导航栏隐藏和显示;

--- a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -259,6 +259,10 @@ public class StatusBar extends SystemUI implements DemoMode,
     public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
     static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot";
 
        public static final String ACTION_HIDE_NAVIGATION = "action.ACTION_HIDE_NAVIGATION"; //add by LQX
+       public static final String ACTION_API_HIDE_NAVIGATION = "action.ACTION_API_HIDE_NAVIGATION"; //add by LQX
+       public static final String ACTION_API_SHOW_NAVIGATION = "action.ACTION_API_SHOW_NAVIGATION"; //add by LQX
+       
     private static final String BANNER_ACTION_CANCEL =
             "com.android.systemui.statusbar.banner_action_cancel";
@@ -1288,6 +1305,9 @@ public class StatusBar extends SystemUI implements DemoMode,
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
         filter.addAction(ACTION_HIDE_NAVIGATION); //add by LQX
+        filter.addAction(ACTION_API_HIDE_NAVIGATION); //add by LQX添加到广播队列里
+        filter.addAction(ACTION_API_SHOW_NAVIGATION); //add by LQX添加到广播队列里
         mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, null, UserHandle.ALL);
     }
@@ -1362,6 +1382,57 @@ public class StatusBar extends SystemUI implements DemoMode,
         }
     }
    private void hideNavigation() {
        if (mHideNavStatus){
            Log.d(TAG,"====== hide Navigation ======");
            NavigationBarView mNavigationBarView = mNavigationBarController.getDefaultNavigationBarView();
            if (mNavigationBarView != null)
                mNavigationBarController.hideNavigationBar();
            mHideNavStatus = false;
        }
    }
+   private void apiShowNavigation() {
+        if (!mHideNavStatus){
+            Log.d(TAG,"====== api show Navigation ======");
+            NavigationBarView mNavigationBarView = mNavigationBarController.getDefaultNavigationBarView();
+
+            if (mNavigationBarView == null)
+                mNavigationBarController.createNavigationBars(true,null);
+                       
+            mHideNavStatus = true;
+        }
+    }
//end,add by LQX
     // TODO(b/117478341): This was left such that CarStatusBar can override this method.
     // Try to remove this.
     protected void createNavigationBar(@Nullable RegisterStatusBarResult result) {
@@ -2804,7 +2878,19 @@ public class StatusBar extends SystemUI implements DemoMode,
             }
             else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
                 mQSPanel.showDeviceMonitoringDialog();
            }  
      //add by LQX
            else if(ACTION_HIDE_NAVIGATION.equals(action)) {
                mHandler.removeMessages(MSG_HIDE_NAVIGATION_STATUS);
                mHandler.sendEmptyMessageDelayed(MSG_HIDE_NAVIGATION_STATUS, 350);
+           }
+           else if(ACTION_API_HIDE_NAVIGATION.equals(action)) { 
+               hideNavigation(); //隐藏导航栏
+           }
+           else if(ACTION_API_SHOW_NAVIGATION.equals(action)) { 
+               apiShowNavigation(); //显示导航栏
            }
     //end,add by LQX

总结

教程结束!编译成功后可以先用adb测试:
PS:对了!踩到的坑,改了系统api需要更新

make update-api

adb shell

am broadcast -a "action.ACTION_API_SHOW_NAVIGATION"
am broadcast -a "action.ACTION_API_HIDE_NAVIGATION"
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐