專案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這個類中,如果要自定義修改可以在裡面改