一、SystemUI 之状态上的手机信号显示

 本文主要是讲SystemUI手机信号在状态栏上的加载过程,从结构树和处理逻辑上分析。

一、结构树:

        一、SystemUI 之状态上的手机信号显示_第1张图片

 以上就是整个界面显示的xml加载流程,后面会逐个源码贴出来。

  1. 先看staus_bar.xml

         

        

               加载system_icons.xml

            
        
    

  2.system_icon.xml

     



    

    

    

 这是父类是一个linearLayout  水平布局,从代码中不仅仅加载了信号图标区域(signal_cluster_view)还加载了电量显示图标(BatterMeterView),从现象看到与代码是一致的,电量图标一直在信号图标的右侧。

3.signal_cluster_view.xml


    
    
        
        
    
    
        
        
    
    
        
        
        
    
    
    
    
                       
    
        
        
    
    
    

     这段代码加载了一个自定义的SignalClusterView,SignalClusterView是一个继承LinearLayout的ViewGroup,这个xml布局不仅仅包含了手机信号图标还有wifi以及飞行模式等。有朋友会问,从这个xml文件中我没看到mobile_signal_group_ext.xml的任何信息,那么mobile_signal_group_ext.xml是怎么被添加到手机信号图标树中呢?答案是通过代码的方式加载,在SignalClusterView.java 中有这么一段代码:

     

  public PhoneState(int subId, Context context) {
            ViewGroup root = (ViewGroup) LayoutInflater.from(context)
                    .inflate(R.layout.mobile_signal_group_ext, null);

            /// M: Add data group for plugin feature. @ {
            mPhoneStateExt = OpSystemUICustomizationFactoryBase.getOpFactory(context)
                                .makeSystemUIStatusBar(context);
            mPhoneStateExt.addCustomizedView(subId, context, root);
            /// @ }

            setViews(root);
            mSubId = subId;
        }

4.mobile_signal_group_ext.xml

 


    
    
    

5.mobile_signal_group.xml

  


    
        
        
    
    
        
        
        
        
    

这两个xml布局都比较简单,其中对应的具体图标如下图

   一、SystemUI 之状态上的手机信号显示_第2张图片

至此结构树的分析到此。

二、处理逻辑:

    其实从网上能收到很多资料关于手机信号图标的信息,NetworkControllerImpl.java是手机信号处理逻辑类,这个类继承了BroadcastReceiver.java ,因此手机信号变化是监听一些信号广播来做修改的。之前提到的SignalClusterView.java则是信号显示类。那么这两个类是如何联系在一起的呢?答案是通过NetworkControllerImpl.SignalCallback,NetworkControllerImpl.SignalCallback是一个接口。

  SignalClusterView.java继承NetworkControllerImpl.SignalCallback,并且向NetworkControllerImpl.java注册接口信息,NetworkControllerImpl.java根据信号广播回调NetworkControllerImpl.SignalCallback。


