Android6.0 SystemUI network signal bar display refresh

The display refresh of Android's network signal bar is also part of SystemUI. The main business logic is also in the SystemUI module. The beginning of the entire process is in PhoneStatusBar.java.

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java;



Let's start with the layout: makeStatusBarView() of PhoneStatusBar.java loads super_status_bar.xml uniformly. In Android, there are three main places where the signal status bar is displayed on the SystemUI, namely the status bar, the status bar under the lock screen interface, and the shortcut setting area of ​​the drop-down notification bar. The three references are status_bar.xml, keyguard_status_bar.xml, status_bar_expanded_header.xml; and these three layout files will all include a system_icons.xml layout,
which is the network signal bar display and battery icon display view you are looking for local.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/system_icons"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:gravity="center_vertical">

    <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/statusIcons"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal"/>

    <include layout="@layout/signal_cluster_view"
        android:id="@+id/signal_cluster"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="2.5dp"/>

    <!-- battery must be padded below to match assets -->
    <com.android.systemui.BatteryMeterView android:id="@+id/battery"
        android:layout_height="14.5dp"
        android:layout_width="9.5dp"
        android:layout_marginBottom="@dimen/battery_margin_bottom"/>
</LinearLayout>
This layout will include a signal_cluster_view.xml layout, that is, this layout is the layout file of the specific signal bar

<com.android.systemui.statusbar.SignalClusterView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="wrap_content"
    android:gravity="center_vertical"
    android:orientation="horizontal"
    android:paddingEnd="@dimen/signal_cluster_battery_padding"
    >
    <ImageView
        android:id="@+id/vpn"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:paddingEnd="6dp"
        android:src="@drawable/stat_sys_vpn_ic"
        />
    <FrameLayout
        android:id="@+id/wifi_combo"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        >
        <ImageView
            android:id="@+id/wifi_signal"
            android:layout_height="wrap_content"
            android:layout_width="wrap_content"
            />
    </FrameLayout>
    <View
        android:id="@+id/wifi_signal_spacer"
        android:layout_width="4dp"
        android:layout_height="4dp"
        android:visibility="gone"
        />
    <LinearLayout
        android:id="@+id/mobile_signal_group"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        >
    </LinearLayout>
    <ImageView
        android:id="@+id/no_sims"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:src="@drawable/stat_sys_no_sims"
        />
    <View
        android:id="@+id/wifi_airplane_spacer"
        android:layout_width="4dp"
        android:layout_height="4dp"
        android:visibility="gone"
        />
    <ImageView
        android:id="@+id/airplane"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        />
</com.android.systemui.statusbar.SignalClusterView>


Code logic:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/
PhoneStatusBar.java makeStatusBarView() method:

In this method, first create two controllers mNetworkController and mSecurityController;

mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
mSecurityController = new SecurityControllerImpl(mContext);
NetworkControllerImpl.java inherits from BroadcastReceiver, and then look at the construction method of NetworkControllerImpl:

public NetworkControllerImpl(Context context, Looper bgLooper) {
        this(context, (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE),
                (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE),
                (WifiManager) context.getSystemService(Context.WIFI_SERVICE),
                SubscriptionManager.from(context), Config.readConfig(context), bgLooper,
                new CallbackHandler(),
                new AccessPointControllerImpl(context, bgLooper),
                new MobileDataControllerImpl(context),
                new SubscriptionDefaults());
        mReceiverHandler.post(mRegisterListeners);
    }
This construction method will first call another construction method;

