Android 信號欄SignalClusterView顯示與更新流程

上一篇博客寫了關於顯示SignalClusterView的流程。
https://blog.csdn.net/csdnxialei/article/details/86570013

這一篇寫關於SignalClusterView如何在控制和顯示着信號相關信息。


SignalClusterView是顯示各種信號欄圖標view集合,它實現了多個接口。

public class SignalClusterView extends LinearLayout implements NetworkControllerImpl.SignalCallback,
        SecurityController.SecurityControllerCallback, Tunable,
        DarkReceiver

其中最重要的莫過於NetworkControllerImpl.SignalCallback這個接口了。

public interface SignalCallback {
    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) {}
}

SignalCallback這個接口,直接控制着信號欄view的顯示問題。

其中setWifiIndicators,和setMobileDataIndicators就是控制顯示wifi信息,和信號格網絡狀態的信息。

在SignalClusterView構造的時候

public SignalClusterView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    ...
    mNetworkController = Dependency.get(NetworkController.class);
    mSecurityController = Dependency.get(SecurityController.class);
    ...

mNetworkController通過Dependency的服務來獲取了NetworkController的實例。

然後在onAttachedToWindow的時候將SignalClusterView註冊到了NetworkController.SignalCallback

@Override
protected void onAttachedToWindow() {
    ...
    mNetworkController.addCallback(this);
    mSecurityController.addCallback(this);
    ...
}

至此,SignalClusterView在顯示到界面上以後,就開始接受mNetworkController的接口方法控制,

然而mNetworkController是個接口對象,所以誰繼承了mNetworkController,誰就是實際控制SignalClusterView顯示信號信息的幕後主使。

誰是幕後主使?

通過繼承關係找到了NetworkControllerImpl。

public class NetworkControllerImpl extends BroadcastReceiver
        implements NetworkController, DemoMode,
        DataUsageController.NetworkNameProvider,ConfigurationChangedReceiver, Dumpable 

看看NetworkControllerImpl

public void addCallback(SignalCallback cb) {
    cb.setSubs(mCurrentSubscriptions);
    cb.setIsAirplaneMode(new IconState(mAirplaneMode,TelephonyIcons.FLIGHT_MODE_ICON, 
    R.string.accessibility_airplane_mode, mContext));
    mWifiSignalController.notifyListeners(cb);
    mEthernetSignalController.notifyListeners(cb);
    for (int i = 0; i < mMobileSignalControllers.size(); i++) {
        MobileSignalController mobileSignalController =mMobileSignalControllers.valueAt(i);
        mobileSignalController.notifyListeners(cb);
    }
    mCallbackHandler.setListening(cb, true);
    cb.setNoSims(mHasNoSubs, mSimDetected);
}

在addCallback的時候,這個SignalCallback也就是前面的SignalClusterView。

雖然上面有 mobileSignalController.notifyListeners(cb);在後面也會出現,但是這只是第一次刷新,之後的刷新交給了另一個對象,

mCallbackHandler.setListening(cb, true);

CallbackHandler

private final CallbackHandler mCallbackHandler;
public void setListening(SignalCallback listener, boolean listening) {
    if (DEBUG) {
        Log.d(TAG, "setListening, listener = " + listener
              + ", listening = " + listening);
    }
    obtainMessage(MSG_ADD_REMOVE_SIGNAL, listening ? 1 : 0, 0, listener).sendToTarget();
}

setListening之後,就會由CallbackHandler來通知所有Listenner來更新顯示。

而且CallbackHandler也是繼承了SignalCallback

public class CallbackHandler extends Handler implements EmergencyListener, SignalCallback
    @Override
    public void setMobileDataIndicators(final IconState statusIcon, final IconState qsIcon,
            final int statusType, final int networkIcon, final int volteType,
            final int qsType,final boolean activityIn,
            final boolean activityOut, final String typeContentDescription,
            final String description, final boolean isWide, final int subId, boolean roaming) {
        post(new Runnable() {
            @Override
            public void run() {
                for (SignalCallback signalCluster : mSignalCallbacks) {
                    ///M: Support[Network Type and volte on StatusBar].
                    /// add more parameter networkIcon and volte.
                    signalCluster.setMobileDataIndicators(statusIcon, qsIcon, statusType,
                            networkIcon, volteType, qsType, activityIn, activityOut,
                            typeContentDescription, description, isWide, subId, roaming);
                }
            }
        });
    }

在CallbackHandler的setMobileDataIndicators,去調用各個監聽器的同一setMobileDataIndicators,

CallbackHandler實現了統一管理。

