该篇博文需要一定的Systemui的状态栏基础才能看懂,所以如果各位看官是第一次学习Systemui的状态栏的话建议您点击以下传送门
http://blog.youkuaiyun.com/yihongyuelan?viewmode=contents
以下是正文:状态栏的信号包括:手机网络信号,无线WIFI网络信号,代理服务器网络信号,飞行模式4种
以上的4种信号由SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java实现具体的流程逻辑,该类继承BroadcastReceiver,所以大胆猜测底层信号如果发生改变,该广播会接受到相应的广播.
然后在SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java创建一个NetworkController对象,具体代码如下:
protected PhoneStatusBarView makeStatusBarView() {
……..
mNetworkController = new NetworkController(mContext);
final SignalClusterView signalCluster =
(SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster);
mNetworkController.addSignalCluster(signalCluster);
signalCluster.setNetworkController(mNetworkController);
…..
}
然后在状态栏上的UI界面更新,在类SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java中实现.
下面我们开始具体的流程分析吧
先从类SignalClusterView.java开始,因为该类比较简单,易于以后的对复杂的类NetworkController.java分析
public class SignalClusterView
extends LinearLayout
implements NetworkController.SignalCluster
这是该类的继承关系,我们很明显的看到该类实例化了类NetworkController中的内部接口SignalCluster
以下SignalCluserView的全部展示
package com.android.systemui.statusbar;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.NetworkController;
// Intimately tied to the design of res/layout/signal_cluster_view.xml
/**
* @author tony
* 信号集中类,包含wifi,以太网,手机信号,飞行模式
*/
public class SignalClusterView
extends LinearLayout
implements NetworkController.SignalCluster {
static final boolean DEBUG = false;
static final String TAG = "SignalClusterView";
NetworkController mNC;
private boolean mWifiVisible = false;
private int mWifiStrengthId = 0;
private boolean mEthernetVisible = false;
private int mEthernetStateId = 0, mEthernetActivityId = 0;
private boolean mMobileVisible = false;
private int mMobileStrengthId = 0, mMobileTypeId = 0;
private boolean mIsAirplaneMode = false;
private int mAirplaneIconId = 0;
private String mWifiDescription, mMobileDescription, mMobileTypeDescription, mEthernetDescription;
ViewGroup mWifiGroup, mMobileGroup, mEthernetGroup; //Ethernet是代理服务器的意思
ImageView mWifi, mMobile, mMobileType, mAirplane, mEthernet;
View mSpacer;
public SignalClusterView(Context context) {
this(context, null);
}
public SignalClusterView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SignalClusterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setNetworkController(NetworkController nc) {
if (DEBUG) Log.d(TAG, "NetworkController=" + nc);
mNC = nc;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mWifiGroup = (ViewGroup) findViewById(R.id.wifi_combo);
mWifi = (ImageView) findViewById(R.id.wifi_signal);
mMobileGroup = (ViewGroup) findViewById(R.id.mobile_combo);
mMobile = (ImageView) findViewById(R.id.mobile_signal);
mMobileType = (ImageView) findViewById(R.id.mobile_type);
mSpacer = findViewById(R.id.spacer);
mAirplane = (ImageView) findViewById(R.id.airplane);
mEthernetGroup = (ViewGroup) findViewById(R.id.ethernet_combo);
mEthernet = (ImageView) findViewById(R.id.ethernet_state);
apply();
}
@Override
protected void onDetachedFromWindow() {
mWifiGroup = null;
mWifi = null;
mMobileGroup = null;
mMobile = null;
mMobileType = null;
mSpacer = null;
mAirplane = null;
super.onDetachedFromWindow();
}
/**
* change by tony
* 当wifi信号改变时所调用的方法
* @param visible
* @param strengthIcon
* @param contentDescription
*/
@Override
public void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription) {
mWifiVisible = visible;
mWifiStrengthId = strengthIcon;
mWifiDescription = contentDescription;
apply();
}
/**
* change by tony
* 当手机信号改变时所调用的方法
* @param visible
* @param strengthIcon
* @param typeIcon
* @param contentDescription
* @param typeContentDescription
*/
@Override
public void setMobileDataIndicators(boolean visible, int strengthIcon,
int typeIcon, String contentDescription, String typeContentDescription) {
mMobileVisible = visible;
mMobileStrengthId = strengthIcon;
mMobileTypeId = typeIcon;
mMobileDescription = contentDescription;
mMobileTypeDescription = typeContentDescription;
apply();
}
/**
* change by tony
* 当以太网信号改变时所调用的方法
* @param visible
* @param strengthIcon
* @param activityIcon
* @param contentDescription
*/
public void setEthernetIndicators(boolean visible,int strengthIcon,int activityIcon,
String contentDescription){
mEthernetVisible = visible;
mEthernetStateId = strengthIcon;
mEthernetActivityId = activityIcon;
mEthernetDescription = contentDescription;
apply();
}
@Override
public void setIsAirplaneMode(boolean is, int airplaneIconId) {
mIsAirplaneMode = is;
mAirplaneIconId = airplaneIconId;
apply();
}
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
// Standard group layout onPopulateAccessibilityEvent() implementations
// ignore content description, so populate manually
if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null)
event.getText().add(mWifiGroup.getContentDescription());
if (mMobileVisible && mMobileGroup != null && mMobileGroup.getContentDescription() != null)
event.getText().add(mMobileGroup.getContentDescription());
return super.dispatchPopulateAccessibilityEvent(event);
}
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
if (mWifi != null) {
mWifi.setImageDrawable(null);
}
if (mMobile != null) {
mMobile.setImageDrawable(null);
}
if (mMobileType != null) {
mMobileType.setImageDrawable(null);
}
if(mAirplane != null) {
mAirplane.setImageDrawable(null);
}
apply();
}
// Run after each indicator change.
private void apply() {
if (mWifiGroup == null) return;
if (mWifiVisible) {
mWifi.setImageResource(mWifiStrengthId);
mWifiGroup.setContentDescription(mWifiDescription);
mWifiGroup.setVisibility(View.VISIBLE);
} else {
mWifiGroup.setVisibility(View.GONE);
}
if(mEthernetVisible){
mEthernetGroup.setVisibility(View.VISIBLE);
mEthernet.setImageResource(mEthernetStateId);
mEthernetGroup.setContentDescription(mEthernetDescription);
} else {
mEthernetGroup.setVisibility(View.GONE);
}
if (DEBUG) Log.d(TAG,
String.format("wifi: %s sig=%d",
(mWifiVisible ? "VISIBLE" : "GONE"),
mWifiStrengthId));
if (mMobileVisible && !mIsAirplaneMode) {
mMobile.setImageResource(mMobileStrengthId);
mMobileType.setImageResource(mMobileTypeId);
mMobileGroup.setContentDescription(mMobileTypeDescription + " " + mMobileDescription);
mMobileGroup.setVisibility(View.VISIBLE);
} else {
mMobileGroup.setVisibility(View.GONE);
}
if (mIsAirplaneMode) {
mAirplane.setImageResource(mAirplaneIconId);
mAirplane.setVisibility(View.VISIBLE);
} else {
mAirplane.setVisibility(View.GONE);
}
if (mMobileVisible && (mWifiVisible || mEthernetVisible) && mIsAirplaneMode) {
mSpacer.setVisibility(View.INVISIBLE);
} else {
mSpacer.setVisibility(View.GONE);
}
if (DEBUG) Log.d(TAG,
String.format("mobile: %s sig=%d typ=%d",
(mMobileVisible ? "VISIBLE" : "GONE"),
mMobileStrengthId, mMobileTypeId));
mMobileType.setVisibility(
!(mWifiVisible || mEthernetVisible) ? View.VISIBLE : View.GONE);
}
}
从上诉代码我们可以很容易的分析得到SignalCluster类上实现界面更新的时机是类NetworkController的内部接口调用实现的.具体的UI界面在类SignalCluster中的方法apply(){}中,具体的ui更新分析就不在详细展开了,大家自己看下代码就懂了.
下面是对重中之重的类NetworkController分析,
虽然该类是一个广播,但是没有在AndroidMainfest.XML上注册,所以不是一个静态广播,而是一个动态广播
首先对该类的构造方法分析:
public NetworkController(Context context) {
.......
mContext = context;
// set up the default wifi icon, used when no radios have ever appeared
updateWifiIcons();
updateWimaxIcons();
// telephony
mPhone = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
//手机信号监听器,如果手机信号有更新的话就在监听器mPhoneStateListener有回调
mPhone.listen(mPhoneStateListener,
PhoneStateListener.LISTEN_SERVICE_STATE
| PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
| PhoneStateListener.LISTEN_CALL_STATE
| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
| PhoneStateListener.LISTEN_DATA_ACTIVITY);
// wifi
//AsyncChannel通讯主要是两个handler的通讯,不了解的同学可以先了解一下,所以通讯在
//WifiHandler()
mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
Handler handler = new WifiHandler();
mWifiChannel = new AsyncChannel();
Messenger wifiMessenger = mWifiManager.getWifiServiceMessenger();
if (wifiMessenger != null) {
mWifiChannel.connect(mContext, handler, wifiMessenger);
}
// 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.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);
filter.addAction(EthernetManager.ETHERNET_STATE_CHANGED_ACTION);
filter.addAction(EthernetManager.NETWORK_STATE_CHANGED_ACTION);
// AIRPLANE_MODE_CHANGED is sent at boot; we've probably already missed it
updateAirplaneMode();
mLastLocale = mContext.getResources().getConfiguration().locale;
}
从上面的构造方法中我们可以看出,手机信号的更新是通过getSystemService(Context.TELEPHONY_SERVICE)获取实例,然后再通过注册监听来监听手机信号的变化.wifi信号getSystemService(Context.WIFI_SERVICE)获取实例,然后通过AsyncChannel实现自己的WifiHandler跟wifiManager中的handler实现通讯.并且注册一个动态广播,监听手机信号跟wifi信号来更新UI
手机信号监听器的代码:
// ===== Telephony ==============================================================
PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
//手机信号强度改变,在这里实现具体的业务逻辑
}
@Override
public void onServiceStateChanged(ServiceState state) {
//手机信号状态改变,在这里实现具体的业务逻辑,比如强度,信号类型
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
}
@Override
public void onDataConnectionStateChanged(int state, int networkType) {
//手机信号状态改变,在这里实现具体的业务逻辑,比如强度,信号类型
}
@Override
public void onDataActivity(int direction) {
};
WIFI信号跟新
// ===== Wifi ===================================================================
class WifiHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
mWifiChannel.sendMessage(Message.obtain(this,
AsyncChannel.CMD_CHANNEL_FULL_CONNECTION));
} else {
Log.e(TAG, "Failed to connect to wifi");
}
break;
case WifiManager.DATA_ACTIVITY_NOTIFICATION:
if (msg.arg1 != mWifiActivity) {
mWifiActivity = msg.arg1;
refreshViews();
}
break;
default:
//Ignore
break;
}
}
}
由于NetworkController是个广播,所以必须得分析public void onReceive(Context context, Intent intent)
下面是onReceive的具体代码了
@Override
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();
} else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
updateSimState(intent);
updateDataIcon();
refreshViews();
} else if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) {
updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false),
intent.getStringExtra(TelephonyIntents.EXTRA_SPN),
intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false),
intent.getStringExtra(TelephonyIntents.EXTRA_PLMN));
refreshViews();
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
updateConnectivity(intent);
refreshViews();
} else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
refreshLocale();
refreshViews();
} else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
refreshLocale();
updateAirplaneMode();
refreshViews();
} else if (action.equals(WimaxManagerConstants.NET_4G_STATE_CHANGED_ACTION) ||
action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
action.equals(WimaxManagerConstants.WIMAX_NETWORK_STATE_CHANGED_ACTION)) {
updateWimaxState(intent);
refreshViews();
} else if (action.equals(EthernetManager.NETWORK_STATE_CHANGED_ACTION)
|| action.equals(EthernetManager.ETHERNET_STATE_CHANGED_ACTION)) {
updateEthernetState(intent);
refreshViews();
}
}
以上的代码也很清晰了,就是根据不同的广播Action来实现具体的业务逻辑
由于最近在实习工作事情很多,并且毕业之际,诸事于一身,以上的分析由于时间比较匆促,所以分析得挺粗的,如果抽得空出来,我会继续分析具体业务流程.如有错漏,欢迎大家指出,毕竟小菜鸟一个.