@VisibleForTesting
    NetworkControllerImpl(Context context, ConnectivityManager connectivityManager,
            TelephonyManager telephonyManager, WifiManager wifiManager,
            SubscriptionManager subManager, Config config, Looper bgLooper,
            CallbackHandler callbackHandler,
            AccessPointControllerImpl accessPointController,
            MobileDataControllerImpl mobileDataController,
            SubscriptionDefaults defaultsHandler) {
        mContext = context;
        mConfig = config;
        mReceiverHandler = new Handler(bgLooper);
        mCallbackHandler = callbackHandler;

        mSubscriptionManager = subManager;
        mSubDefaults = defaultsHandler;
        mConnectivityManager = connectivityManager;
        mHasMobileDataFeature =
                mConnectivityManager.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);

        // telephony
        mPhone = telephonyManager;

        // wifi
        mWifiManager = wifiManager;

        mLocale = mContext.getResources().getConfiguration().locale;
        mAccessPoints = accessPointController;
        mMobileDataController = mobileDataController;
        mMobileDataController.setNetworkController(this);
        // TODO: Find a way to move this into MobileDataController.
        mMobileDataController.setCallback(new MobileDataControllerImpl.Callback() {
            @Override
            public void onMobileDataEnabled(boolean enabled) {
                mCallbackHandler.setMobileDataEnabled(enabled);
            }
        });
        mWifiSignalController = new WifiSignalController(mContext, mHasMobileDataFeature,
                mCallbackHandler, this);

        mEthernetSignalController = new EthernetSignalController(mContext, mCallbackHandler, this);

        // AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
        updateAirplaneMode(true /* force callback */);
    }
1. Assign values ​​to the corresponding member variables;
2. Create handlers, mReceiverHandler and mCallbackHandler;
3. Create mMobileDataController controllers and set callbacks for them;
4. Create mWifiSignalController and mEthernetSignalController controllers;
5. Check and update the flight mode;


Then after executing this internal construction method, the next step is to use mReceiverHandler to perform a registration broadcast operation, responsible for monitoring wifi, SIM card status, service state, flight mode, etc., and finally call the updateMobileControllers() method to initialize the signal bar display:

mReceiverHandler.post(mRegisterListeners);
    /**
     * Used to register listeners from the BG Looper, this way the PhoneStateListeners that
     * get created will also run on the BG Looper.
     */
    private final Runnable mRegisterListeners = new Runnable() {
        @Override
        public void run() {
            registerListeners();
        }
    };
    private void registerListeners() {
        for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
            mobileSignalController.registerListener();
        }
        if (mSubscriptionListener == null) {
            mSubscriptionListener = new SubListener();
        }
        mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener);

        // broadcasts
        IntentFilter filter = new IntentFilter();
        filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
        filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
        filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
        filter.addAction(Intent.ACTION_LOCALE_CHANGED);
        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        if (carrier != null && (CarrierAppUtils.CARRIER.TELEPHONY_CARRIER_ONE
                == carrier)) {
        filter.addAction(ACTION_EMBMS_STATUS);
        }
        mContext.registerReceiver(this, filter, null, mReceiverHandler);
        mListening = true;

        updateMobileControllers();
    }
After analyzing the construction method of NetworkControllerImpl.java, we can basically know that NetworkControllerImpl.java is used as the signal bar data control class, responsible for monitoring wifi, service state, flight mode, etc.


Let's look at the construction method of SecurityControllerImpl.java, which mainly obtains some system service instances first, and then registers a network callback interface when the user switches;

    public SecurityControllerImpl(Context context) {
        mContext = context;
        mDevicePolicyManager = (DevicePolicyManager)
                context.getSystemService(Context.DEVICE_POLICY_SERVICE);
        mConnectivityManager = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);
        mConnectivityManagerService = IConnectivityManager.Stub.asInterface(
                ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
        mUserManager = (UserManager)
                context.getSystemService(Context.USER_SERVICE);

        // TODO: re-register network callback on user change.
        mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback);
        onUserSwitched(ActivityManager.getCurrentUser());
    }



Go back to the makeStatusBarView() method of PhoneStatusBar.java, and then instantiate the custom view object SignalClusterView. As mentioned above, the network signal status bar needs to be used in the three places of android SystemUI, so I instantiated it three times and used it for it. Add the corresponding interface.

