今天我們來(lái)講講大家比較熟悉的狀態(tài)欄wifi icon和數(shù)據(jù)icon顯示邏輯。
一般在正常使用情況下,當(dāng)手機(jī)連接wifi的時(shí)候,狀態(tài)欄就會(huì)顯示wifi icon,而當(dāng)wifi斷開(kāi)的時(shí)候,狀態(tài)欄就會(huì)顯示4G 3G等等的數(shù)據(jù)icon。那么顯示wifi或者4G的依據(jù)是什么呢?手機(jī)在某些網(wǎng)絡(luò)狀態(tài)下,會(huì)不會(huì)有wifi和4G icon同時(shí)顯示的現(xiàn)象呢?下面我們就帶著這個(gè)疑問(wèn),去了解下wifi和4G icon顯示的邏輯。
- 首先我們看下wifi的顯示邏輯
@Override
public void notifyListeners(SignalCallback callback) {
// only show wifi in the cluster if connected or if wifi-only
boolean wifiVisible = mCurrentState.enabled
&& (mCurrentState.connected || !mHasMobileData);
String wifiDesc = wifiVisible ? mCurrentState.ssid : null;
boolean ssidPresent = wifiVisible && mCurrentState.ssid != null;
String contentDescription = getStringIfExists(getContentDescription());
if (mCurrentState.inetCondition == 0) {
contentDescription +=
("," + mContext.getString(R.string.accessibility_quick_settings_no_internet));
}
IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
在WifiSignalController中wifiVisible控制著wifi的visibility,而wifiVisible主要是受mCurrentState.enabled和mCurrentState.connected影響(mHasMobileData這個(gè)值可以忽略,這個(gè)值代表是否支持?jǐn)?shù)據(jù)網(wǎng)絡(luò),顯然手機(jī)項(xiàng)目這個(gè)值始終是true)
public void handleBroadcast(Intent intent) {
String action = intent.getAction();
if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN);
enabled = state == WifiManager.WIFI_STATE_ENABLED;
Log.d("SIGNALICON", TAG + ",handleBroadcast,WIFI_STATE,state = " + state + ",enabled = " + enabled);
} else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
final NetworkInfo networkInfo = (NetworkInfo)
intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
connecting = networkInfo != null && !networkInfo.isConnected()
&& networkInfo.isConnectedOrConnecting();
connected = networkInfo != null && networkInfo.isConnected();
Log.d("SIGNALICON", TAG + ",handleBroadcast,NETWORK_STATE,connecting = " + connecting + ",connected = " + connected);
.........................
.........................
.........................
如上就是在WifiStatusTracker中通過(guò)廣播消息取到的wifi的狀態(tài),到這里wifi的顯示就講完了,邏輯還是很簡(jiǎn)單清晰的
- 下面我們就需要重點(diǎn)關(guān)注下數(shù)據(jù)icon的顯示邏輯了
final boolean dataDisabled = (mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED)
&& mCurrentState.userSetup;
boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
Log.d("SIGNALICON", mTag + ",notifyListeners======dataDisabled = " + dataDisabled
+ ",dataConnected = " + mCurrentState.dataConnected + ",showDataIcon= " + showDataIcon);
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;
showDataIcon &= mCurrentState.isDefault || dataDisabled;
Log.d("SIGNALICON", mTag + ",notifyListeners,dataDisabled = " + dataDisabled
+ ",isDefault = " + mCurrentState.isDefault + ",showDataIcon= " + showDataIcon);
Log.d("SIGNALICON", mTag + ",notifyListeners,showDataIcon= " + showDataIcon + ",mStyle = " + mStyle);
int typeIcon = (showDataIcon && mStyle == STATUS_BAR_STYLE_ANDROID_DEFAULT) ? icons.mDataType : 0;
int dataActivityId = showDataIcon && !showMobileActivity() ? icons.mActivityId : 0;
callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
activityIn, activityOut, dataActivityId,
icons.mStackedDataIcon, icons.mStackedVoiceIcon,
dataContentDescription, description, icons.mIsWide,
mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming,
networkIcon, volteIcon, showDataIcon);
如上,在MobileSignalController中,就是核心的數(shù)據(jù)icon的顯示,其中我們關(guān)注的是typeIcon,這個(gè)icon就是顯示的4G,3G icon,所以我們?cè)敿?xì)分析下typeIcon 的邏輯
int typeIcon = (showDataIcon && mStyle == STATUS_BAR_STYLE_ANDROID_DEFAULT) ? icons.mDataType : 0;
從這里我們可以清晰的看到,typeIcon 是受showDataIcon的控制
boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
showDataIcon &= mCurrentState.isDefault || dataDisabled;
可以看到showDataIcon主要有兩處進(jìn)行了賦值,那么這兩次賦值分別代表了什么不同的意義呢?我們接著往下看
在updateTelephony()函數(shù)中
if (mNetworkToIconLookup.indexOfKey(mDataNetType) >= 0) {
mCurrentState.iconGroup = mNetworkToIconLookup.get(mDataNetType);
} else {
mCurrentState.iconGroup = mDefaultIcons;
}
mCurrentState.dataConnected = mCurrentState.connected
&& mDataState == TelephonyManager.DATA_CONNECTED;
Log.d("SIGNALICON", mTag + ",updateTelephony,connected = " + mCurrentState.connected
+ ", mDataState = " + mDataState + ",dataConnected = " + mCurrentState.dataConnected);
mCurrentState.roaming = isRoaming();
if (isCarrierNetworkChangeActive()) {
mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
} else if (isDataDisabled()) {
mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
}
找到了mCurrentState.dataConnected和mCurrentState.iconGroup賦值的地方,我們主要關(guān)注mDataState 即可。
在class MobilePhoneStateListener extends PhoneStateListener {}中我們找到了mDataState 的出處
@Override
public void onDataConnectionStateChanged(int state, int networkType) {
mDataState = state;
mDataNetType = networkType;
Log.d("SIGNALICON", mTag + ",onDataConnectionStateChanged,state = " + state
+ ", networkType = " + networkType);
if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
mServiceState.isUsingCarrierAggregation()) {
mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
}
updateTelephony();
}
可見(jiàn)mDataState 是從PhoneStateListener callback中上報(bào)的,該值主要對(duì)應(yīng)了不同的連接狀態(tài),可以看下framework定義。TelephonyManager.java中
** Data connection state: Unknown. Used before we know the state.
* @hide
*/
public static final int DATA_UNKNOWN = -1;
/** Data connection state: Disconnected. IP traffic not available. */
public static final int DATA_DISCONNECTED = 0;
/** Data connection state: Currently setting up a data connection. */
public static final int DATA_CONNECTING = 1;
/** Data connection state: Connected. IP traffic should be available. */
public static final int DATA_CONNECTED = 2;
/** Data connection state: Suspended. The connection is up, but IP
* traffic is temporarily unavailable. For example, in a 2G network,
* data activity may be suspended when a voice call arrives. */
public static final int DATA_SUSPENDED = 3;
實(shí)際上這個(gè)callback就是用戶(hù)主動(dòng)開(kāi)啟和關(guān)閉數(shù)據(jù)業(yè)務(wù)的時(shí)候,framework上報(bào)的流程,我順帶加了點(diǎn)log有助于邏輯分析,下面我們就分幾種情況看下對(duì)應(yīng)的log
- 開(kāi)啟數(shù)據(jù)業(yè)務(wù)
09-11 16:38:45.477 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),onDataConnectionStateChanged,state = 2, networkType = 13
09-11 16:38:45.509 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),updateTelephony,connected = true, mDataState = 2,dataConnected = true
09-11 16:38:45.517 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:38:45.518 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = false,showDataIcon= false
09-11 16:38:45.519 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,showDataIcon= false,mStyle = 0
09-11 16:38:45.529 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),updateTelephony,connected = true, mDataState = 2,dataConnected = true
09-11 16:38:45.572 1524 1755 D SIGNALICON: NetworkController,updateConnectivity update transportType
09-11 16:38:45.574 1524 1755 D SIGNALICON: NetworkController,updateConnectivity======transportType = 0
09-11 16:38:45.575 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:38:45.576 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = true,showDataIcon= true
09-11 16:38:45.576 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,showDataIcon= true,mStyle = 0
當(dāng)主動(dòng)開(kāi)啟數(shù)據(jù)業(yè)務(wù)的時(shí)候,callback上報(bào)了state = 2, networkType = 13狀態(tài),state代表數(shù)據(jù)連接狀態(tài)而networkType 則代表當(dāng)前的網(wǎng)絡(luò)類(lèi)型(3G和4G等等),緊接著updateTelephony函數(shù)中會(huì)根據(jù)state設(shè)置mCurrentState.dataConnected狀態(tài),最后在notifyListeners根據(jù)mCurrentState.dataConnected的狀態(tài)設(shè)置了showDataIcon的值
- 關(guān)閉數(shù)據(jù)業(yè)務(wù)
09-11 16:40:32.840 1524 1755 D SIGNALICON: NetworkController,updateConnectivity update transportType
09-11 16:40:32.843 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:40:32.843 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = false,showDataIcon= false
09-11 16:40:32.843 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,showDataIcon= false,mStyle = 0
09-11 16:40:32.943 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),updateTelephony,connected = true, mDataState = 2,dataConnected = true
09-11 16:40:33.172 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),onDataConnectionStateChanged,state = 0, networkType = 13
09-11 16:40:33.181 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),updateTelephony,connected = true, mDataState = 0,dataConnected = false
09-11 16:40:33.185 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = false,showDataIcon= false
09-11 16:40:33.185 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = false,showDataIcon= false
09-11 16:40:33.185 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,showDataIcon= false,mStyle = 0
09-11 16:40:36.461 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),updateTelephony,connected = true, mDataState = 0,dataConnected = false
關(guān)閉數(shù)據(jù)業(yè)務(wù)的流程,大致和開(kāi)啟式一致的,只是中間的狀態(tài)是相反的
以上就是我們第二點(diǎn)要講的,數(shù)據(jù)業(yè)務(wù)開(kāi)關(guān)的流程,說(shuō)白了狀態(tài)欄就是依據(jù)onDataConnectionStateChanged callback來(lái)刷新UI,邏輯也是比較清晰明了的。
細(xì)心的你可能就會(huì)發(fā)現(xiàn),showDataIcon 不是有兩處賦值的地方嗎?
boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
showDataIcon &= mCurrentState.isDefault || dataDisabled;
onDataConnectionStateChanged callback 只與第一次的賦值有關(guān)聯(lián),那第二次的賦值又與什么有關(guān)聯(lián)呢?
下面就是我們要重點(diǎn)講的第三點(diǎn),我們來(lái)看看第二個(gè)賦值中的mCurrentState.isDefault是何方神圣,
這也是寫(xiě)本文的最終用意。
- 數(shù)據(jù)業(yè)務(wù)的被動(dòng)刷新
你有否想過(guò),在數(shù)據(jù)業(yè)務(wù)開(kāi)啟的情況下,手機(jī)又連接了wifi,這時(shí)狀態(tài)欄顯示了wifi icon而4G icon是怎么消失的呢?
首先我們看下wifi開(kāi)啟和關(guān)閉的log
- wifi開(kāi)啟
09-11 16:42:34.264 1524 1755 D SIGNALICON: WifiStatusTracker,handleBroadcast,WIFI_STATE,state = 2, enabled = false
09-11 16:42:34.278 1524 1755 D SIGNALICON: WifiStatusTracker,handleBroadcast,WIFI_STATE,state = 3, enabled = true
09-11 16:42:37.596 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:42:37.596 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = true,showDataIcon= true
09-11 16:42:37.596 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,showDataIcon= true,mStyle = 0
09-11 16:42:39.608 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:42:39.609 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = true,showDataIcon= true
09-11 16:42:39.609 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,showDataIcon= true,mStyle = 0
09-11 16:42:56.984 1524 1755 D SIGNALICON: WifiStatusTracker,handleBroadcast,NETWORK_STATE,connected = true
09-11 16:42:57.096 1524 1755 D SIGNALICON: NetworkController,updateConnectivity update transportType
09-11 16:42:57.097 1524 1755 D SIGNALICON: NetworkController,updateConnectivity======transportType = 1
09-11 16:42:57.101 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:42:57.101 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = false,showDataIcon= false
09-11 16:42:57.101 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,showDataIcon= false,mStyle = 0
- wifi關(guān)閉
09-11 16:44:26.877 1524 1755 D SIGNALICON: WifiStatusTracker,handleBroadcast------>NETWORK_STATE,connected = false
09-11 16:44:26.913 1524 1755 D SIGNALICON: NetworkController,updateConnectivity update transportType
09-11 16:44:26.974 1524 1755 D SIGNALICON: WifiStatusTracker,handleBroadcast------>WIFI_STATE,state = 0, enabled = false
09-11 16:44:27.007 1524 1755 D SIGNALICON: NetworkController,updateConnectivity update transportType
09-11 16:44:27.010 1524 1755 D SIGNALICON: NetworkController,updateConnectivity======transportType = 0
09-11 16:44:27.012 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:44:27.012 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = true,showDataIcon= true
09-11 16:44:27.012 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,showDataIcon= true,mStyle = 0
09-11 16:44:27.622 1524 1755 D SIGNALICON: WifiStatusTracker,handleBroadcast------>WIFI_STATE,state = 1, enabled = false
09-11 16:44:28.265 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:44:28.266 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = true,showDataIcon= true
09-11 16:44:28.266 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,showDataIcon= true,mStyle = 0
我們截取log其中一段看下
wifi 開(kāi)啟
09-11 16:42:56.984 1524 1755 D SIGNALICON: WifiStatusTracker,handleBroadcast,NETWORK_STATE,connected = true
NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:42:57.101 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = false,showDataIcon= false
wifi 關(guān)閉
09-11 16:44:26.974 1524 1755 D SIGNALICON: WifiStatusTracker,handleBroadcast------>WIFI_STATE,state = 0, enabled = false
NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:44:27.012 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = true,showDataIcon= true
09-11 16:44:27.012 1524 1755 D SIGNALICON:
在wifi開(kāi)啟或者關(guān)閉的時(shí)候,showDataIcon第一次賦值的地方始終是true,這也是正常的,因?yàn)閿?shù)據(jù)業(yè)務(wù)本來(lái)就是開(kāi)著的,而且onDataConnectionStateChanged callback也沒(méi)有上報(bào)刷新,然后到了第二次showDataIcon賦值的時(shí)候卻出現(xiàn)變化了
showDataIcon &= mCurrentState.isDefault || dataDisabled;
邏輯里面是這么定義的,log里面也能看到,mCurrentState.isDefault導(dǎo)致了最后showDataIcon發(fā)生了變化。我們接著往下看
@Override
public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
boolean isValidated = validatedTransports.get(mTransportType);
mCurrentState.isDefault = connectedTransports.get(mTransportType);
// Only show this as not having connectivity if we are default.
mCurrentState.inetCondition = (isValidated || !mCurrentState.isDefault) ? 1 : 0;
notifyListenersIfNecessary();
}
還是在MobileSignalController中,我們找到了mCurrentState.isDefault的出處,看過(guò)我上一篇狀態(tài)欄信號(hào)分析的同學(xué)
SystemUI狀態(tài)欄wifi和sim icon顯示"x"號(hào)或者"!"號(hào)現(xiàn)象分析
對(duì)這個(gè)函數(shù)一定很清楚了,有興趣的可以再看下熟悉這之間的流程,那么我們長(zhǎng)話(huà)短說(shuō)。
在NetworkControllerImpl中,當(dāng)接收到ConnectivityManager.CONNECTIVITY_ACTION或者ConnectivityManager.INET_CONDITION_ACTION廣播的時(shí)候,觸發(fā)了updateConnectivity的刷新
/**
* Update the Inet conditions and what network we are connected to.
*/
private void updateConnectivity() {
mConnectedTransports.clear();
mValidatedTransports.clear();
Log.d("SIGNALICON", TAG + ",updateConnectivity update transportType");
for (NetworkCapabilities nc :
mConnectivityManager.getDefaultNetworkCapabilitiesForUser(mCurrentUserId)) {
for (int transportType : nc.getTransportTypes()) {
Log.d("SIGNALICON", TAG + ",updateConnectivity======transportType = " + transportType);
mConnectedTransports.set(transportType);
if (nc.hasCapability(NET_CAPABILITY_VALIDATED)) {
mValidatedTransports.set(transportType);
}
}
}
if (CHATTY) {
Log.d(TAG, "updateConnectivity: mConnectedTransports=" + mConnectedTransports);
Log.d(TAG, "updateConnectivity: mValidatedTransports=" + mValidatedTransports);
}
mInetCondition = !mValidatedTransports.isEmpty();
pushConnectivityToSignals();
}
/**
* Pushes the current connectivity state to all SignalControllers.
*/
private void pushConnectivityToSignals() {
// We want to update all the icons, all at once, for any condition change
for (int i = 0; i < mMobileSignalControllers.size(); i++) {
MobileSignalController mobileSignalController = mMobileSignalControllers.valueAt(i);
mobileSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
}
mWifiSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
mEthernetSignalController.updateConnectivity(mConnectedTransports, mValidatedTransports);
}
到這里我們就找到了mCurrentState.isDefault = connectedTransports.get(mTransportType)實(shí)現(xiàn)的邏輯,就是在收到信號(hào)刷新廣播消息的時(shí)候,通過(guò)NetworkCapabilities中獲取了transportType,而MobileSignalController在初始化的時(shí)候就傳入了需要的數(shù)據(jù)類(lèi)型NetworkCapabilities.TRANSPORT_CELLULAR
public MobileSignalController(Context context, Config config, boolean hasMobileData,
TelephonyManager phone, CallbackHandler callbackHandler,
NetworkControllerImpl networkController, SubscriptionInfo info,
SubscriptionDefaults defaults, Looper receiverLooper) {
super("MobileSignalController(" + info.getSubscriptionId() + "_" + info.getSimSlotIndex() + ")", context,
NetworkCapabilities.TRANSPORT_CELLULAR, callbackHandler,
networkController);
................
................
SignalController對(duì)mTransportType進(jìn)行了賦值
public SignalController(String tag, Context context, int type, CallbackHandler callbackHandler,
NetworkControllerImpl networkController) {
mTag = TAG + "." + tag;
mNetworkController = networkController;
mTransportType = type;
...........
...........
NetworkCapabilities中定義了信號(hào)類(lèi)型的值:
/**
* Representing the transport type. Apps should generally not care about transport. A
* request for a fast internet connection could be satisfied by a number of different
* transports. If any are specified here it will be satisfied a Network that matches
* any of them. If a caller doesn't care about the transport it should not specify any.
*/
private long mTransportTypes;
/**
* Indicates this network uses a Cellular transport.
*/
public static final int TRANSPORT_CELLULAR = 0;
/**
* Indicates this network uses a Wi-Fi transport.
*/
public static final int TRANSPORT_WIFI = 1;
/**
* Indicates this network uses a Bluetooth transport.
*/
public static final int TRANSPORT_BLUETOOTH = 2;
我們?cè)俳Y(jié)合log確認(rèn)下:
wifi 開(kāi)啟
09-11 16:42:56.984 1524 1755 D SIGNALICON: WifiStatusTracker,handleBroadcast,NETWORK_STATE,connected = true
09-11 16:42:57.096 1524 1755 D SIGNALICON: NetworkController,updateConnectivity update transportType
09-11 16:42:57.097 1524 1755 D SIGNALICON: NetworkController,updateConnectivity======transportType = 1
09-11 16:42:57.101 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:42:57.101 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = false,showDataIcon= false
wifi 關(guān)閉
09-11 16:44:26.877 1524 1755 D SIGNALICON: WifiStatusTracker,handleBroadcast------>NETWORK_STATE,connected = false
09-11 16:44:26.913 1524 1755 D SIGNALICON: NetworkController,updateConnectivity update transportType
09-11 16:44:26.974 1524 1755 D SIGNALICON: WifiStatusTracker,handleBroadcast------>WIFI_STATE,state = 0, enabled = false
09-11 16:44:27.007 1524 1755 D SIGNALICON: NetworkController,updateConnectivity update transportType
09-11 16:44:27.010 1524 1755 D SIGNALICON: NetworkController,updateConnectivity======transportType = 0
09-11 16:44:27.012 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners======dataDisabled = false,dataConnected = true,showDataIcon= true
09-11 16:44:27.012 1524 1755 D SIGNALICON: NetworkController.MobileSignalController(2_1),notifyListeners,dataDisabled = false,isDefault = true,showDataIcon= true
在wifi連接的時(shí)候上報(bào)了transportType = 1,導(dǎo)致isDefault = false;而wifi斷開(kāi),數(shù)據(jù)連接上時(shí),上報(bào)了transportType = 0,導(dǎo)致isDefault = true,log和我們的分析過(guò)程是完全吻合的。
以上systemui模塊刷新wifi和數(shù)據(jù)icon的分析就完結(jié)了,總結(jié)下:
- 當(dāng)wifi和數(shù)據(jù)連接同時(shí)打開(kāi),wifi連接的時(shí)候,framework會(huì)通過(guò)ConnectivityManager.CONNECTIVITY_ACTION或者ConnectivityManager.INET_CONDITION_ACTION廣播,觸發(fā)了updateConnectivity的刷新,然后取到了transportType = 1,從而isDefault = false,MobileSignalController中showDataIcon = fase,數(shù)據(jù)icon就隱藏了
- 當(dāng)wifi和數(shù)據(jù)連接同時(shí)打開(kāi),wifi斷開(kāi),數(shù)據(jù)連接的時(shí)候,framework會(huì)也通過(guò)ConnectivityManager.CONNECTIVITY_ACTION或者ConnectivityManager.INET_CONDITION_ACTION廣播,觸發(fā)了updateConnectivity的刷新,然后取到了transportType = 0,從而isDefault = true,MobileSignalController中showDataIcon = true,數(shù)據(jù)icon就顯示了。
項(xiàng)目開(kāi)發(fā)中有時(shí)候也會(huì)遇到wifi連接上了,wifi和4G同時(shí)顯示的現(xiàn)象
通過(guò)上面的分析,我們也就比較容易定位問(wèn)題了,加點(diǎn)log確認(rèn)下,當(dāng)時(shí)wifi connected = true的時(shí)候,updateConnectivity是不是也取到了transportType = 0的狀態(tài),從項(xiàng)目經(jīng)驗(yàn)中看90%是因?yàn)檫@個(gè)原因,貌似Android有這樣一個(gè)機(jī)制,當(dāng)wifi信號(hào)很微弱的時(shí)候,會(huì)自動(dòng)切換到數(shù)據(jù)流量,以免影響用戶(hù)體驗(yàn)。此時(shí)就需要framework協(xié)助進(jìn)一步確認(rèn)了
如果想進(jìn)階了解下framework上報(bào)的流程,各位看官可以跟著往下走;當(dāng)然如果覺(jué)得比較枯燥乏味,可以拿好貴重物品歡快的離場(chǎng)了。
- framework更新wifi和數(shù)據(jù)信號(hào)的流程
既然wifi和數(shù)據(jù)顯示的邏輯是受NetworkCapabilities 中的 TRANSPORT_CELLULAR和TRANSPORT_WIFI影響,而獲取這個(gè)狀態(tài)的入口是updateConnectivity函數(shù)
/**
* Update the Inet conditions and what network we are connected to.
*/
private void updateConnectivity() {
mConnectedTransports.clear();
mValidatedTransports.clear();
for (NetworkCapabilities nc :
mConnectivityManager.getDefaultNetworkCapabilitiesForUser(mCurrentUserId)) {
for (int transportType : nc.getTransportTypes()) {
mConnectedTransports.set(transportType);
.....................................
那我們就從getDefaultNetworkCapabilitiesForUser和getTransportTypes它們?nèi)胧?/p>
在ConnectivityService中我們找到了getDefaultNetworkCapabilitiesForUser的實(shí)現(xiàn)
@Override
public NetworkCapabilities[] getDefaultNetworkCapabilitiesForUser(int userId) {
// The basic principle is: if an app's traffic could possibly go over a
// network, without the app doing anything multinetwork-specific,
// (hence, by "default"), then include that network's capabilities in
// the array.
//
// In the normal case, app traffic only goes over the system's default
// network connection, so that's the only network returned.
//
// With a VPN in force, some app traffic may go into the VPN, and thus
// over whatever underlying networks the VPN specifies, while other app
// traffic may go over the system default network (e.g.: a split-tunnel
// VPN, or an app disallowed by the VPN), so the set of networks
// returned includes the VPN's underlying networks and the system
// default.
enforceAccessPermission();
HashMap<Network, NetworkCapabilities> result = new HashMap<Network, NetworkCapabilities>();
NetworkAgentInfo nai = getDefaultNetwork();
NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
if (nc != null) {
result.put(nai.network, nc);
}
....................
這個(gè)函數(shù)中NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai)就是從NetworkAgentInfo把信息取出來(lái),最終給NetworkCapabilities設(shè)置mTransportTypes的地方
private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) {
if (nai != null) {
synchronized (nai) {
if (nai.networkCapabilities != null) {
return new NetworkCapabilities(nai.networkCapabilities);
}
}
}
return null;
}
我們看NetworkCapabilities類(lèi)中的以下兩個(gè)函數(shù)
public NetworkCapabilities(NetworkCapabilities nc) {
if (nc != null) {
mNetworkCapabilities = nc.mNetworkCapabilities;
mTransportTypes = nc.mTransportTypes;
mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
mNetworkSpecifier = nc.mNetworkSpecifier;
mSignalStrength = nc.mSignalStrength;
}
}
/**
* Gets all the transports set on this {@code NetworkCapability} instance.
*
* @return an array of {@code NetworkCapabilities.TRANSPORT_*} values
* for this instance.
* @hide
*/
public int[] getTransportTypes() {
return BitUtils.unpackBits(mTransportTypes);
}
好了到這里,我們就找到了getTransportTypes的實(shí)現(xiàn)
下面就主要關(guān)注ConnectivityService類(lèi)中g(shù)etDefaultNetworkCapabilitiesForUser函數(shù)是如何取到getDefaultNetwork()數(shù)據(jù)的的,因?yàn)楹竺娴倪壿嫸际菑倪@個(gè)函數(shù)中取數(shù)據(jù)的
private NetworkAgentInfo getDefaultNetwork() {
return getNetworkForRequest(mDefaultRequest.requestId);
}
private NetworkAgentInfo getNetworkForRequest(int requestId) {
synchronized (mNetworkForRequestId) {
return mNetworkForRequestId.get(requestId);
}
}
private void setNetworkForRequest(int requestId, NetworkAgentInfo nai) {
synchronized (mNetworkForRequestId) {
mNetworkForRequestId.put(requestId, nai);
}
}
/**
* NetworkAgentInfo supporting a request by requestId.
* These have already been vetted (their Capabilities satisfy the request)
* and the are the highest scored network available.
* the are keyed off the Requests requestId.
*/
// NOTE: Accessed on multiple threads, must be synchronized on itself.
@GuardedBy("mNetworkForRequestId")
private final SparseArray<NetworkAgentInfo> mNetworkForRequestId =
new SparseArray<NetworkAgentInfo>();
在上面的函數(shù)中我們找到了mNetworkForRequestId就是一個(gè)SparseArray,setNetworkForRequest給mNetworkForRequestId賦值,getNetworkForRequest負(fù)責(zé)取值。
- 信號(hào)類(lèi)型的初始化
下面我們關(guān)注setNetworkForRequest函數(shù)是哪里調(diào)用,然后往里面?zhèn)髦档?我們就能夠找到出處了
private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork,
ReapUnvalidatedNetworks reapUnvalidatedNetworks, long now) {
.................
newNetwork.unlingerRequest(nri.request);
setNetworkForRequest(nri.request.requestId, newNetwork);
if (!newNetwork.addRequest(nri.request)) {
Slog.wtf(TAG, "BUG: " + newNetwork.name() + " already has " + nri.request);
}
addedRequests.add(nri);
.................
}
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
................
updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
// Consider network even though it is not yet validated.
final long now = SystemClock.elapsedRealtime();
rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now);
// This has to happen after matching the requests, because callbacks are just requests.
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
.................
}
我們看到在updateNetworkInfo中設(shè)置了最終的NetworkCapabilities,接著往下看
private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
if (VDBG) log("Got NetworkAgent Messenger");
mNetworkAgentInfos.put(na.messenger, na);
synchronized (mNetworkForNetId) {
mNetworkForNetId.put(na.network.netId, na);
}
na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
NetworkInfo networkInfo = na.networkInfo;
na.networkInfo = null;
updateNetworkInfo(na, networkInfo);
}
private class InternalHandler extends Handler {
public InternalHandler(Looper looper) {
super(looper);
}
case EVENT_REGISTER_NETWORK_AGENT: {
handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
break;
}
public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkMisc networkMisc) {
enforceConnectivityInternalPermission();
LinkProperties lp = new LinkProperties(linkProperties);
lp.ensureDirectlyConnectedRoutes();
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
// satisfies mDefaultRequest.
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(reserveNetId()), new NetworkInfo(networkInfo), lp,
new NetworkCapabilities(networkCapabilities), currentScore,
mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
synchronized (this) {
nai.networkMonitor.systemReady = mSystemReady;
}
addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network,
networkInfo.getExtraInfo());
if (DBG) log("registerNetworkAgent " + nai);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
return nai.network.netId;
}
在registerNetworkAgent中完成了updateNetworkInfo的設(shè)置,仿佛離答案越來(lái)越近了有木有,那么這個(gè)函數(shù)是怎么設(shè)置的呢
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
super(looper);
LOG_TAG = logTag;
mContext = context;
if (ni == null || nc == null || lp == null) {
throw new IllegalArgumentException();
}
if (VDBG) log("Registering NetworkAgent");
ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
}
在NetworkAgent.java中我們找到了答案,就是在NetworkAgent初始化的時(shí)候注冊(cè)的。我們看下NetworkAgent的注釋
/**
* A Utility class for handling for communicating between bearer-specific
* code and ConnectivityService.
*
* A bearer may have more than one NetworkAgent if it can simultaneously
* support separate networks (IMS / Internet / MMS Apns on cellular, or
* perhaps connections with different SSID or P2P for Wi-Fi).
*
* @hide
*/
public abstract class NetworkAgent extends Handler {}
英文大意就是:
用于處理bearer-specific code 和 ConnectivityService通信的實(shí)用類(lèi),如果這個(gè)bearer可以承載多個(gè)網(wǎng)絡(luò)的話(huà),那它就會(huì)有多個(gè)NetworkAgent,比如 (IMS / Internet / MMS Apns on cellular, or perhaps connections with different SSID or P2P for Wi-Fi)
到這里我們就能夠大概猜到了,每個(gè)網(wǎng)絡(luò)類(lèi)型應(yīng)該就對(duì)應(yīng)著一個(gè)NetworkAgent,是不是醬紫呢?我們接著往下找
private class WifiNetworkAgent extends NetworkAgent {
public WifiNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
super(l, c, TAG, ni, nc, lp, score, misc);
}
.............
}
class L2ConnectedState extends State {
@Override
public void enter() {
mRssiPollToken++;
if (mEnableRssiPolling) {
sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
}
if (mNetworkAgent != null) {
loge("Have NetworkAgent when entering L2Connected");
setNetworkDetailedState(DetailedState.DISCONNECTED);
}
setNetworkDetailedState(DetailedState.CONNECTING);
mNetworkAgent = new WifiNetworkAgent(getHandler().getLooper(), mContext,
"WifiNetworkAgent", mNetworkInfo, mNetworkCapabilitiesFilter,
mLinkProperties, 60, mNetworkMisc);
.............
}
public WifiStateMachine(Context context, FrameworkFacade facade, Looper looper,
UserManager userManager, WifiInjector wifiInjector,
BackupManagerProxy backupManagerProxy, WifiCountryCode countryCode,
WifiNative wifiNative,
WrongPasswordNotifier wrongPasswordNotifier) {
.......................
mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
mNetworkCapabilitiesFilter.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
mNetworkCapabilitiesFilter.setLinkUpstreamBandwidthKbps(1024 * 1024);
mNetworkCapabilitiesFilter.setLinkDownstreamBandwidthKbps(1024 * 1024);
.......................
}
在WifiStateMachine.java中發(fā)現(xiàn)了初始化NetworkAgent 的地方,我們看到了熟悉的身影
mNetworkCapabilitiesFilter.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
終于我們找到設(shè)置TRANSPORT_WIFI的地方
private class DcNetworkAgent extends NetworkAgent {
public DcNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
super(l, c, TAG, ni, nc, lp, score, misc);
}
.............
}
/**
* The state machine is connected, expecting an EVENT_DISCONNECT.
*/
private class DcActiveState extends State {
@Override public void enter() {
.............
final NetworkMisc misc = new NetworkMisc();
final CarrierSignalAgent carrierSignalAgent = mPhone.getCarrierSignalAgent();
if (carrierSignalAgent.hasRegisteredReceivers(TelephonyIntents
.ACTION_CARRIER_SIGNAL_REDIRECTED)) {
// carrierSignal Receivers will place the carrier-specific provisioning notification
misc.provisioningNotificationDisabled = true;
}
misc.subscriberId = mPhone.getSubscriberId();
setNetworkRestriction();
mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
"DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties,
50, misc);
.............
}
NetworkCapabilities getNetworkCapabilities() {
NetworkCapabilities result = new NetworkCapabilities();
result.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
.......................
}
同理在數(shù)據(jù)網(wǎng)絡(luò)DataConnection.java初始化的時(shí)候我們也找到了result.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)設(shè)置的地方
到這里初始化的地方就看的差不多了,下面我們?cè)倭私庀滦盘?hào)變化時(shí)刷新的數(shù)據(jù),NetworkAgentInfo是如何取到的。
- 信號(hào)類(lèi)型的更新
我們?cè)倩氐紺onnectivityService中
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
final NetworkInfo.State state = newInfo.getState();
NetworkInfo oldInfo = null;
final int oldScore = networkAgent.getCurrentScore();
synchronized (networkAgent) {
oldInfo = networkAgent.networkInfo;
networkAgent.networkInfo = newInfo;
}
notifyLockdownVpn(networkAgent);
.....................
}
private void maybeHandleNetworkAgentMessage(Message msg) {
NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
if (nai == null) {
if (VDBG) {
log(String.format("%s from unknown NetworkAgent", eventName(msg.what)));
}
return;
}
....................
case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
NetworkInfo info = (NetworkInfo) msg.obj;
updateNetworkInfo(nai, info);
break;
}
....................
}
private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
if (VDBG) log("Got NetworkAgent Messenger");
mNetworkAgentInfos.put(na.messenger, na);
synchronized (mNetworkForNetId) {
mNetworkForNetId.put(na.network.netId, na);
}
na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
NetworkInfo networkInfo = na.networkInfo;
na.networkInfo = null;
updateNetworkInfo(na, networkInfo);
}
NetworkAgent.java
/**
* Called by the bearer code when it has new NetworkInfo data.
*/
public void sendNetworkInfo(NetworkInfo networkInfo) {
queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));
}
我們可以看到在收到EVENT_NETWORK_INFO_CHANGED的message觸發(fā)了updateNetworkInfo這就是信號(hào)刷新的地方,
我們看到NetworkAgentInfo 就是從初始化的時(shí)候handleRegisterNetworkAgent函數(shù)中,HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos里面取出來(lái)的
case EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED:
AsyncResult ar = (AsyncResult)msg.obj;
Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>)ar.result;
mDataRegState = drsRatPair.first;
if (mRilRat != drsRatPair.second) {
updateTcpBufferSizes(drsRatPair.second);
}
mRilRat = drsRatPair.second;
if (DBG) {
log("DcDefaultState: EVENT_DATA_CONNECTION_DRS_OR_RAT_CHANGED"
+ " drs=" + mDataRegState
+ " mRilRat=" + mRilRat);
}
ServiceState ss = mPhone.getServiceState();
int networkType = ss.getDataNetworkType();
mNetworkInfo.setSubtype(networkType,
TelephonyManager.getNetworkTypeName(networkType));
if (mNetworkAgent != null) {
updateNetworkInfoSuspendState();
mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities());
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
mNetworkAgent.sendLinkProperties(mLinkProperties);
}
break;
DataConenection.java 中刷新信號(hào)類(lèi)型的地方
class ConnectModeState extends State {
@Override
public void enter() {
if (!mWifiNative.removeAllNetworks()) {
loge("Failed to remove networks on entering connect mode");
}
mWifiInfo.reset();
mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
// Let the system know that wifi is available in client mode.
setWifiState(WIFI_STATE_ENABLED);
mNetworkInfo.setIsAvailable(true);
if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
......................
}
@Override
public void exit() {
// Let the system know that wifi is not available since we are exiting client mode.
mNetworkInfo.setIsAvailable(false);
if (mNetworkAgent != null) mNetworkAgent.sendNetworkInfo(mNetworkInfo);
......................
}
}
WifiStateMachine信號(hào)類(lèi)型刷新的地方
好了,到這里framework信號(hào)類(lèi)型的初始化和更新就分析完畢了,中間過(guò)程雖然有點(diǎn)繁瑣,但總的來(lái)說(shuō)邏輯還是相對(duì)清晰的
下面簡(jiǎn)單總結(jié)下吧:
Systemui中顯示wifi和數(shù)據(jù)icon是根據(jù)ConnectivityService.java中上報(bào)的NetworkCapabilities狀態(tài)來(lái)定
當(dāng)NetworkCapabilities getTransportTypes() 返回 TRANSPORT_CELLULAR(== 0)的時(shí)候就顯示數(shù)據(jù)信號(hào)
而NetworkCapabilities getTransportTypes() 返回 TRANSPORT_WIFI(== 1)的時(shí)候就顯示wifi信號(hào)framework信號(hào)類(lèi)型初始化的時(shí)候,每一個(gè)信號(hào)都對(duì)應(yīng)著一個(gè)NetworkAgent,WifiStateMachine 設(shè)置了TRANSPORT_WIFI,而DataConenection 設(shè)置了TRANSPORT_CELLULAR。
分析就到這里了,文章若有什么分析不對(duì)的地方,歡迎大家指正,謝謝O(∩_∩)O