在Android系统中,状态栏(StatusBar)、导航栏(NavigationBar)和下拉菜单(ExPlan)是三个常见的用户界面元素,它们分别提供了一些基本的信息显示和交互功能。例如,状态栏可以显示时间、电量、信号等信息,导航栏可以提供返回、主页、多任务等按钮,下拉菜单可以提供快速设置、通知等选项。并不是所有客户的Android设备都需要或支持这些,有时候客户可能想要自由地控制它们的显示和隐藏。
本文将介绍如何在Android系统中定制添加状态栏、导航栏和下拉菜单的控制功能,以便客户可以根据需求使用。
实现步骤
要实现状态栏、导航栏和下拉菜单的控制功能,需要修改以下几个部分:
- SystemUI模块:这是一个系统应用程序,负责显示和管理状态栏、导航栏和下拉菜单等界面元素。
- Settings模块:这是一个系统应用程序,负责提供各种系统设置选项,包括显示设置。
- 系统属性:这是一种用于存储和传递系统配置信息的机制,可以通过命令行或代码来读写。
- 广播:这是一种用于在不同组件之间传递消息的机制,可以通过命令行或代码来发送和接收。
需要完成以下几个步骤:
- 在SystemUI模块中添加广播接收器,用于接收控制状态栏、导航栏和下拉菜单显示和隐藏的广播,并执行相应的操作。
- 在SystemUI模块中添加系统属性读取,用于获取状态栏、导航栏和下拉菜单的初始状态,并创建或移除相应的界面元素。
- 在Settings模块中添加开关偏好项,用于控制状态栏、导航栏和下拉菜单的开启和关闭,并发送相应的广播,并写入相应的系统属性。
- 编译并运行修改后的系统,并在设置中测试控制功能。
修改示例
SystemUI模块
frameworks/base/packages/SystemUI/AndroidManifest.xml
在SystemUI模块的AndroidManifest.xml文件中 需要添加以下几行代码,用于声明要接收的广播:
<protected-broadcast android:name="sys.explan.show" /> <protected-broadcast android:name="sys.explan.hide" /> <protected-broadcast android:name="sys.statusbar.show" /> <protected-broadcast android:name="sys.statusbar.hide" /> <protected-broadcast android:name="sys.navigationbar.show" /> <protected-broadcast android:name="sys.navigationbar.hide" />
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java
在SystemUI模块的NavigationBarController.java文件中需要添加一个函数,用于移除所有的导航栏:
public void removeNavigationBars() { Display[] displays = mDisplayManager.getDisplays(); for (Display display : displays) { removeNavigationBar(display.getDisplayId()); } }
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
在SystemUI模块的PhoneStatusBarView.java文件中需要修改,用于根据系统属性来决定是否响应下拉菜单的触摸事件:
(这个文件如果用于动态控制 有bug,除了这个文件其他都正常修改 )
- return barConsumedEvent || super.onTouchEvent(event); + /* String value = SystemProperties.get("persist.sys.explan.enable", "false"); + if(value.equals("true")){ + return barConsumedEvent || super.onTouchEvent(event); + }else{ + return true; + }*/ + // + return barConsumedEvent || super.onTouchEvent(event);
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
在SystemUI模块的StatusBar.java文件中,我们需要添加以下几行代码,用于声明和初始化一些变量和方法:
+ private static final String ACTION_HIDE_EXPLAN = "sys.explan.hide"; + private static final String ACTION_SHOW_EXPLAN = "sys.explan.show"; + private static final String ACTION_HIDE_STATUS_BAR = "sys.statusbar.hide"; + private static final String ACTION_SHOW_STATUS_BAR = "sys.statusbar.show"; + private static final String ACTION_HIDE_NAVIGATION_BAR = "sys.navigationbar.hide"; + private static final String ACTION_SHOW_NAVIGATION_BAR = "sys.navigationbar.show"; + private static final String SYS_PROPERTY_STATUS_BAR = "persist.sys.statusbar.enable"; + private static final String SYS_PROPERTY_NAVIGATION_BAR = "persist.sys.navigationbar.enable"; + private static final String SYS_PROPERTY_EXPLAN = "persist.sys.explan.enable"; + protected StatusBarManager mStatusBarManager; + public StatusBar(Context context) { super(context); ... + mStatusBarManager = (StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE); ... } + + public void explan_show() { + mStatusBarManager.disable(StatusBarManager.DISABLE_NONE); + } + public void explan_hide() { + mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND); + }
在SystemUI模块的StatusBar.java文件中,还需要修改以下几行代码,用于根据系统属性来决定初始化是否创建或隐藏状态栏、导航栏和下拉菜单:
- createAndAddWindows(result); - + //ln28_add_start + if (!SystemProperties.getBoolean(SYS_PROPERTY_STATUS_BAR, false)) { + mStatusBarWindowController.setBarVisibility(View.GONE); + } + //ln28_add_end if (mWallpaperSupported) { ... } - - createNavigationBar(result); - + //ln28_add_start + if (SystemProperties.getBoolean(SYS_PROPERTY_NAVIGATION_BAR, false)) { + createNavigationBar(result); + } + if (SystemProperties.getBoolean(SYS_PROPERTY_EXPLAN, false)) { + explan_show(); + } + //ln28_add_end if (ENABLE_LOCKSCREEN_WALLPAPER && mWallpaperSupported) { ... }
在SystemUI模块的StatusBar.java文件中,还还需要添加以下几行代码,用于注册和处理我们要接收的广播 实现逻辑动态控制:
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_BAR); + filter.addAction(ACTION_SHOW_NAVIGATION_BAR); + filter.addAction(ACTION_HIDE_STATUS_BAR); + filter.addAction(ACTION_SHOW_STATUS_BAR); + filter.addAction(ACTION_HIDE_EXPLAN); + filter.addAction(ACTION_SHOW_EXPLAN); mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, null, UserHandle.ALL); } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { ... } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { ... } else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) { mQSPanel.showDeviceMonitoringDialog(); + } else if (ACTION_HIDE_NAVIGATION_BAR.equals(action)) { + mNavigationBarController.removeNavigationBars(); + SystemProperties.set(SYS_PROPERTY_NAVIGATION_BAR, "false"); + } else if (ACTION_SHOW_NAVIGATION_BAR.equals(action)) { + createNavigationBar(null); + SystemProperties.set(SYS_PROPERTY_NAVIGATION_BAR, "true"); + } else if (ACTION_HIDE_STATUS_BAR.equals(action)) { + mStatusBarWindowController.setBarVisibility(View.GONE); + SystemProperties.set(SYS_PROPERTY_STATUS_BAR, "false"); + } else if (ACTION_SHOW_STATUS_BAR.equals(action)) { + mStatusBarWindowController.setBarVisibility(View.VISIBLE); + SystemProperties.set(SYS_PROPERTY_STATUS_BAR, "true"); + } else if (ACTION_HIDE_EXPLAN.equals(action)) { + explan_hide(); + SystemProperties.set(SYS_PROPERTY_EXPLAN, "false"); + } else if (ACTION_SHOW_EXPLAN.equals(action)) { + explan_show(); + SystemProperties.set(SYS_PROPERTY_EXPLAN, "true"); } } };
OK 到这我们就完成了SystemUI模块的修改,是不是很简单? 接下来我们需要修改Settings模块。
Settings模块
packages/apps/Settings/res/values/strings.xml
在Settings模块的strings.xml文件中,需要添加以下几行代码,用于定义我们要显示的开关偏好项的标题:
<string name="ctrl_statusbar">状态栏</string> <string name="ctrl_explan">下拉菜单</string> <string name="ctrl_navigationbar">导航栏</string>
packages/apps/Settings/res/xml/display_settings.xml
在Settings模块的display_settings.xml文件中,需要添加以下几行代码,用于创建我们要显示的开关偏好项,并指定它们的键值和标题:
<SwitchPreference android:key="ctrl_statusbar" android:title="@string/ctrl_statusbar"/> <SwitchPreference android:key="ctrl_navigationbar" android:title="@string/ctrl_navigationbar"/> <SwitchPreference android:key="ctrl_explan" android:title="@string/ctrl_explan"/>
packages/apps/Settings/src/com/android/settings/DisplaySettings.java
在Settings模块的DisplaySettings.java文件中,需要添加以下几行代码,用于注册我们要控制的开关偏好项的控制器:
controllers.add(new ThemePreferenceController(context)); controllers.add(new BrightnessLevelPreferenceController(context, lifecycle)); controllers.add(new HdmiSettingsPreferenceController(context, KET_HDMI_SETTINGS)); + controllers.add(new StatusBarPreferenceController(context)); + controllers.add(new NavigationBarPreferenceController(context)); + controllers.add(new ExPlanPreferenceController(context));
packages/apps/Settings/src/com/android/settings/display/StatusBarPreferenceController.java
在Settings模块的StatusBarPreferenceController.java文件中,需要添加以下几行代码,用于实现状态栏开关偏好项的控制器,主要负责读取和写入系统属性,以及发送控制广播:
package com.android.settings.display; import android.content.Context; import android.provider.Settings; import androidx.preference.SwitchPreference; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.core.AbstractPreferenceController; import android.content.Intent; import android.util.Log; import android.os.SystemProperties; public class StatusBarPreferenceController extends AbstractPreferenceController implements Preference.OnPreferenceChangeListener { private static final String TAG = "StatusBarCtrl"; private static final boolean DEBUG = true; private static final String KEY_STATUS_BAR = "ctrl_statusbar"; private static final String SYS_PROP_STATUS_BAR_ENABLE = "persist.sys.statusbar.enable"; public static final String ACTION_HIDE_STATUS_BAR = "sys.statusbar.hide"; public static final String ACTION_SHOW_STATUS_BAR = "sys.statusbar.show"; public StatusBarPreferenceController(Context context) { super(context); } @Override public String getPreferenceKey() { return KEY_STATUS_BAR; } @Override public boolean isAvailable() { return true; } @Override public void displayPreference(PreferenceScreen screen) { if (!isAvailable()) { setVisible(screen, KEY_STATUS_BAR, false); return; } final SwitchPreference mStatusBarPreference = screen.findPreference(KEY_STATUS_BAR); if (mStatusBarPreference != null) { String value = SystemProperties.get(SYS_PROP_STATUS_BAR_ENABLE, "false"); mStatusBarPreference.setChecked(value.equals("true")); mStatusBarPreference.setOnPreferenceChangeListener(this); } } @Override public void updateState(Preference preference) { String value = SystemProperties.get(SYS_PROP_STATUS_BAR_ENABLE, "false"); ((SwitchPreference) preference).setChecked(value.equals("true")); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { boolean value = (Boolean) newValue; if (DEBUG) { Log.d(TAG, "key value " + value); } Intent intent = new Intent(); if (value) { intent.setAction(ACTION_SHOW_STATUS_BAR); } else { intent.setAction(ACTION_HIDE_STATUS_BAR); } mContext.sendBroadcast(intent); return true; } }
packages/apps/Settings/src/com/android/settings/display/NavigationBarPreferenceController.java
在Settings模块的NavigationBarPreferenceController.java文件中,需要添加以下几行代码,用于实现导航栏开关偏好项的控制器,主要负责读取和写入系统属性,以及发送控制广播:
package com.android.settings.display; import android.content.Context; import android.provider.Settings; import androidx.preference.SwitchPreference; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.core.AbstractPreferenceController; import android.content.Intent; import android.util.Log; import android.os.SystemProperties; public class NavigationBarPreferenceController extends AbstractPreferenceController implements Preference.OnPreferenceChangeListener { private static final String TAG = "NavigationBarCtrl"; private static final boolean DEBUG = true; private static final String KEY_NAVIGATION_BAR = "ctrl_navigationbar"; private static final String SYS_PROP_NAVIGATION_BAR_ENABLE = "persist.sys.navigationbar.enable"; public static final String ACTION_HIDE_NAVIGATION_BAR = "sys.navigationbar.hide"; public static final String ACTION_SHOW_NAVIGATION_BAR = "sys.navigationbar.show"; public NavigationBarPreferenceController(Context context) { super(context); } @Override public String getPreferenceKey() { return KEY_NAVIGATION_BAR; } @Override public boolean isAvailable() { return true; } @Override public void displayPreference(PreferenceScreen screen) { if (!isAvailable()) { setVisible(screen, KEY_NAVIGATION_BAR, false); return; } final SwitchPreference mNavigationBarPreference = screen.findPreference(KEY_NAVIGATION_BAR); if (mNavigationBarPreference != null) { String value = SystemProperties.get(SYS_PROP_NAVIGATION_BAR_ENABLE, "false"); mNavigationBarPreference.setChecked(value.equals("true")); mNavigationBarPreference.setOnPreferenceChangeListener(this); } } @Override public void updateState(Preference preference) { String value = SystemProperties.get(SYS_PROP_NAVIGATION_BAR_ENABLE, "false"); ((SwitchPreference) preference).setChecked(value.equals("true")); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { boolean value = (Boolean) newValue; if (DEBUG) { Log.d(TAG, "key value " + value); } Intent intent = new Intent(); if (value) { intent.setAction(ACTION_SHOW_NAVIGATION_BAR); } else { intent.setAction(ACTION_HIDE_NAVIGATION_BAR); } mContext.sendBroadcast(intent); return true; } }
packages/apps/Settings/src/com/android/settings/display/ExPlanPreferenceController.java
在Settings模块的ExPlanPreferenceController.java文件中,需要添加以下几行代码,用于实现下拉菜单开关偏好项的控制器,主要负责读取和写入系统属性,以及发送控制广播:
package com.android.settings.display; import android.content.Context; import android.provider.Settings; import androidx.preference.SwitchPreference; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.core.AbstractPreferenceController; import android.content.Intent; import android.util.Log; import android.os.SystemProperties; public class ExPlanPreferenceController extends AbstractPreferenceController implements Preference.OnPreferenceChangeListener { private static final String TAG = "ExPlanCtrl"; private static final boolean DEBUG = true; private static final String KEY_EXPLAN = "ctrl_explan"; private static final String SYS_PROP_EXPLAN_ENABLE = "persist.sys.explan.enable"; private static final String ACTION_HIDE_EXPLAN = "sys.explan.hide"; private static final String ACTION_SHOW_EXPLAN = "sys.explan.show"; public ExPlanPreferenceController(Context context) { super(context); } @Override public String getPreferenceKey() { return KEY_EXPLAN; } @Override public boolean isAvailable() { return true; } @Override public void displayPreference(PreferenceScreen screen) { if (!isAvailable()) { setVisible(screen, KEY_EXPLAN, false); return; } final SwitchPreference mExPlanPreference = screen.findPreference(KEY_EXPLAN); if (mExPlanPreference != null) { String value = SystemProperties.get(SYS_PROP_EXPLAN_ENABLE, "false"); mExPlanPreference.setChecked(value.equals("true")); mExPlanPreference.setOnPreferenceChangeListener(this); } } @Override public void updateState(Preference preference) { String value = SystemProperties.get(SYS_PROP_EXPLAN_ENABLE, "false"); ((SwitchPreference) preference).setChecked(value.equals("true")); } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { boolean value = (Boolean) newValue; if (DEBUG) { Log.d(TAG, "key value " + value); } Intent intent = new Intent(); if (value) { intent.setAction(ACTION_SHOW_EXPLAN); } else { intent.setAction(ACTION_HIDE_EXPLAN); } mContext.sendBroadcast(intent); return true; } }
这样就完成了Settings模块的修改,接下来直接编译并运行修改后的系统,并在设置中测试控制功能。
测试结果
以下是我在模拟器上测试的结果,您可以看到状态栏、导航栏和下拉菜单的显示和隐藏效果:
这是全部关闭的效果
这是全部打开的效果
重启后看到设置保存 到此, 需求实现完毕。
忘记了 如果要设置属性默认值你们自己随便找个位置添加就OK了。
+PRODUCT_PROPERTY_OVERRIDES += persist.sys.statusbar.enable=true +PRODUCT_PROPERTY_OVERRIDES += persist.sys.navigationbar.enable=true +PRODUCT_PROPERTY_OVERRIDES += persist.sys.explan.enable=true
结语
本文介绍了如何在Android系统中添加状态栏、导航栏和下拉菜单的控制功能,主要涉及了SystemUI模块和Settings模块的修改,以及系统属性和广播的使用。这些功能可以让用户控制和调用决定是否启用显示xx。
希望本文对你有所帮助,如果有任何问题或建议,请私信和留言。