final SignalClusterView signalCluster =
                (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
        final SignalClusterView signalClusterKeyguard =
                (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster);
        final SignalClusterView signalClusterQs =
                (SignalClusterView) mHeader.findViewById(R.id.signal_cluster);
        mNetworkController.addSignalCallback(signalCluster);
        mNetworkController.addSignalCallback(signalClusterKeyguard);
        mNetworkController.addSignalCallback(signalClusterQs);
        signalCluster.setSecurityController(mSecurityController);
        signalCluster.setNetworkController(mNetworkController);
        signalClusterKeyguard.setSecurityController(mSecurityController);
        signalClusterKeyguard.setNetworkController(mNetworkController);
        signalClusterQs.setSecurityController(mSecurityController);
        signalClusterQs.setNetworkController(mNetworkController);
Let’s take a look at the addSignalCallback() method first. The parameter passed in is an object of SignalClusterView.java, which means that you can boldly speculate that the function of this method should be to establish callback calls for SignalClusterView.java and NetworkControllerImpl.java. Can be analyzed in detail, the main implementation of this method is in NetworkControllerImpl.java

public void addSignalCallback(SignalCallback cb) {
        mCallbackHandler.setListening(cb, true);
        mCallbackHandler.setSubs(mCurrentSubscriptions);
        mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
                TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
        mCallbackHandler.setNoSims(mHasNoSims);
        mWifiSignalController.notifyListeners();
        mEthernetSignalController.notifyListeners();
        for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
            mobileSignalController.notifyListeners();
        }
    }
Call the CallbackHandler.setXXX() method. These methods mainly send a msg to the handler to perform the corresponding operation. Take the setListening() method as an example:
first send a message with msg as MSG_ADD_REMOVE_SIGNAL to the handler:

    public void setListening(SignalCallback listener, boolean listening) {
        obtainMessage(MSG_ADD_REMOVE_SIGNAL, listening ? 1 : 0, 0, listener).sendToTarget();
    }
Add the callback to the collection in the handler to store it, and complete the setListening() method:

case MSG_ADD_REMOVE_SIGNAL:
    if (msg.arg1 != 0) {
        mSignalCallbacks.add((SignalCallback) msg.obj);
     } else {
        mSignalCallbacks.remove((SignalCallback) msg.obj);
     }
     break;
After analyzing these setXXX() methods, it is found that the CallBackHandler.java class is mainly used for message transmission between NetworkControllerImpl.java and SignalClusterView.java, and the two are implemented through the callback of the NetworkController.SignalCallback interface;

Next, call the notifyListeners() methods of the wifi, Ethernet signal, and cell phone signal controllers to perform initialization information state operations.

Go back to the makeStatusBarView() method of PhoneStatusBar.java, and then continue to call the SignalClusterView.java method:

signalCluster.setSecurityController(mSecurityController);
signalCluster.setNetworkController(mNetworkController);
setNetworkController()方法主要是实例化该类的NetworkControllerImpl控制对象;
    public void setNetworkController(NetworkControllerImpl nc) {
        if (DEBUG) Log.d(TAG, "NetworkController=" + nc);
        mNC = nc;
    }

    public void setSecurityController(SecurityController sc) {
        if (DEBUG) Log.d(TAG, "SecurityController=" + sc);
        mSC = sc;
        mSC.addCallback(this);
        mVpnVisible = mSC.isVpnEnabled();
    }

The setSecurityController() method not only needs to assign values ​​to member variables, but also needs to call the addCallback() method of SecurityControllerImpl.java to add the callback object of this controller to the collection mCallbacks to save;

    @Override
    public void addCallback(SecurityControllerCallback callback) {
        synchronized (mCallbacks) {
            if (callback == null || mCallbacks.contains(callback)) return;
            if (DEBUG) Log.d(TAG, "addCallback " + callback);
            mCallbacks.add(callback);
        }
    }
At this point, the signal bar is analyzed in makeStatusBarView() in PhoneStatusBar.java.

Summary of the process execution of the signal bar in makeStatusBarView() of PhoneStatusBar.java:
1. Instantiate two controller implementation objects, NetworkControllerImpl.java and SecurityControllerImpl.java; register the corresponding state change broadcast in the construction method of NetworkControllerImpl.java , Register in SecurityControllerImpl.java to monitor the callback of the network status change when the user switches;
2. Initialize the signal bar object, SignalClusterView.java;
3. Link NetworkControllerImpl.java and SignalClusterView.java through CallbackHandler.java, and use callbacks in the middle To realize the control communication between NetworkControllerImpl.java and SignalClusterView.java;
4. SignalClusterView.java calls setSecurityController() to implement the SecurityControllerCallback interface, and implements the monitoring of network state changes when switching users through the callback onStateChanged() method;
5.NetworkControllerImpl.java is As the signal bar data control class, inherited from BroadcastReceiver, responsible for monitoring wifi, SIM card status, service state, flight mode, etc.
6. SignalClusterView.java is used to refresh and display the interface;



