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

该篇博文需要一定的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来实现具体的业务逻辑

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值