Android system adds dynamic control of SystemUI status bar, navigation bar and drop-down menu

In the Android system, status bar (StatusBar), navigation bar (NavigationBar) and drop-down menu (ExPlan) are three common user interface elements, which provide some basic information display and interactive functions respectively. For example, the status bar can display information such as time, power, signal, etc., the navigation bar can provide buttons such as return, homepage, and multitasking, and the drop-down menu can provide options such as quick settings and notifications. Not all customers' Android devices require or support these, and sometimes customers may want the freedom to control showing and hiding them.

This article will introduce how to customize and add status bar, navigation bar and drop-down menu control functions in the Android system so that customers can use them according to their needs.

Implementation steps

To implement the control functions of the status bar, navigation bar and drop-down menu, you need to modify the following parts:

  • SystemUI module: This is a system application responsible for displaying and managing interface elements such as status bars, navigation bars, and drop-down menus.
  • Settings module: This is a system application responsible for providing various system setting options, including display settings.
  • System properties: This is a mechanism for storing and passing system configuration information, which can be read and written from the command line or code.
  • Broadcast: This is a mechanism used to pass messages between different components and can be sent and received from the command line or code.

The following steps need to be completed:

  1. Add a broadcast receiver in the SystemUI module to receive broadcasts that control the display and hiding of the status bar, navigation bar, and drop-down menus, and perform corresponding operations.
  2. Add system property reading in the SystemUI module to obtain the initial state of the status bar, navigation bar and drop-down menu, and create or remove corresponding interface elements.
  3. Add a switch preference item in the Settings module to control the opening and closing of the status bar, navigation bar and drop-down menu, send corresponding broadcasts, and write corresponding system properties.
  4. Compile and run the modified system and test the control functionality in the setup.

Modify example

SystemUI module

frameworks/base/packages/SystemUI/AndroidManifest.xml

The following lines of code need to be added to the AndroidManifest.xml file of the SystemUI module to declare the broadcasts to be received:

    <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

A function needs to be added to the NavigationBarController.java file of the SystemUI module to remove all navigation bars:

    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

The PhoneStatusBarView.java file of the SystemUI module needs to be modified to determine whether to respond to the touch event of the drop-down menu based on the system properties: (
If this file is used for dynamic control and has bugs, other than this file, everything else will be modified normally)

-        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

In the StatusBar.java file of the SystemUI module, we need to add the following lines of code to declare and initialize some variables and methods:

+     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);
+   }

In the StatusBar.java file of the SystemUI module, you also need to modify the following lines of code to determine whether to create or hide the status bar, navigation bar, and drop-down menu during initialization based on system properties:

-        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) {
    
    
             ...
         }

In the StatusBar.java file of the SystemUI module, you also need to add the following lines of code to register and process the broadcasts we want to receive to achieve logical dynamic control:

         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 At this point we have completed the modification of the SystemUI module, is it very simple? Next we need to modify the Settings module.

Settings module

packages/apps/Settings/res/values/strings.xml

In the strings.xml file of the Settings module, you need to add the following lines of code to define the title of the switch preference item we want to display:

    <string name="ctrl_statusbar">状态栏</string>
    <string name="ctrl_explan">下拉菜单</string>
    <string name="ctrl_navigationbar">导航栏</string>

packages/apps/Settings/res/xml/display_settings.xml

In the display_settings.xml file of the Settings module, you need to add the following lines of code to create the switch preferences we want to display and specify their key values ​​and titles:

   <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

In the DisplaySettings.java file of the Settings module, you need to add the following lines of code to register the controller of the switch preference item we want to control:

        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

In the StatusBarPreferenceController.java file of the Settings module, you need to add the following lines of code to implement the controller for the status bar switch preference item. It is mainly responsible for reading and writing system properties, and sending control broadcasts:

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

In the NavigationBarPreferenceController.java file of the Settings module, you need to add the following lines of code to implement the controller for the navigation bar switch preference item. It is mainly responsible for reading and writing system properties, and sending control broadcasts:

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

In the ExPlanPreferenceController.java file of the Settings module, you need to add the following lines of code to implement the controller for the drop-down menu switch preference item. It is mainly responsible for reading and writing system properties, and sending control broadcasts:

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;
    }
}

This completes the modification of the Settings module. Next, compile and run the modified system directly, and test the control function in the settings.

Test Results

The following are the results of my test on the simulator. You can see the display and hiding effects of the status bar, navigation bar and drop-down menu:

This is the effect of turning everything off.
Insert image description here
This is the effect of turning everything on.
Insert image description here
After restarting, you will see that the settings are saved here, and the requirements are completed.

I forgot that if you want to set the default value of an attribute, you can just find a location and add it yourself.

+PRODUCT_PROPERTY_OVERRIDES += persist.sys.statusbar.enable=true
+PRODUCT_PROPERTY_OVERRIDES += persist.sys.navigationbar.enable=true
+PRODUCT_PROPERTY_OVERRIDES += persist.sys.explan.enable=true

Conclusion

This article introduces how to add the control functions of status bar, navigation bar and drop-down menu in Android system. It mainly involves the modification of SystemUI module and Settings module, as well as the use of system properties and broadcast. These functions allow users to control and call the decision whether to enable display xx.

I hope this article is helpful to you. If you have any questions or suggestions, please send a private message and leave a message.

Guess you like

Origin blog.csdn.net/SHH_1064994894/article/details/132483279