Next, let’s analyze the process executed by SystemUI when some status changes, taking the example of inserting a SIM card:

1. When the SIM card is inserted, the android system will send TelephonyIntents.ACTION_SIM_STATE_CHANGED broadcast;
2. NetworkControllerImpl.java inherits from BroadcastReceiver and monitors some corresponding system broadcasts;

3. After receiving the TelephonyIntents.ACTION_SIM_STATE_CHANGED broadcast, call the onReceiver() method of NetworkControllerImpl.java and call the updateMobileControllers() method;

if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
    // Might have different subscriptions now.
    updateMobileControllers();
} 
4. Internally call the doUpdateMobileControllers() method;

private void updateMobileControllers() {
        if (!mListening) {
            return;
        }
        doUpdateMobileControllers();
    }
5. Get the sim card information in the current device, if the return is empty, then this set will be empty for processing; if there is no change in the subscription information of the sim card, it will enter the if() statement and then call the updateNoSims() method and then return; Because the current analysis is to insert the sim card, this if() statement will not be entered;
    @VisibleForTesting
    void doUpdateMobileControllers() {
        List<SubscriptionInfo> subscriptions = mSubscriptionManager.getActiveSubscriptionInfoList();
        if (subscriptions == null) {
            subscriptions = Collections.emptyList();
        }
        // If there have been no relevant changes to any of the subscriptions, we can leave as is.
        if (hasCorrectMobileControllers(subscriptions)) {
            // Even if the controllers are correct, make sure we have the right no sims state.
            // Such as on boot, don't need any controllers, because there are no sims,
            // but we still need to update the no sim state.
            updateNoSims();
            return;
        }
        setCurrentSubscriptions(subscriptions);
        updateNoSims();
        recalculateEmergency();
    }

Call the setCurrentSubscriptions() method; this method is mainly to construct the MobileSignalController according to the returned sim card subscription information collection, and use the collection Map<Integer, MobileSignalController> mMobileSignalControllers to store it;

    @VisibleForTesting
    void setCurrentSubscriptions(List<SubscriptionInfo> subscriptions) {
        Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() {
            @Override
            public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) {
                return lhs.getSimSlotIndex() == rhs.getSimSlotIndex()
                        ? lhs.getSubscriptionId() - rhs.getSubscriptionId()
                        : lhs.getSimSlotIndex() - rhs.getSimSlotIndex();
            }
        });
        mCurrentSubscriptions = subscriptions;

        HashMap<Integer, MobileSignalController> cachedControllers =
                new HashMap<Integer, MobileSignalController>(mMobileSignalControllers);
        mMobileSignalControllers.clear();
        final int num = subscriptions.size();
        for (int i = 0; i < num; i++) {
            int subId = subscriptions.get(i).getSubscriptionId();
            // If we have a copy of this controller already reuse it, otherwise make a new one.
            if (cachedControllers.containsKey(subId)) {
                mMobileSignalControllers.put(subId, cachedControllers.remove(subId));
            } else {
                MobileSignalController controller = new MobileSignalController(mContext, mConfig,
                        mHasMobileDataFeature, mPhone, mCallbackHandler,
                        this, subscriptions.get(i), mSubDefaults, mReceiverHandler.getLooper());
                mMobileSignalControllers.put(subId, controller);
                if (subscriptions.get(i).getSimSlotIndex() == 0) {
                    mDefaultSignalController = controller;
                }
                if (mListening) {
                    controller.registerListener();
                }
            }
        }
        if (mListening) {
            for (Integer key : cachedControllers.keySet()) {
                if (cachedControllers.get(key) == mDefaultSignalController) {
                    mDefaultSignalController = null;
                }
                cachedControllers.get(key).unregisterListener();
            }
        }
        mCallbackHandler.setSubs(subscriptions);
        notifyAllListeners();

        // There may be new MobileSignalControllers around, make sure they get the current
        // inet condition and airplane mode.
        pushConnectivityToSignals();
        updateAirplaneMode(true /* force */);
    }
