Android6.0 SystemUI之网络信号栏显示刷新

Android的网络信号栏的显示刷新也是SystemUI的一部分,主要业务逻辑也是在SystemUI这模块内的,整个流程的开始是在PhoneStatusBar.java内的,

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


先从布局方面入手:
由PhoneStatusBar.java的makeStatusBarView()统一加载super_status_bar.xml的。而在Android中,SystemUI上显示信号状态栏的地方主要由三处,分别是状态栏、锁屏界面下的状态栏以及下拉通知栏的快捷设置区域。这三个引用处分别是status_bar.xml、keyguard_status_bar.xml、status_bar_expanded_header.xml;而这三个布局文件都会去include一个system_icons.xml布局,
这个布局就是所要寻找的网络信号栏显示和电池图标显示view的地方。

<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>
这个布局又会去include一个signal_cluster_view.xml布局,即这个布局才是具体的信号栏的布局文件

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


代码逻辑方面:
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
makeStatusBarView()方法:

在这个方法内先去创建两个控制器mNetworkController、mSecurityController;

mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
mSecurityController = new SecurityControllerImpl(mContext);
NetworkControllerImpl.java继承于BroadcastReceiver,再看下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);
    }
这个构造方法内部会先去调用一个另外的构造方法;

@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、给相应的成员变量赋值;
2、创建handler,mReceiverHandler、mCallbackHandler;
3、创建mMobileDataController控制器,并为其设置回调;
4、创建mWifiSignalController,mEthernetSignalController控制器;
5、检查更新飞行模式;


然后执行完这个内部的构造方法后,接下来会去使用mReceiverHandler去执行一个注册广播的操作,负责监控 wifi, SIM卡状态, service state ,飞行模式等等,最后调用updateMobileControllers()方法初始化一下信号栏显示:

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();
    }
分析完NetworkControllerImpl.java的构造方法之后,基本上我们可以知道NetworkControllerImpl.java是作为信号栏数据控制类,负责监控 wifi, service state ,飞行模式等。


再来看SecurityControllerImpl.java的构造方法,主要先获取一些系统服务的实例,然后再去注册一个用户切换时候的网络回调接口;

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



回到PhoneStatusBar.java的makeStatusBarView()方法,接下来实例化自定义的view对象SignalClusterView,上面说过在android SystemUI的三个地方都需要使用网络信号状态栏,所以分别实例化了三次,并为其添加相应的接口。

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);
先来看下addSignalCallback()方法,传入的参数为SignalClusterView.java的对象,也就是可以大胆推测这个方法的作用应该就是将SignalClusterView.java和NetworkControllerImpl.java建立callback调用。可以具体来分析下,这个方法的主要实现是在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();
        }
    }
调用CallbackHandler.setXXX()方法,这些方法主要是通过发送一个msg到handler去执行相应的操作,以setListening()方法为例:
先发送msg为MSG_ADD_REMOVE_SIGNAL的消息到handler:

    public void setListening(SignalCallback listener, boolean listening) {
        obtainMessage(MSG_ADD_REMOVE_SIGNAL, listening ? 1 : 0, 0, listener).sendToTarget();
    }
在handler中将callback添加到集合中存储起来,完成setListening()方法:

case MSG_ADD_REMOVE_SIGNAL:
    if (msg.arg1 != 0) {
        mSignalCallbacks.add((SignalCallback) msg.obj);
     } else {
        mSignalCallbacks.remove((SignalCallback) msg.obj);
     }
     break;
经过对这些setXXX()方法的分析发现,CallBackHandler.java这个类主要是用来NetworkControllerImpl.java与SignalClusterView.java之间的消息传递,二者之间通过NetworkController.SignalCallback接口的回调来实现的;

接下来分别去调用wifi、以太网信号、手机信号控制器的notifyListeners()方法去分别执行初始化信息状态操作。

回到PhoneStatusBar.java的makeStatusBarView()方法,接下来继续调用SignalClusterView.java的方法:

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

而setSecurityController()方法不仅需要给成员变量赋值,还需要去调用SecurityControllerImpl.java的addCallback()方法,将这个控制器的callback对象添加到集合mCallbacks中保存;

    @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);
        }
    }
至此完成信号栏在PhoneStatusBar.java的makeStatusBarView()中执行分析。

信号栏在PhoneStatusBar.java的makeStatusBarView()中的流程执行小结:
1、实例化两个控制器实现对象,NetworkControllerImpl.java、SecurityControllerImpl.java;在NetworkControllerImpl.java的构造方法中去注册相应状态改变的广播,在SecurityControllerImpl.java中注册用户切换时网络状态改变的监听回调;
2、初始化信号栏对象,SignalClusterView.java;
3、通过CallbackHandler.java将NetworkControllerImpl.java和SignalClusterView.java联系起来,中间通过回调的方式来实现NetworkControllerImpl.java对SignalClusterView.java控制通信;
4、SignalClusterView.java调用setSecurityController()来实现SecurityControllerCallback接口,通过回调onStateChanged()方法来实现对切换用户时网络状态改变的监听;
5、NetworkControllerImpl.java是作为信号栏数据控制类,继承于BroadcastReceiver,负责监控 wifi, SIM卡状态, service state ,飞行模式等。
6、SignalClusterView.java用来实现界面的刷新显示;



接下来来分析一下当某些状态发生变化时,SystemUI执行的流程,以插入SIM卡为例:

1、当插SIM卡时,android系统会发送TelephonyIntents.ACTION_SIM_STATE_CHANGED广播;
2、NetworkControllerImpl.java继承于BroadcastReceiver,监听某些相应的系统广播;

3、接收到TelephonyIntents.ACTION_SIM_STATE_CHANGED广播后调用NetworkControllerImpl.java的onReceiver()方法,调用updateMobileControllers()方法;

if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
    // Might have different subscriptions now.
    updateMobileControllers();
} 
4、内部调用doUpdateMobileControllers()方法;

private void updateMobileControllers() {
        if (!mListening) {
            return;
        }
        doUpdateMobileControllers();
    }
5、获取当前设备内的sim卡信息,如果返回为空,则将此集合置空处理;如果sim卡的订阅信息没有什么变化,则会进入if()语句然后调用updateNoSims()方法然后return;因为当前分析的是插入sim卡,不会进入此if()语句;
    @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();
    }

调用setCurrentSubscriptions()方法;此方法主要是根据返回的sim卡订阅信息集合来构造MobileSignalController,并用集合Map<Integer, MobileSignalController> mMobileSignalControllers将其存储起来;

    @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 */);
    }
MobileSignalController.java这个类主要是用来对信号强度、运营商、网络类型等以及根据这些状态封装对应Icon的控制器,

    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用来监听信号强度、移动数据链接情况等。当检测到信号强度、移动数据连接情况等发生变化的时候会去调用updateTelephony()方法去更新current state设置网络类型、icon、信号强度等等;然后再去调用notifyListenersIfNecessary()方法去调用notifyListeners()方法,通过CallbackHandler对象去调用SignalClusterView.java内的setMobileDataIndicators()方法完成图标的刷新显示;
2、mapIconSets()用来设置网络类型的Icon map集合;
3、此构造方法执行完毕之后会回到NetworkControllerImpl.java的setCurrentSubscriptions()方法,执行controller.registerListener()语句给每一个MobileSignalController对象注册MobilePhoneStateListener监听;


然后调用mCallbackHandler.setSubs()将sim卡的订阅信息集合传给SignalClusterView.java的setSubs()方法。首先会去清除掉之前的mPhoneStates信息和mMobileSignalGroup view,然后再去调用inflatePhoneState()方法;

    @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();
        }
    }
调用inflatePhoneState()方法重新add state和view;

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

然后回到setSubs()方法调用applyIconTint()方法,来设置一些Icon的色彩;

    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);
        }
    }
继续回到NetworkControllerImpl.java的setCurrentSubscriptions()方法,接下来调用notifyAllListeners()方法来通知mWifiSignalController(wifi)、mEthernetSignalController(以太网)以及所有的mobileSignalController(手机信号)去执行各自的notifyListeners()方法;

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();
    }
主要看MobileSignalController.java的notifyListeners()方法,这个方法主要是用来设置当前sim卡属性的显示Icon图像属性;然后通过CallbackHandler对象去调用SignalClusterView.java内的setMobileDataIndicators()方法;

    @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();
            }
        });
    }
调用SignalClusterView.java内的setMobileDataIndicators()方法完成current PhoneState对象的状态刷新,最后调用apply()方法去完成界面上Icon图标的刷新;
    @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();
    }
可能在上述操作的过程中,网络连接状态发生了变化,所有最后回到NetworkControllerImpl.java类中继续执行pushConnectivityToSignals()方法将当前的网络连接状态推送给所有的SignalControllers对象控制器。


信号栏总结:
1、由PhoneStatusBar.java的makeStatusBarView()方法来加载布局。由于在Android系统中由三处地方会使用信号栏(状态栏、锁屏界面下的状态栏以及下拉通知栏的快捷设置区域),这三个引用处分别是status_bar.xml、keyguard_status_bar.xml、status_bar_expanded_header.xml),实例化三个对象,并在这个方法中为每一个SignalClusterView.java对象绑定两个控制器对象,NetworkControllerImpl.java、SecurityControllerImpl.java;
2、NetworkControllerImpl.java对象主要是负责作为信号栏数据控制类,继承于BroadcastReceiver,负责监控 wifi, SIM卡状态, service state ,飞行模式等。
SecurityControllerImpl.java对象主要是负责作为用户切换时信号栏数据控制类,负责监控用户切换时的网络状态改变回调;
3、NetworkControllerImpl.java通过CallbackHandler.java将它自己和SignalClusterView.java联系起来,中间通过在CallbackHandler.java的对象中调用SignalClusterView.java的方法来实现NetworkControllerImpl.java对SignalClusterView.java控制通信;
另一方面SignalClusterView.java通过直接实现SecurityController.java的接口来完成通信功能,在SecurityControllerImpl.java通过直接回调onStateChanged()方法通知SignalClusterView.java进行相应的操作;
4、NetworkControllerImpl.java是继承于BroadcastReceiver,通过监听系统广播等来监控SIM卡事件变化等。当插入SIM卡时会获取当前SIM卡的订阅信息集合,然后遍历此集合,为订阅信息再设置一个MobileSignalController.java。
5、MobileSignalController.java类则主要是实现PhoneStateListener接口用来监听service state、信号强度、通话状态、移动数据连接状态,设置相应的显示图标。然后将这些状态和图标显示属性通过CallbackHandler.java传递给SignalClusterView.java对象中。
6、SignalClusterView.java通过调用apply()方法和内部类PhoneState的apply()方法来完成最终的界面刷新。

























猜你喜欢

转载自blog.csdn.net/Otaku_627/article/details/53613642