public class SignalClusterView extends LinearLayout implements NetworkControllerImpl.SignalCallback,
        SecurityController.SecurityControllerCallback, Tunable,
        DarkReceiver {
 public void setForceBlockWifi() {
        mForceBlockWifi = true;
        mBlockWifi = true;
        if (isAttachedToWindow()) {
            // Re-register to get new callbacks.
            mNetworkController.removeCallback(this);
            mNetworkController.addCallback(this);
        }
    }

  mNetWorkController  就是NetworkControllerImpl.Java实例,这个实例在SystemUI体系中被统一保存在Dependency.java中,有兴趣的朋友可以自己阅读相关的源码。下图是两者的关系。

   一、SystemUI 之状态上的手机信号显示_第3张图片

  后面我们捋一捋信号变化的逻辑部分,NetworkControllerImpl.java既然是一个BroadcastReceiver,那肯定会涉及到广播的注册和监听。

  1.下面是广播的注册部分,代码比较简单。其中的MobileSignalController 是一个单独对手机信号逻辑处理类。

  

private void registerListeners() {
         Log.e(TAG, "registerListeners-----------------------------");
        for (int i = 0; i < mMobileSignalControllers.size(); i++) {
            MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
			StringBuilder st=new StringBuilder();
			mobileSignalController.mCurrentState.toString(st);
			Log.e(TAG, "registerListeners------- mNetworkNameDefault"+mobileSignalController.mNetworkNameDefault+"  i ="+i+"   st="+st.toString());
            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_AIRPLANE_MODE_CHANGED);
        /// M: Add mtk
        addCustomizedAction(filter);
        mContext.registerReceiver(this, filter, null, mReceiverHandler);
        mListening = true;

        updateMobileControllers();
    }

  2.在NetworkControllerImpl.java中有关手机信号监听部分如下代码,所有有关SIM的监听最终会调用MobileSignalController.Java -->notifyListeners(SignalCallback callback)。但是信号强弱的变化则是由MobileSignalController.Java -->MobilePhoneStateListener的一个接口监听回调实现的,MobilePhoneStateListener通过向TelephonyManager.Java注册,最终还是会调用MobileSignalController.Java -->notifyListeners(SignalCallback callback)来实现信号的显示,相关的代码逻辑自行研究。

  

 public void onReceive(Context context, Intent intent) {
        if (CHATTY) {
            Log.d(TAG, "onReceive: intent=" + intent);
        }
        final String action = intent.getAction();
        if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
                action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
            updateConnectivity();
        } 
				//飞行模式变化
		else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
            refreshLocale();
            updateAirplaneMode(false);
        } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED)) {
            // We are using different subs now, we might be able to make calls.
            recalculateEmergency();
        } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
            // Notify every MobileSignalController so they can know whether they are the
            // data sim or not.
            for (int i = 0; i < mMobileSignalControllers.size(); i++) {
                MobileSignalController controller = mMobileSignalControllers.valueAt(i);
                controller.handleBroadcast(intent);
            }
        } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
            // Might have different subscriptions now.
            updateMobileControllers();
        /// M: Support "subinfo record update". @{
        } else if (action.equals(TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED)) {
            /// M: update plmn label @{
            refreshPlmnCarrierLabel();
            /// @}
            updateMobileControllersEx(intent);
       /// @}
        } else if (action.equals(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED)) {
            mLastServiceState = ServiceState.newFromBundle(intent.getExtras());
            /// M:[ALPS02809725]Always save ecc state not only no sim
            /// M: [ALPS02614114] Check all phone's emergency state when no sims @{
            if (mLastServiceState != null) {
               int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
                     PhoneConstants.SIM_ID_1);
               mEmergencyPhone[phoneId] = mLastServiceState.isEmergencyOnly();
               if (DEBUG) {
                   Log.d(TAG, "Service State changed...phoneId: " + phoneId
                           + " ,isEmergencyOnly: " + mEmergencyPhone[phoneId]);
               }
               if (mMobileSignalControllers.size() == 0) {
                  // If none of the subscriptions are active, we might need to recalculate
                  // emergency state.
                  recalculateEmergency();
               }
               // @}
            }
        }  else if (action.equals(NetworkTypeUtils.LWA_STATE_CHANGE_ACTION)) {
            /// M: Add for 4G+W
            handleLwaAction(intent);
        }
        else {
            int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
                    SubscriptionManager.INVALID_SUBSCRIPTION_ID);
            if (SubscriptionManager.isValidSubscriptionId(subId)) {
                if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
                    mMobileSignalControllers.get(subId).handleBroadcast(intent);
                } else {
                    // Can't find this subscription...  We must be out of date.
                    updateMobileControllers();
                }
            } else {
                // No sub id, must be for the wifi.
                mWifiSignalController.handleBroadcast(intent);
            }
        }
    }
  注释:
网络连接成功:ConnectivityManager.CONNECTIVITY_ACTION) ------- 能够上网
网络变化 ConnectivityManager.INET_CONDITION_ACTION -------- 能够上网
默认SIM变化:TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED -------- 相对于双卡手机,默认数据的SIM变化
默认SIM数据变化:TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED-----相对于双卡手机,默认数据的SIM变化
SIM状态变化:TelephonyIntents.ACTION_SIM_STATE_CHANGED----相对于双卡手机,默认数据的SIM变化
SIM数据变化:TelephonyIntents.ACTION_SUBINFO_RECORD_UPDATED
Phone service 变化:TelephonyIntents.ACTION_SERVICE_STATE_CHANGED
SIM正在打开数据:Telephony.SPN_STRINGS_UPDATED
SIM服务变化:TelephonyIntents.ACTION_SERVICE_STATE_CHANGED ----所有跟SIM相关的变化都会发送这个广播

  3.  MobileSignalController.Java -->notifyListeners(SignalCallback callback)

   

 public void notifyListeners(SignalCallback callback) {
    
        MobileIconGroup icons = getIcons();
       Log.d(mTag, "mCurrentState.inetCondition " + mCurrentState.inetCondition + "mCurrentState.level"
							+ mCurrentState.level);
        String contentDescription = getStringIfExists(getContentDescription());
        String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
        final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
                && mCurrentState.userSetup;


        /// M: Customize the signal strength icon id. @ {
        int iconId = getCurrentIconId();
        iconId = mStatusBarExt.getCustomizeSignalStrengthIcon(
                    mSubscriptionInfo.getSubscriptionId(),
                    iconId,
                    mSignalStrength,
                    mDataNetType,
                    mServiceState);
        /// @ }


        // Show icon in QS when we are connected or data is disabled.
        boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;//modify xiao
        IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
                iconId, contentDescription);




		 Log.d(mTag, "notifyListeners: contentDescription=" + contentDescription+" dataContentDescription=" + dataContentDescription+
		 	" dataDisabled=" + dataDisabled+" iconId=" + iconId+" showDataIcon=" + showDataIcon
		 	+"  mCurrentState.dataSim:"+mCurrentState.dataSim);		
        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;
        showDataIcon &= mCurrentState.isDefault || dataDisabled;
        int typeIcon = showDataIcon ? icons.mDataType : 0;


        /// M: Add for lwa.
        typeIcon = mCurrentState.lwaRegState == NetworkTypeUtils.LWA_STATE_CONNCTED
                && showDataIcon ? NetworkTypeUtils.LWA_ICON : typeIcon;
        /** M: Support [Network Type on StatusBar], change the implement methods.
          * Get the network icon base on service state.
          * Add one more parameter for network type.
          * @ { **/
        int networkIcon = mCurrentState.networkIcon;
        /// M: Support volte icon.Bug fix when airplane mode is on go to hide volte icon
        int volteIcon = mCurrentState.airplaneMode && !isWfcEnable()
                ? 0 : mCurrentState.volteIcon;


        /// M: when data disabled, common show data icon as x, but op do not need show it @ {
        mStatusBarExt.isDataDisabled(mSubscriptionInfo.getSubscriptionId(), dataDisabled);
        /// @ }


        /// M: Customize the data type icon id. @ {
        typeIcon = mStatusBarExt.getDataTypeIcon(
                        mSubscriptionInfo.getSubscriptionId(),
                        typeIcon,
                        mDataNetType,
                        mCurrentState.dataConnected ? TelephonyManager.DATA_CONNECTED :
                            TelephonyManager.DATA_DISCONNECTED,
                        mServiceState);
        /// @ }
        /// M: Customize the network type icon id. @ {
        networkIcon = mStatusBarExt.getNetworkTypeIcon(
                        mSubscriptionInfo.getSubscriptionId(),
                        networkIcon,
                        mDataNetType,
                        mServiceState);
        /// @ }
         //执行更新信号图标。
        callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, networkIcon, volteIcon,
                qsTypeIcon,activityIn, activityOut, dataContentDescription, description,
                 icons.mIsWide, mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);


        /// M: update plmn label @{
        mNetworkController.refreshPlmnCarrierLabel();
        /// @}
    }

1.  typeIcon就是我们之前在分析控制树中有一张图片所显示4G ,networkIcon  3G,qsIcon是三角形图标,最终是调用SignalDrawable,SignalDrawable的主要工作就是根据信号强弱来画三角形图标。 SignalStrength表示信号等级,是通过MobilePhoneStateListener接口得到的。

2.   typeIcon保存和获取会用到一个类TelephonyIcons.java,这个类保存了所有要显示信号类型。MobileSignalController-->mapIconSets() :根据信号类型加载不同的图标,就是我们在有的时候看到是3G,有时候显示的是4G。根据信号类型是如何获取得到的呢?答案是MobilePhoneStateListener 接口中onServiceStateChanged方法有这么一段代码

  

if (state != null) {
                mDataNetType = state.getDataNetworkType();

3. networkIcon  保存和获取会用到一个类NetworkTypeUtils.java,这个类保存了所有要显示的网络类型图标,根据不同的ServiceState 和config来加载对应的网络类型图标。而ServiceState是依据MobilePhoneStateListener接口获取,config是根据SystemUI下面的Config.xml来配置的。NetworkControllerImpl.Java会加载相关的配置。

 public static int getNetworkTypeIcon(ServiceState serviceState, Config config,

4.SignalClusterView.java最终依据callback.setMobileDataIndicators所传递的信息,对不同的View设置VISIBLE和GONE,以及图片的加载。

 public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
             int networkType, int volteIcon, int qsType, boolean activityIn, boolean activityOut,
             String typeContentDescription, String description, boolean isWide, int subId,
              boolean roaming) {
        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;
        /// M: for big network icon and volte icon.
        state.mNetworkIcon = networkType;
        state.mVolteIcon = volteIcon;
        state.mRoaming = roaming;
        state.mActivityIn = activityIn && mActivityEnabled;
        state.mActivityOut = activityOut && mActivityEnabled;

        /// M: Add for plugin features. @ {
        state.mDataActivityIn = activityIn;
        state.mDataActivityOut = activityOut;
        /// @ }
	 Log.d(TAG, "setMobileDataIndicators  description:"+description+"  typeContentDescription="+typeContentDescription);

        apply();
    }




至此手机信号图标的控制加载流程讲述完毕,本文只是讲了大体的流程,其中详情,可以自行阅读。


   

你可能感兴趣的:(#,SystemUI)