The MobileSignalController.java class is mainly used to encapsulate the controller of the corresponding Icon according to the signal strength, operator, network type, etc.,

    public MobileSignalController(Context context, Config config, boolean hasMobileData,
            TelephonyManager phone, CallbackHandler callbackHandler,
            NetworkControllerImpl networkController, SubscriptionInfo info,
            SubscriptionDefaults defaults, Looper receiverLooper) {
        super("MobileSignalController(" + info.getSubscriptionId() + ")", context,
                NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
                networkController);
        mNetworkToIconLookup = new SparseArray<>();
        mConfig = config;
        mPhone = phone;
        mDefaults = defaults;
        mSubscriptionInfo = info;
        mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId(),
                receiverLooper);
        mNetworkNameSeparator = getStringIfExists(R.string.status_bar_network_name_separator);
        mNetworkNameDefault = getStringIfExists(
                com.android.internal.R.string.lockscreen_carrier_default);
        mIsDataSignalControlEnabled = mContext.getResources()
                .getBoolean(R.bool.config_data_signal_control);
        if (mIsDataSignalControlEnabled) {
            mDataEnabledSettingObserver =
                    new DataEnabledSettingObserver(new Handler(), context);
            mLastState.isForbidden = mCurrentState.isForbidden =
                  !(isMobileDataEnabled(mSubscriptionInfo.getSubscriptionId()));
        }
        if (config.readIconsFromXml) {
            TelephonyIcons.readIconsFromXml(context);
            mDefaultIcons = !mConfig.showAtLeast3G ? TelephonyIcons.G : TelephonyIcons.THREE_G;
        } else {
            mapIconSets();
        }

        if (carrier != null && (CarrierAppUtils.CARRIER.TELEPHONY_CARRIER_ONE
                 == carrier)) {
            mStyle = context.getResources().getInteger(R.integer.status_bar_style_extended);
        } else {
            mStyle = context.getResources().getInteger(R.integer.status_bar_style);
        }

        String networkName = info.getCarrierName() != null ? info.getCarrierName().toString()
                : mNetworkNameDefault;
        mLastState.networkName = mCurrentState.networkName = networkName;
        mLastState.networkNameData = mCurrentState.networkNameData = networkName;
        mLastState.enabled = mCurrentState.enabled = hasMobileData;
        mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons;
        // Get initial data sim state.
        updateDataSim();
    }
1. MobilePhoneStateListener is used to monitor signal strength, mobile data link status, etc. When it detects changes in signal strength, mobile data connection, etc., it will call the updateTelephony() method to update the current state, set the network type, icon, signal strength, etc.; then call the notifyListenersIfNecessary() method to call notifyListeners() Method, through the CallbackHandler object to call the setMobileDataIndicators() method in SignalClusterView.java to refresh the icon;
2. mapIconSets() is used to set the Icon map collection of the network type;
3. After this construction method is executed, it will return to NetworkControllerImpl. java setCurrentSubscriptions() method, execute controller.registerListener() statement to register MobilePhoneStateListener listener for each MobileSignalController object;


Then call mCallbackHandler.setSubs() to pass the subscription information collection of the sim card to the setSubs() method of SignalClusterView.java. First, it will clear the previous mPhoneStates information and mMobileSignalGroup view, and then call the inflatePhoneState() method;

    @Override
    public void setSubs(List<SubscriptionInfo> subs) {
        if (hasCorrectSubs(subs)) {
            return;
        }
        // Clear out all old subIds.
        mPhoneStates.clear();
        if (mMobileSignalGroup != null) {
            mMobileSignalGroup.removeAllViews();
        }
        final int n = subs.size();
        boolean imsOverWiFi = false;
        for (int i = 0; i < n; i++) {
            inflatePhoneState(subs.get(i).getSubscriptionId());
            imsOverWiFi |= getImsOverWifiStatus(subs.get(i).getSubscriptionId());
        }
        mImsOverWifi = imsOverWiFi;
        if (isAttachedToWindow()) {
            applyIconTint();
        }
    }
