手机在Statusbar 上,会有个信号塔的图标。该图标是标识当前手机信号的强度(通常是voice的信号强度)。此图标会根据当前设备所收到的信号强度来对应的显示不同的资源图标,就是通常说的信号格数。这个信号值是一直变化的,那么图标也是实时更新的。在此总结下信号图标更新的流程。
在ServiceStateTracker.java的构造函数里可以看到,在初始化ServiceStateTracker时,有向Ril监听EVENT_SIGNAL_STRENGTH_UPDATE的消息,那么当modem上报信号变化更新时,在ServiceStateTracker会去处理这个消息。这里关于注册消息的处理,不熟悉的可以查看 Android 基础篇 -- Registrant
xref: /frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java
/**
* Registrant a message on Ril
* You can check setOnSignalStrengthUpdate on RIL.java
*/
public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
...
mCi.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
...
}
/**
* send signal-strength-changed notification if changed Called both for
* solicited and unsolicited signal strength updates
*
* @return true if the signal strength changed and a notification was sent.
*/
protected boolean onSignalStrengthResult(AsyncResult ar) {
boolean isGsm = false;
int dataRat = mSS.getRilDataRadioTechnology();
int voiceRat = mSS.getRilVoiceRadioTechnology();
...
boolean ssChanged = notifySignalStrength();
return ssChanged;
}
/**
* Notify all SignalStrength Registrants about SignalStrength update
*
*/
protected boolean notifySignalStrength() {
boolean notified = false;
if (!mSignalStrength.equals(mLastSignalStrength)) {
try {
mPhone.notifySignalStrength();
notified = true;
} catch (NullPointerException ex) {
loge("updateSignalStrength() Phone already destroyed: " + ex
+ "SignalStrength not notified");
}
}
return notified;
}
当ServiceStateTracker处理完上报的消息后,可以看到是通知所有注册该监听的对象。
在ServiceStateTracker通知注册监听对象后,会通过一系列通知 & aidl 进行数据传递,一直传递到MobileSignalController.这块没有太多的逻辑,大概传递方向是:ServiceStateTracker # notifySignalStrength --> Phone # notifySignalStrength --> DefaultPhoneNotifier # notifySignalStrength --> TelephonyRegistry# notifySignalStrengthForPhoneId
MobileSignal 有监听到SignalStrengthsChange的消息,开始在SystemUI来处理消息并显示。
xref: /frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
...
mSignalStrength = signalStrength;
updateTelephony();
}
/**
* Updates the current state based on mServiceState, mSignalStrength,
* mDataNetType, mDataState, and mSimState. It should be called any time one of
* these is updated.
* This will call listeners if necessary.
*/
private final void updateTelephony() {
...
notifyListenersIfNecessary();
}
/**
* This method will setMobileDataIndicators to SystemUI
* and display these icons.
*/
@Override
public void notifyListeners(SignalCallback callback) {
MobileIconGroup icons = getIcons();
...
int typeIcon = showDataIcon ? icons.mDataType : 0;
callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
activityIn, activityOut, dataContentDescription, description,
icons.mIsWide,
mSubscriptionInfo.getSubscriptionId(), mCurrentState.roaming);
}
/**
* This method will set and display these icons
* to view.
*/
@Override
public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
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;
state.mRoaming = roaming;
state.mActivityIn = activityIn && mActivityEnabled;
state.mActivityOut = activityOut && mActivityEnabled;
apply();
}
至此该值会在SystemUI上显示出来,逻辑比较简单,没有太多的复杂逻辑,主要都是注册消息和监听。主要的流程如下:
原生系统中,信号格是满格四格,但是不同的OEM或者不同的运营商,对于信号区间显示几格信号图标有特殊的需求。那么我们就要研究下其判断逻辑。
先上代码:
/**
* Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
* mDataState, and mSimState. It should be called any time one of these is updated.
* This will call listeners if necessary.
*/
private final void updateTelephony() {
if (DEBUG) {
Log.d(mTag, "updateTelephonySignalStrength: hasService=" + hasService()
+ " ss=" + mSignalStrength);
}
//判断是否有信号
mCurrentState.connected = hasService() && mSignalStrength != null;
if (mCurrentState.connected) {
//判断是GSM 或是 CDMA的信号,然后获取level
if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
mCurrentState.level = mSignalStrength.getCdmaLevel();
} else {
mCurrentState.level = mSignalStrength.getLevel();
...
}
可以看到在updateTelephony时,会先判断当前是否有信号,否则下面执行就没有意义了。然后判断是什么类型的信号,我们就以GSM为例,可以看到是SignalStrength.getLevel().
/**
* Retrieve an abstract level value for the overall signal strength.
*
* @return a single integer from 0 to 4 representing the general signal quality.
* This may take into account many different radio technology inputs.
* 0 represents very poor signal strength
* while 4 represents a very strong signal strength.
*/
public int getLevel() {
// 首先给默认信号格数为0
int level = 0;
if (isGsm) {
//先根据LTE的信号量来判断
level = getLteLevel();
//如果没有LTE信号则去根据TdScdma的信号来判断
if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
level = getTdScdmaLevel();
//如果仍然没有的话,则用Gsm信号量来判断
if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
level = getGsmLevel();
}
}
} else {
// CDMA 信号逻辑相同
int cdmaLevel = getCdmaLevel();
int evdoLevel = getEvdoLevel();
if (evdoLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
/* We don't know evdo, use cdma */
level = cdmaLevel;
} else if (cdmaLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
/* We don't know cdma, use evdo */
level = evdoLevel;
} else {
/* We know both, use the lowest level */
level = cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel;
}
}
if (DBG) log("getLevel=" + level);
return level;
}
我们再看下getLTElevel:
/**
* Get LTE as level 0..4
*
* @hide
*/
public int getLteLevel() {
/*
* TS 36.214 Physical Layer Section 5.1.3 TS 36.331 RRC RSSI = received
* signal + noise RSRP = reference signal dBm RSRQ = quality of signal
* dB= Number of Resource blocksxRSRP/RSSI SNR = gain=signal/noise ratio
* = -10log P1/P2 dB
*/
int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, rsrpIconLevel = -1, snrIconLevel = -1;
int rsrpThreshType = Resources.getSystem().getInteger(com.android.internal.R.integer.
config_LTE_RSRP_threshold_type);
if (mThreshRsrp == null) {
if (rsrpThreshType == RSRP_THRESH_TYPE_STRICT) {
mThreshRsrp = RSRP_THRESH_STRICT;
} else {
mThreshRsrp = RSRP_THRESH_LENIENT;
}
}
if (Resources.getSystem().getBoolean(
com.android.internal.R.bool.config_regional_lte_singnal_threshold)){
mThreshRsrp = Resources.getSystem().getIntArray(
com.android.internal.R.array.lte_signal_strength_threshold);
}
if (mLteRsrp > mThreshRsrp[5]) rsrpIconLevel = -1;
else if (mLteRsrp >= mThreshRsrp[4]) rsrpIconLevel = SIGNAL_STRENGTH_GREAT;
else if (mLteRsrp >= mThreshRsrp[3]) rsrpIconLevel = SIGNAL_STRENGTH_GOOD;
else if (mLteRsrp >= mThreshRsrp[2]) rsrpIconLevel = SIGNAL_STRENGTH_MODERATE;
else if (mLteRsrp >= mThreshRsrp[1]) rsrpIconLevel = SIGNAL_STRENGTH_POOR;
else if (mLteRsrp >= mThreshRsrp[0]) rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
/*
* Values are -200 dB to +300 (SNR*10dB) RS_SNR >= 13.0 dB =>4 bars 4.5
* dB <= RS_SNR < 13.0 dB => 3 bars 1.0 dB <= RS_SNR < 4.5 dB => 2 bars
* -3.0 dB <= RS_SNR < 1.0 dB 1 bar RS_SNR < -3.0 dB/No Service Antenna
* Icon Only
*/
if (mLteRssnr > 300) snrIconLevel = -1;
else if (mLteRssnr >= 130) snrIconLevel = SIGNAL_STRENGTH_GREAT;
else if (mLteRssnr >= 45) snrIconLevel = SIGNAL_STRENGTH_GOOD;
else if (mLteRssnr >= 10) snrIconLevel = SIGNAL_STRENGTH_MODERATE;
else if (mLteRssnr >= -30) snrIconLevel = SIGNAL_STRENGTH_POOR;
else if (mLteRssnr >= -200)
snrIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
if (DBG) log("getLTELevel - rsrp:" + mLteRsrp + " snr:" + mLteRssnr + " rsrpIconLevel:"
+ rsrpIconLevel + " snrIconLevel:" + snrIconLevel);
/* Choose a measurement type to use for notification */
if (snrIconLevel != -1 && rsrpIconLevel != -1) {
/*
* The number of bars displayed shall be the smaller of the bars
* associated with LTE RSRP and the bars associated with the LTE
* RS_SNR
*/
return (rsrpIconLevel < snrIconLevel ? rsrpIconLevel : snrIconLevel);
}
if (snrIconLevel != -1) return snrIconLevel;
if (rsrpIconLevel != -1) return rsrpIconLevel;
/* Valid values are (0-63, 99) as defined in TS 36.331 */
if (mLteSignalStrength > 63) rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
else if (mLteSignalStrength >= 12) rssiIconLevel = SIGNAL_STRENGTH_GREAT;
else if (mLteSignalStrength >= 8) rssiIconLevel = SIGNAL_STRENGTH_GOOD;
else if (mLteSignalStrength >= 5) rssiIconLevel = SIGNAL_STRENGTH_MODERATE;
else if (mLteSignalStrength >= 0) rssiIconLevel = SIGNAL_STRENGTH_POOR;
if (DBG) log("getLTELevel - rssi:" + mLteSignalStrength + " rssiIconLevel:"
+ rssiIconLevel);
return rssiIconLevel;
}
可以看出,数组的定义就是在这里,如果我们只需要更改这个区间就可以更改信号格数。此处要注意的是设备的信号是以RSSI 还是以RSRP来判断的。 在遇到不同的运营商需求时,可以通过更改数组的区间以及显示信号level的api来实现。