This article is based on Android 10 source code analysis.

The StatusBar consists of three parts

  1. The leftmost section shows the operator, time, and notification ICONS
  2. The rightmost section shows the system icon, which consists of a status icon (such as wifi, BT) and a battery icon.
  3. There’s another area in the middle that I won’t talk about.

This article focuses on how status ICONS (e.g. Wifi, Bt) can be displayed under control.

Status bar icon controller

Status icon in the status bar control, will be done by an interface, this interface is StatusBarIconController, and its implementation class is StatusBarIconControllerImpl.

Let’s start with its annotations and inheritance structure

/** * Receives the callbacks from CommandQueue related to icons and tracks the state of * all the icons. Dispatches this  state to any IconManagers that are currently * registered with it. */
@Singleton
public class StatusBarIconControllerImpl extends StatusBarIconList 
                implements Tunable.CommandQueue.Callbacks.StatusBarIconController {}
Copy the code

The comment says that it receives callbacks about ICONS from CommandQueue and distributes them to the registered IconManager. However, it does more than that. SystemUI can call it from anywhere to set ICONS for the status bar, because it also implements the StatusBarIconController interface, which is described below

public interface StatusBarIconController {
    // Set the icon
    public void setIcon(String slot, int resourceId, CharSequence contentDescription);
    public void setIcon(String slot, StatusBarIcon icon);
    // Set the wifi icon
    public void setSignalIcon(String slot, WifiIconState state);
    // Set the phone signal icon
    public void setMobileIcons(String slot, List<MobileIconState> states);
    // Set icon visibility
    public void setIconVisibility(String slot, boolean b);
}
Copy the code

With that in mind, now look at what its constructor does

    // frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
    
    public StatusBarIconControllerImpl(Context context) {
        mContext = context;
        
        // Save the status bar icon name through the parent class
        super(context.getResources().getStringArray(
                com.android.internal.R.array.config_statusBarIcons));
                
        // Register a callback to CommandQueue
        SysUiServiceProvider.getComponent(context, CommandQueue.class)
                .addCallback(this);
        
        // Implement the blacklist function, the principle is to listen to the database blacklist value
        Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST);

    }
Copy the code

There are three main things going on here

  1. Save the name of the icon in the status bar.
  2. toCommandQueueRegister a callback.
  3. Listen to the database blacklist.

Blacklist function is very simple, is to monitor the database on the blacklist URI changes, and then update the blacklist list, and then set the icon when to query the blacklist, and then decide how to set.

CommandQueue is a Binder class registered with StatusBar#start() to receive messages from the server, which registers a callback on the server. And StatusBarIconControllerImpl CommandQueue to register the callback, it is to get information about icon, so that it can be correctly set icon in the status bar.

Now look at the config_statusBarIcons array that saves the ICONS ‘names

    // frameworks/base/core/res/res/values/config.xml
    
    <string-array name="config_statusBarIcons">
        <item><xliff:g id="id">@string/status_bar_alarm_clock</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_rotate</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_headset</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_data_saver</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_ime</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_sync_failing</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_sync_active</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_nfc</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_tty</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_speakerphone</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_cdma_eri</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_data_connection</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_phone_evdo_signal</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_phone_signal</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_secure</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_camera</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_microphone</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_location</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_mute</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_volume</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_zen</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_ethernet</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_wifi</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_hotspot</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_mobile</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_airplane</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_battery</xliff:g></item>
        <item><xliff:g id="id">@string/status_bar_sensors_off</xliff:g></item>
    </string-array>
Copy the code

This array defines not only the name of the icon, but also the order in which the icon is displayed, for example, wifi must come before the battery icon.

Register icon Manager

This article is to discuss the status icon control, according to the above said, it must first registered an icon with the StatusBarIconControllerImpl manager, according to the above can be speculated that this is implemented in CollapsedStatusBarFragment

    // frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
    
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        // ...
        
        // r.id.satusicons represent status icon areas, such as BT, wifi
        // Create an icon manager in the status icon area
        mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons));

        / / to StatusBarIconControllerImpl registration manager icon
        Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);  
        
        // ...
    }
Copy the code

Set status icon

With everything in place, how does the status icon set work? In StatusBar#start(), it is set by some policy

    // frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
    
    public void start(a) {
        // ...
        
        // Call the icon policy to install/update all ICONS
        mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController);
        mSignalPolicy = new StatusBarSignalPolicy(mContext, mIconController);
        
        // ...
    }        
Copy the code

All status ICONS are set in these two policy classes. How is the cell phone signal icon set? It’s in StatusBarSignalPolicy. Okay

    public StatusBarSignalPolicy(Context context, StatusBarIconController iconController) {
        mContext = context;

        // Get the signal icon name
        mSlotMobile   = mContext.getString(com.android.internal.R.string.status_bar_mobile);

        / / this is StatusBarIconContrllerImpl object
        mIconController = iconController;
        
        // Register the network listener
        mNetworkController = Dependency.get(NetworkController.class);
        mNetworkController.addCallback(this);
    }
Copy the code

To set an icon, first get the name of the icon, which can be obtained from the array mentioned above.

It then registers a network listener to get events about the phone signal

    @Override
    public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
            int qsType, boolean activityIn, boolean activityOut, int volteIcon,
            String typeContentDescription, String description, boolean isWide,
            int subId, boolean roaming) {
        // ...
        
        // Set the signal icon. The first parameter indicates the icon name and the second parameter indicates the status
        mIconController.setMobileIcons(mSlotMobile, MobileIconState.copyStates(mMobileStates));

        // ..
    }
Copy the code

As you can see, this is implemented via StatusBarIconController#setMobileIcons(), but I won’t go into the details.

Setting ICONS through the StatusBarIconController interface is the same

  1. Get icon name
  2. Listen for an event
  3. throughStatusBarIconControllerCorresponding method setting icon.

Set the icon without SIM card

Before, the company needed to set an icon without SIM. In fact, this interface has been provided by the system, which is in StatusBarSignalPolicy

     public void setNoSims(boolean show, boolean simDetected) {
        String mobileSlot = mContext.getString(com.android.internal.R.string.status_bar_mobile);
        if(show && ! simDetected) { mIconController.setIcon(mobileSlot, R.drawable.ic_no_sim_black_24dp,"no_sim");
            mIconController.setIconVisibility(mobileSlot, true);
        } else {
            mIconController.setIconVisibility(mobileSlot, false); }}Copy the code

Follow the formula, so easy!