Call the inflatePhoneState() method to re-add state and view;

    private PhoneState inflatePhoneState(int subId) {
        PhoneState state = new PhoneState(subId, mContext);
        if (mMobileSignalGroup != null) {
            mMobileSignalGroup.addView(state.mMobileGroup);
        }
        mPhoneStates.add(state);
        return state;
    }

Then go back to the setSubs() method and call the applyIconTint() method to set some Icon colors;

    private void applyIconTint() {
        setTint(mVpn, mIconTint);
        setTint(mAirplane, mIconTint);
        applyDarkIntensity(mDarkIntensity, mNoSims, mNoSimsDark);
        applyDarkIntensity(mDarkIntensity, mWifi, mWifiDark);
        applyDarkIntensity(mDarkIntensity, mEthernet, mEthernetDark);
        for (int i = 0; i < mPhoneStates.size(); i++) {
            mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity);
        }
    }
Continue back to the setCurrentSubscriptions() method of NetworkControllerImpl.java, and then call the notifyAllListeners() method to notify mWifiSignalController(wifi), mEthernetSignalController(Ethernet) and all mobileSignalController(cell phone signals) to execute their respective notifyListeners() methods;

notifyAllListeners();
    /**
     * Forces update of all callbacks on both SignalClusters and
     * NetworkSignalChangedCallbacks.
     */
    private void notifyAllListeners() {
        notifyListeners();
        for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
            mobileSignalController.notifyListeners();
        }
        mWifiSignalController.notifyListeners();
        mEthernetSignalController.notifyListeners();
    }
Mainly look at the notifyListeners() method of MobileSignalController.java. This method is mainly used to set the display Icon image attribute of the current sim card attribute; then use the CallbackHandler object to call the setMobileDataIndicators() method in SignalClusterView.java;

    @Override
    public void notifyListeners() {
        if (mConfig.readIconsFromXml) {
            generateIconGroup();
        }
        MobileIconGroup icons = getIcons();

        String contentDescription = getStringIfExists(getContentDescription());
        String dataContentDescription = getStringIfExists(icons.mDataContentDescription);

        // Show icon in QS when we are connected or need to show roaming.
        boolean showDataIcon = false;
        if (mContext.getResources().getBoolean(R.bool.show_roaming_and_network_icons)) {
            showDataIcon = mCurrentState.dataConnected;
        } else {
            showDataIcon = mCurrentState.dataConnected
                    || (mCurrentState.iconGroup == TelephonyIcons.ROAMING || isRoaming());
        }
        IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
                getCurrentIconId(), contentDescription);

        int qsTypeIcon = 0;
        IconState qsIcon = null;
        String description = null;
        // Only send data sim callbacks to QS.
        if (mCurrentState.dataSim) {
            qsTypeIcon = showDataIcon ? icons.mQsDataType : 0;
            qsIcon = new IconState(mCurrentState.enabled
                    && !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);
            description = mCurrentState.isEmergency ? null : mCurrentState.networkName;
        }
        boolean activityIn = mCurrentState.dataConnected
                        && !mCurrentState.carrierNetworkChangeMode
                        && mCurrentState.activityIn;
        boolean activityOut = mCurrentState.dataConnected
                        && !mCurrentState.carrierNetworkChangeMode
                        && mCurrentState.activityOut;
        if (!mContext.getResources().getBoolean(R.bool.show_roaming_and_network_icons)) {
            showDataIcon &= mCurrentState.isDefault
                    || (mCurrentState.iconGroup == TelephonyIcons.ROAMING || isRoaming());
        }
        showDataIcon &= (mStyle == STATUS_BAR_STYLE_ANDROID_DEFAULT
                || mStyle == STATUS_BAR_STYLE_EXTENDED);
        int typeIcon = showDataIcon ? icons.mDataType : 0;
        int dataActivityId = showMobileActivity() ? 0 : icons.mActivityId;
        int mobileActivityId = showMobileActivity() ? icons.mActivityId : 0;
        int dataNetworkTypeInRoamingId = 0;
        if (mStyle == STATUS_BAR_STYLE_EXTENDED && isRoaming()) {
            dataNetworkTypeInRoamingId = mCurrentState.dataConnected ? typeIcon : 0;
            typeIcon = TelephonyIcons.ROAMING_ICON;
            qsTypeIcon = mCurrentState.dataConnected ? qsTypeIcon : 0;
        }
        mCallbackHandler.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
                activityIn, activityOut, dataActivityId, mobileActivityId,
                icons.mStackedDataIcon, icons.mStackedVoiceIcon,
                dataContentDescription, description, icons.mIsWide,
                mSubscriptionInfo.getSubscriptionId(), getImsIconId(),
                isImsRegisteredInWifi(), dataNetworkTypeInRoamingId,
                getEmbmsIconId());

        mCallbackHandler.post(new Runnable() {
            @Override
            public void run() {
                mNetworkController.updateNetworkLabelView();
            }
        });
    }
