關於systemui wifi圖示更新過程分析

MiTiHome發表於2016-10-21
專案systemui沒有wifi圖示,我不知道是在佈局還是程式碼中隱藏了還是沒有接收到wifi更新通知,所以看了下wifi圖示更新的過程,有些東西可能受水平的侷限,分析得不是很到位
首先systemui狀態列的主體在phonestatusbar這個類,在start()中可以看到
mNetworkController = new NetworkController(mContext);
final SignalClusterView signalCluster =(SignalClusterView)mStatusBarView.findViewById(R.id.signal_cluster);
mNetworkController.addSignalCluster(signalCluster);
signalCluster.setNetworkController(mNetworkController);
NetworkController是一個廣播接收者,接收訊號的改變,包括wifi,手機訊號,飛航模式等
而SignalClusterView是一個自定義的佈局,實現了SignalCluster介面,用於顯示訊號圖示,在xml檔案singal_cluster_view中使用,可以看到此佈局下還放了細分的wifi,手機訊號等佈局,
而singal_cluster_view在佈局status_bar中被include,而status_bar又被include在super_status_bar中,而super_status_bar在phonestatusbar中被填充為根佈局
mStatusBarWindow = (StatusBarWindowView) View.inflate(context,R.layout.super_status_bar, null);
    
下面具體說下這2個類,首先NetworkController,我們在其構造方法中可以看到註冊了這些廣播,而且通過context.registerReceiver(this,filter)註冊了自己  
 
public NetworkController(Context context) {
...
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.SPN_STRINGS_UPDATED_ACTION);
        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
        filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        mWimaxSupported = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_wimaxEnabled);
        if(mWimaxSupported) {
            filter.addAction(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION);
            filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
            filter.addAction(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION);
        }
        context.registerReceiver(this, filter);
}
我們來看其方法addSignalCluster
public void addSignalCluster(SignalCluster cluster) {
        mSignalClusters.add(cluster);
        refreshSignalCluster(cluster);
    }
首先mSignalClusters.add(cluster);mSignalClusters是一個集合,SignalCluster是一個介面,把cluster新增到集合以便通過介面的方法通知cluster更新,介面方法如下
public interface SignalCluster {
        void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon,
                String contentDescription);
        void setMobileDataIndicators(boolean visible, int strengthIcon, int activityIcon,
                int typeIcon, String contentDescription, String typeContentDescription);
        void setIsAirplaneMode(boolean is, int airplaneIcon);
    }
我們看setWifiIndicators是把wifi的資訊比如是否可見,圖示,名稱給SignalCluster,而SignalClusterView實現了這個介面
再看refreshSignalCluster(cluster);主要呼叫了setWifiIndicators在新增後初次更新圖示
public void refreshSignalCluster(SignalCluster cluster) {
        cluster.setWifiIndicators(
                // only show wifi in the cluster if connected or if wifi-only
                mWifiEnabled && (mWifiConnected || !mHasMobileDataFeature),
                mWifiIconId,
                mWifiActivityIconId,
                mContentDescriptionWifi);
      ...
    }
初次更新圖示完成後,以後wifi資訊有變化怎麼更新呢,我們看NetworkController的onreceive會接收到廣播
public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        if (action.equals(WifiManager.RSSI_CHANGED_ACTION)
                || action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)
                || action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
            updateWifiState(intent);
            refreshViews();
     }
   }
我們看updateWifiState(intent);
private void updateWifiState(Intent intent) {
        final String action = intent.getAction();
        if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
            mWifiEnabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
                    WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
            final NetworkInfo networkInfo = (NetworkInfo)
                    intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
            boolean wasConnected = mWifiConnected;
            mWifiConnected = networkInfo != null && networkInfo.isConnected();
            // If we just connected, grab the inintial signal strength and ssid
            if (mWifiConnected && !wasConnected) {
                // try getting it out of the intent first
                WifiInfo info = (WifiInfo) intent.getParcelableExtra(WifiManager.EXTRA_WIFI_INFO);
                if (info == null) {
                    info = mWifiManager.getConnectionInfo();
                }
                if (info != null) {
                    mWifiSsid = huntForSsid(info);
                } else {
                    mWifiSsid = null;
                }
            } else if (!mWifiConnected) {
                mWifiSsid = null;
            }
        } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
            mWifiRssi = intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200);
            mWifiLevel = WifiManager.calculateSignalLevel(
                    mWifiRssi, WifiIcons.WIFI_LEVEL_COUNT);
        }
        updateWifiIcons();
    }
