Android4.4 Systemui状态栏之信号逻辑流程分析

来源:互联网 发布:java中log 编辑:程序博客网 时间:2024/05/16 10:58

该篇博文需要一定的Systemui的状态栏基础才能看懂,所以如果各位看官是第一次学习Systemui的状态栏的话建议您点击以下传送门
http://blog.csdn.net/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来实现具体的业务逻辑

由于最近在实习工作事情很多,并且毕业之际,诸事于一身,以上的分析由于时间比较匆促,所以分析得挺粗的,如果抽得空出来,我会继续分析具体业务流程.如有错漏,欢迎大家指出,毕竟小菜鸟一个.

0 0
原创粉丝点击