状态栏上信号区域在电池图标的左侧包括 ,ethernet,wifi,sim,airplane等,该区域对应的View为SignalClusterView,其负责显示以上信号图标的显示
图中红框部分就是SignalClusterView
SignalClusterView
// Intimately tied to the design of res/layout/signal_cluster_view.xml
public class SignalClusterView extends LinearLayout implements NetworkControllerImpl.SignalCallback,
SecurityController.SecurityControllerCallback, Tunable,
DarkReceiver {
其实现了NetworkControllerImpl.SignalCallback接口,根据名称可以看出信号图标更新的逻辑主要靠回调接口完成.
SignalCallback接口定义在NetworkControllerImpl实现的接口NetworkController中
NetworkController
public interface SignalCallback {
// 设置wifi图标
default void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
boolean activityIn, boolean activityOut, String description, boolean isTransient) {}
default void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
int networkIcon, int volteType, int qsType, boolean activityIn, boolean activityOut,
String typeContentDescription, String description, boolean isWide, int subId,
boolean roaming) {}
default void setSubs(List<SubscriptionInfo> subs) {}
default void setNoSims(boolean show, boolean simDetected) {}
default void setEthernetIndicators(IconState icon) {}
default void setIsAirplaneMode(IconState icon) {}
default void setMobileDataEnabled(boolean enabled) {}
}
根据每个方法的名称即可看出其具体作用,比如设置wifi图标,设置数据流量图标,设置是否为飞行模式等等.
那具体这些方法如何调用,我们便可从NetworkControllerImpl入手.
NetworkControllerImpl继承自BroadcastReceiver,猜想就是通过接受各个网络状态的广播然后去进行进一步更新状态,让我们一探究竟
其注册了如下广播
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);
可以看出接受了关于网络信号相关的广播,收到广播会在onReceive()方法中处理
NetworkControllerImpl
@Override
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 {
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.
// 处理wifi状态改变
mWifiSignalController.handleBroadcast(intent);
}
}
}
在开篇的图片中可以看到wifi图标本来包含上下行图标,但左侧还有独立的上下行图标,我们就以去掉左侧的上下行图标为例,如果wifi状态改变,则会走到上面代码的mWifiSignalController.handleBroadcast(intent);处
WifiSignalController
public class WifiSignalController extends
SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
/**
* Extract wifi state directly from broadcasts about changes in wifi state.
*/
public void handleBroadcast(Intent intent) {
mWifiTracker.handleBroadcast(intent); // 将intent中wifi状态交给wifiTracker
mCurrentState.enabled = mWifiTracker.enabled;
mCurrentState.connected = mWifiTracker.connected;
mCurrentState.ssid = mWifiTracker.ssid;
mCurrentState.rssi = mWifiTracker.rssi;
mCurrentState.level = mWifiTracker.level;
// 由父类进一步调用notifyListeners(mCallbackHandler);来交由具体子类完成 ,这里就是WifiSignalController了,该出代码不贴出了
notifyListenersIfNecessary();
}
@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 ? mCurrentStateNetworkController.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);
IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(),
contentDescription);
// 该callback实际就是CallbackHandler
callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
wifiDesc, mCurrentState.isTransient);
}
}
notifyListeners中的callback是在创建WifiSignalController创建时传入的,WifiSignalController在NetworkControllerImpl构造方法中创建的,
该callback是直接new了一个CallbackHandler对象,其实现了SignalCallback
CallbackHandler
// 所有实现了SignalCallback并注册过来的集合
private final ArrayList<SignalCallback> mSignalCallbacks = new ArrayList<>();
@Override
public void setWifiIndicators(final boolean enabled, final IconState statusIcon,
final IconState qsIcon, final boolean activityIn, final boolean activityOut,
final String description, boolean isTransient) {
post(new Runnable() {
@Override
public void run() {
for (SignalCallback callback : mSignalCallbacks) {
// 利用多态调用setWifiIndicators
callback.setWifiIndicators(enabled, statusIcon, qsIcon, activityIn, activityOut,
description, isTransient);
}
}
});
}
CallbackHandler维护了所有需要监听的SignalCallback接口对象,我们的SignalClusterView就实现了该接口。该类中持有NetWorkController对象
SignalClusterView
public SignalClusterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
...
mNetworkController = Dependency.get(NetworkController.class);
updateActivityEnabled();
...
}
所有Controller都由Dependency管理,SystemUI启动后就会调用子类的start方法,Dependency会维护所有的Controller对象,具体如下
Dependency
public class Dependency extends SystemUI {
@Override
public void start() {
sDependency = this;
....
mProviders.put(BluetoothController.class, () ->
new BluetoothControllerImpl(mContext, getDependency(BG_LOOPER)));
mProviders.put(LocationController.class, () ->
new LocationControllerImpl(mContext, getDependency(BG_LOOPER)));
mProviders.put(RotationLockController.class, () ->
new RotationLockControllerImpl(mContext));
// 将NetworkControllerImpl由mProviders管理,
mProviders.put(NetworkController.class, () ->
new NetworkControllerImpl(mContext, getDependency(BG_LOOPER),
getDependency(DeviceProvisionedController.class)));
...
}
知道了CallbackHandler中callback来历,继续看callback.setWifiIndicators继续分析
SignalClusterView
public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
boolean activityIn, boolean activityOut, String description, boolean isTransient) {
mWifiVisible = statusIcon.visible && !mBlockWifi;
mWifiStrengthId = statusIcon.icon;
mWifiDescription = statusIcon.contentDescription;
// activityIn标识是否为wifi下行
// mActivityEnabled 是否支持图标显示
// mWifiVisible wifi图标是否可见
mWifiIn = activityIn && mActivityEnabled && mWifiVisible;
mWifiOut = activityOut && mActivityEnabled && mWifiVisible;
apply();
}
如果要去掉wifi图标左侧上下行图标,mActivityEnabled改为不支持即可,其是在config中进行配置
vendor/mediatek/proprietary/packages/apps/SystemUI/res/values/config.xml
<bool name="config_showActivity">falsebool>
至此整个分析结束了,总结下
SignalClusterView是信号区域的View,其实现了NetworkControllerImpl.SignalCallback接口,然后注册到NetworkController,其具体实现类NetworkControllerImpl会根据WIFI,SIM等状态广播来进一步派发给具体的Controller,例如WifiSignalController,每个Controller只与CallbackHandler交互,然后CallbackHandler继续转交给维护的SignalCallback接口的具体实现类,例如SingalClusterView