通過線索查找,我們發現,真正去通知CallbackHandler調用回調方法的是在MobileSignalController裏。

    @Override
    public void notifyListeners(SignalCallback callback) {
        ...
     callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, networkIcon, volteIcon,
                                      qsTypeIcon,activityIn, activityOut, dataContentDescription, description,
                                      icons.mIsWide, mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);
        ...
    }

public class MobileSignalController extends SignalController<
        MobileSignalController.MobileState, MobileSignalController.MobileIconGroup> 

MobileSignalController

MobileSignalController繼承了SignalController,

在SignalController裏

public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
    mCurrentState.inetCondition = validatedTransports.get(mTransportType) ? 1 : 0;
    notifyListenersIfNecessary();
}
public void notifyListenersIfNecessary() {
    if (isDirty()) {
        saveLastState();
        notifyListeners();
    }
}
public final void notifyListeners() {
    notifyListeners(mCallbackHandler);
}

所以,SignalController的notifyListeners,是來自於updateConnectivity。

而反向查找,發現其實是這樣的

NetworkControllerImpl

@Override
public void onReceive(Context context, Intent intent) {
    final String action = intent.getAction();
    if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
        action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
        updateConnectivity();
    } 
private void updateConnectivity() {       
    ...
    pushConnectivityToSignals();
    ...
}
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);
    }
}

發現了一個既定事實,一切起源於NetworkControllerImpl的onReceive。

過程就是下面這個順序

NetworkControllerImpl

MobileSignalController

CallbackHandler

SignalCallback

SignalClusterView

前面notifyListeners的時候獲取了一些icon信息。

@Override
public void notifyListeners(SignalCallback callback) {
    MobileIconGroup icons = getIcons();
    。。。
    int iconId = getCurrentIconId();
    。。。
    IconState statusIcon = new IconState(mCurrentState.enabled && 
    !mCurrentState.airplaneMode,iconId, contentDescription);
    。。。
    qsIcon = new IconState(mCurrentState.enabled&& 
    !mCurrentState.isEmergency, getQsCurrentIconId(), contentDescription);
    。。。
    int networkIcon = mCurrentState.networkIcon;
    int volteIcon = mCurrentState.airplaneMode && !isImsOverWfc()
                ? 0 : mCurrentState.volteIcon;
    。。。
    callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, networkIcon, volteIcon,qsTypeIcon,)
    。。。
}

MobilePhoneStateListener

這些信息的獲取,來自於MobilePhoneStateListener

mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId(),

MobilePhoneStateListener有這些重載方法,

@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength)
@Override
public void onServiceStateChanged(ServiceState state)
@Override
public void onDataConnectionStateChanged(int state, int networkType) 
@Override
public void onCarrierNetworkChange(boolean active)
@Override
public void onCallStateChanged(int state, String incomingNumber) 

他們都調用了updateTelephony();

在updateTelephony裏,MobileSignalController獲取了所需要的關於信號強度,網絡連接狀態等信息。

最後也回到了

    public void notifyListenersIfNecessary() {
        if (isDirty()) {
            saveLastState();
            notifyListeners();
        }
    }

這和前面的NetworkControllerImpl有相同的地方,區別在於NetworkControllerImpl是用廣播接收器更新的,而

MobilePhoneStateListener則是直接通過Telephony系統服務來更新,更新頻率更頻繁。

就這樣,來自系統的信號狀態信息彙集到MobileSignalController的notifyListeners裏。
然後notifyListeners就最後走到了SignalClusterView的setMobileDataIndicators。

所有的信息都被加載到setMobileDataIndicators,然後就是把各個icon資源顯示到狀態欄裏。

@Override
public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, 
	int statusType,int networkType, int volteIcon, int qsType, 
	boolean activityIn, boolean activityOut,String typeContentDescription, 
	String description, boolean isWide, int subId,boolean roaming) {
    PhoneState state = getState(subId);
    if (state == null) {
        return;
    }
    state.mMobileVisible = statusIcon.visible && !mBlockMobile;
    state.mMobileStrengthId = statusIcon.icon;
    state.mMobileTypeId = statusType;
    state.mMobileDescription = statusIcon.contentDescription;
    state.mMobileTypeDescription = typeContentDescription;
    state.mIsMobileTypeIconWide = statusType != 0 && isWide;
    /// M: for big network icon and volte icon.
    state.mNetworkIcon = networkType;
    state.mVolteIcon = volteIcon;
    state.mRoaming = roaming;
    state.mActivityIn = activityIn && mActivityEnabled;
    state.mActivityOut = activityOut && mActivityEnabled;

    /// M: Add for plugin features. @ {
    state.mDataActivityIn = activityIn;
    state.mDataActivityOut = activityOut;
    /// @ }

    apply();
}

顯示流程與更新流程也到此結束。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章