Android系统 添加动态控制SystemUI状态栏、导航栏和下拉菜单

在Android系统中,状态栏(StatusBar)、导航栏(NavigationBar)和下拉菜单(ExPlan)是三个常见的用户界面元素,它们分别提供了一些基本的信息显示和交互功能。例如,状态栏可以显示时间、电量、信号等信息,导航栏可以提供返回、主页、多任务等按钮,下拉菜单可以提供快速设置、通知等选项。并不是所有客户的Android设备都需要或支持这些,有时候客户可能想要自由地控制它们的显示和隐藏。

本文将介绍如何在Android系统中定制添加状态栏、导航栏和下拉菜单的控制功能,以便客户可以根据需求使用。

实现步骤

要实现状态栏、导航栏和下拉菜单的控制功能,需要修改以下几个部分:

  • SystemUI模块:这是一个系统应用程序,负责显示和管理状态栏、导航栏和下拉菜单等界面元素。
  • Settings模块:这是一个系统应用程序,负责提供各种系统设置选项,包括显示设置。
  • 系统属性:这是一种用于存储和传递系统配置信息的机制,可以通过命令行或代码来读写。
  • 广播:这是一种用于在不同组件之间传递消息的机制,可以通过命令行或代码来发送和接收。

需要完成以下几个步骤:

  1. 在SystemUI模块中添加广播接收器,用于接收控制状态栏、导航栏和下拉菜单显示和隐藏的广播,并执行相应的操作。
  2. 在SystemUI模块中添加系统属性读取,用于获取状态栏、导航栏和下拉菜单的初始状态,并创建或移除相应的界面元素。
  3. 在Settings模块中添加开关偏好项,用于控制状态栏、导航栏和下拉菜单的开启和关闭,并发送相应的广播,并写入相应的系统属性。
  4. 编译并运行修改后的系统,并在设置中测试控制功能。

修改示例

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。

希望本文对你有所帮助,如果有任何问题或建议,请私信和留言。

猜你喜欢

转载自blog.csdn.net/SHH_1064994894/article/details/132483279