Call the setMobileDataIndicators() method in SignalClusterView.java to complete the state refresh of the current PhoneState object, and finally call the apply() method to complete the refresh of the Icon icon on the interface;
    @Override
    public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
            int qsType, boolean activityIn, boolean activityOut, int dataActivityId,
            int mobileActivityId, int stackedDataId, int stackedVoiceId,
            String typeContentDescription, String description, boolean isWide, int subId) {
        PhoneState state = getState(subId);
        if (state == null) {
            return;
        }
        state.mMobileVisible = statusIcon.visible && !mBlockMobile;
        state.mMobileStrengthId = statusIcon.icon;
        state.mMobileTypeId = statusType;
        state.mMobileDescription = statusIcon.contentDescription;
        state.mMobileTypeDescription = typeContentDescription;
        state.mIsMobileTypeIconWide = statusType != 0 && isWide;
        state.mDataActivityId = dataActivityId;
        state.mMobileActivityId = mobileActivityId;
        state.mStackedDataId = stackedDataId;
        state.mStackedVoiceId = stackedVoiceId;

        apply();
    }
It is possible that in the process of the above operation, the network connection status has changed, and finally return to the NetworkControllerImpl.java class to continue to execute the pushConnectivityToSignals() method to push the current network connection status to all SignalControllers object controllers.


Summary of signal bar:
1. Load the layout by the makeStatusBarView() method of PhoneStatusBar.java. Since the signal bar is used in three places in the Android system (the status bar, the status bar under the lock screen, and the shortcut setting area of ​​the drop-down notification bar), the three references are status_bar.xml, keyguard_status_bar.xml, status_bar_expanded_header .xml), instantiate three objects, and bind two controller objects for each SignalClusterView.java object in this method, NetworkControllerImpl.java, SecurityControllerImpl.java;
2. The NetworkControllerImpl.java object is mainly responsible for serving as the signal bar Data control class, inherited from BroadcastReceiver, responsible for monitoring wifi, SIM card status, service state, flight mode, etc.
The SecurityControllerImpl.java object is mainly responsible for the data control class of the signal bar when the user switches, and is responsible for monitoring the network state change callbacks when the user switches;
3. NetworkControllerImpl.java associates itself with SignalClusterView.java through CallbackHandler.java, and passes in Call the method of SignalClusterView.java in the object of CallbackHandler.java to realize the control communication of NetworkControllerImpl.java to SignalClusterView.java;
On the other hand, SignalClusterView.java completes the communication function by directly implementing the interface of SecurityController.java. In SecurityControllerImpl.java, it notifies SignalClusterView.java to perform the corresponding operation through the direct callback onStateChanged() method;
4. NetworkControllerImpl.java inherits from BroadcastReceiver, Monitor system broadcasts, etc. to monitor SIM card event changes, etc. When the SIM card is inserted, the subscription information collection of the current SIM card will be obtained, and then this collection will be traversed, and a MobileSignalController.java will be set for the subscription information.
5. The MobileSignalController.java class mainly implements the PhoneStateListener interface to monitor service state, signal strength, call status, and mobile data connection status, and set corresponding display icons. Then pass these status and icon display attributes to the SignalClusterView.java object through CallbackHandler.java.
6. SignalClusterView.java completes the final interface refresh by calling the apply() method and the apply() method of the internal class PhoneState.

























Guess you like

Origin blog.csdn.net/Otaku_627/article/details/53613642