這裡主要把廣播的資料拿出來,比如wifi是否可用,是否連線,訊號強度等,拿到資料後呼叫了updateWifiIcons()
private void updateWifiIcons() {
        if (mWifiConnected) {
            mWifiIconId = WifiIcons.WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
            mQSWifiIconId = WifiIcons.QS_WIFI_SIGNAL_STRENGTH[mInetCondition][mWifiLevel];
            mContentDescriptionWifi = mContext.getString(
                    AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH[mWifiLevel]);
        } else {
            if (mDataAndWifiStacked) {
                mWifiIconId = 0;
                mQSWifiIconId = 0;
            } else {
                mWifiIconId = mWifiEnabled ? R.drawable.stat_sys_wifi_signal_null : 0;
                mQSWifiIconId = mWifiEnabled ? R.drawable.ic_qs_wifi_no_network : 0;
            }
            mContentDescriptionWifi = mContext.getString(R.string.accessibility_no_wifi);
        }
    }
這裡主要是根據這些資料匹配對應的圖示id以及wifi描述(有無連線,強度如何),其中mQSWifiIconId是給下拉欄用的,我們回到廣播接收,在updateWifiState(intent)後還有refreshViews();
在這個方法裡主要把匹配好的圖示id以及wifi描述通過refreshSignalCluster(cluster)設定給cluster,這樣我們就完成了wifi資訊的初始新增和動態更新
 void refreshViews() {
 ...
 for (SignalCluster cluster : mSignalClusters) {
                refreshSignalCluster(cluster);
            }
 }
前面說了這麼多都是對NetworkController,說白了它只是把接收到的資訊轉化成圖示id以及和名稱描述等一起通過refreshSignalCluster扔給cluster就完事了,
那我們再來說一下cluster,也就是我們在phonestatusbar裡新增進來的SignalClusterView
看一下在phonestatusbar用到的setNetworkController方法
public void setNetworkController(NetworkController nc) {
        if (DEBUG) Slog.d(TAG, "NetworkController=" + nc);
        mNC = nc;
    }
其實只是讓他和NetworkController建立聯絡,持有其例項,並沒有在其他地方用到,因為SignalClusterView是一個自定義LinearLayout,看一下其初始化
protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mWifiGroup      = (ViewGroup) findViewById(R.id.wifi_combo);
        mWifi           = (ImageView) findViewById(R.id.wifi_signal);
        mWifiActivity   = (ImageView) findViewById(R.id.wifi_inout);
        mMobileGroup    = (ViewGroup) findViewById(R.id.mobile_combo);
        mMobile         = (ImageView) findViewById(R.id.mobile_signal);
        mMobileActivity = (ImageView) findViewById(R.id.mobile_inout);
        mMobileType     = (ImageView) findViewById(R.id.mobile_type);
        mSpacer         =             findViewById(R.id.spacer);
        mAirplane       = (ImageView) findViewById(R.id.airplane);
        apply();
    }
 
我們前面說了在SignalClusterView應用的佈局下還有一些子佈局,比如wifi,手機訊號,飛航模式,這裡就是初始化這些佈局,我們看初始化之後呼叫的apply方法
 
private void apply() {
        if (mWifiGroup == null) return;
        if (mWifiVisible) {
            mWifiGroup.setVisibility(View.VISIBLE);
            mWifi.setImageResource(mWifiStrengthId);
            mWifiActivity.setImageResource(mWifiActivityId);
            mWifiGroup.setContentDescription(mWifiDescription);
        } else {
            mWifiGroup.setVisibility(View.GONE);
        }
        ...
    }
這裡是把wifi是否可見,圖示id,描述等資訊設定給其子佈局,那這些資訊哪來的呢
public void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon,
            String contentDescription) {
        mWifiVisible = visible;
        mWifiStrengthId = strengthIcon;
        mWifiActivityId = activityIcon;
        mWifiDescription = contentDescription;
        apply();
    }
是通過setWifiIndicators拿到的,而setWifiIndicators是在NetworkController的refreshSignalCluster裡呼叫的,所以NetworkController和SignalClusterView結合完成了wifi圖示的更新
另外,所有wifi圖示的id在WifiIcons這個類中,如果要自定義修改可以在裡面改
 
 
 

相關文章