CellLocation,即小区位置。它保存了设备当前所处网络的位置,对于不同的接入技术,其用来描述CellLocation的参数略有不同。
3GPP:
包含LAC(Location Area Code/位置区域码)、CID(Cell ID/小区ID)、PSC(Primary Scrambling Code/主扰码),
其中PSC是UMTS专有的,
另外,由于LTE中已不再使用LAC/RAC,取而代之的是TAC,因此在GsmCellLocation中直接把其TAC的值作为LAC来保存。
一般来讲,一个位置区包含多个基站,一个基站对应一个或多个扇区,而一个扇区对应一个小区,但有时一个小区也可能由多个扇区组成。
3GPP2:
包含SID(System ID/系统ID)、NID(Network ID/网络ID)、BID(Base station ID/基站ID)、BS Longitude(基站经度)、BS Latitude(基站纬度),
一个System下面包含多个Network,而一个Network下面又有多个BS。
当查询voice注册状态时,返回的结果中就包含了CellLocation相关信息。
我们直接来看ServiceStateTracker中查询voice注册状态的地方,有如下2个:
public void handleMessage(Message msg) {
......
case EVENT_LOCATION_UPDATES_ENABLED:
ar = (AsyncResult) msg.obj;
if (ar.exception == null) {
mCi.getVoiceRegistrationState(obtainMessage(EVENT_GET_LOC_DONE, null));
}
break;
......
}
public void pollState(boolean modemTriggered) {
......
mCi.getVoiceRegistrationState(obtainMessage(EVENT_POLL_STATE_REGISTRATION,
mPollingContext));
......
}
先来看第一个,通过RIL返回查询结果后触发EVENT_GET_LOC_DONE消息,然后就直接通过Phone往上通知CellLocation改变。
public void handleMessage(Message msg) {
......
case EVENT_GET_LOC_DONE:
ar = (AsyncResult) msg.obj;
if (ar.exception == null) {
processCellLocationInfo(mCellLoc, (VoiceRegStateResult) ar.result);
mPhone.notifyLocationChanged();
}
......
}
再来看第二个查询voice注册状态的返回处理流程,触发EVENT_POLL_STATE_REGISTRATION消息,
public void handleMessage(Message msg) {
......
case EVENT_POLL_STATE_REGISTRATION:
......
handlePollStateResult(msg.what, ar);
......
}
处理查询结果,
protected void handlePollStateResult(int what, AsyncResult ar) {
......
if (ar.exception != null) {
......
} else try {
handlePollStateResultMessage(what, ar);
} catch (RuntimeException ex) {
......
}
mPollingContext[0]--;
if (mPollingContext[0] == 0) {
......
pollStateDone();
}
}
会先调用handlePollStateResultMessage()更新查询结果,
void handlePollStateResultMessage(int what, AsyncResult ar) {
int ints[];
switch (what) {
case EVENT_POLL_STATE_REGISTRATION: {
......
processCellLocationInfo(mNewCellLoc, voiceRegStateResult);
......
}
根据不同接入技术获取相应的CellLocation参数,并将结果更新到ServiceStateTracker.mNewCellLoc中。
private void processCellLocationInfo(CellLocation cellLocation,
VoiceRegStateResult voiceRegStateResult) {
if (mPhone.isPhoneTypeGsm()) {
......
switch(voiceRegStateResult.cellIdentity.cellInfoType) {
case CellInfoType.GSM: {
if (voiceRegStateResult.cellIdentity.cellIdentityGsm.size() == 1) {
android.hardware.radio.V1_0.CellIdentityGsm cellIdentityGsm =
voiceRegStateResult.cellIdentity.cellIdentityGsm.get(0);
cid = cellIdentityGsm.cid;
lac = cellIdentityGsm.lac;
}
break;
}
case CellInfoType.WCDMA: {
if (voiceRegStateResult.cellIdentity.cellIdentityWcdma.size() == 1) {
android.hardware.radio.V1_0.CellIdentityWcdma cellIdentityWcdma =
voiceRegStateResult.cellIdentity.cellIdentityWcdma.get(0);
cid = cellIdentityWcdma.cid;
lac = cellIdentityWcdma.lac;
psc = cellIdentityWcdma.psc;
}
break;
}
case CellInfoType.TD_SCDMA: {
if (voiceRegStateResult.cellIdentity.cellIdentityTdscdma.size() == 1) {
android.hardware.radio.V1_0.CellIdentityTdscdma
cellIdentityTdscdma =
voiceRegStateResult.cellIdentity.cellIdentityTdscdma.get(0);
cid = cellIdentityTdscdma.cid;
lac = cellIdentityTdscdma.lac;
}
break;
}
case CellInfoType.LTE: {
if (voiceRegStateResult.cellIdentity.cellIdentityLte.size() == 1) {
android.hardware.radio.V1_0.CellIdentityLte cellIdentityLte =
voiceRegStateResult.cellIdentity.cellIdentityLte.get(0);
cid = cellIdentityLte.ci;
/* Continuing the historical behaviour of using tac as lac. */
lac = cellIdentityLte.tac;
}
break;
}
default: {
break;
}
}
// LAC and CID are -1 if not avail
((GsmCellLocation) cellLocation).setLacAndCid(lac, cid);
((GsmCellLocation) cellLocation).setPsc(psc);
} else {
......
switch(voiceRegStateResult.cellIdentity.cellInfoType) {
case CellInfoType.CDMA: {
if (voiceRegStateResult.cellIdentity.cellIdentityCdma.size() == 1) {
android.hardware.radio.V1_0.CellIdentityCdma cellIdentityCdma =
voiceRegStateResult.cellIdentity.cellIdentityCdma.get(0);
baseStationId = cellIdentityCdma.baseStationId;
baseStationLatitude = cellIdentityCdma.latitude;
baseStationLongitude = cellIdentityCdma.longitude;
systemId = cellIdentityCdma.systemId;
networkId = cellIdentityCdma.networkId;
}
break;
}
default: {
break;
}
}
......
((CdmaCellLocation) cellLocation).setCellLocationData(baseStationId,
baseStationLatitude, baseStationLongitude, systemId, networkId);
}
}
再回到handlePollStateResult()中,更新完查询结果后继续调用pollStateDone(),
如果CellLocation和当前值不同,那就通过Phone发送通知,
这就与最开始处理EVENT_GET_LOC_DONE的流程相同了。
private void pollStateDone() {
......
boolean hasLocationChanged = !mNewCellLoc.equals(mCellLoc);
......
if (hasLocationChanged) {
mPhone.notifyLocationChanged();
}
......
}
GsmCdmaPhone中没有任何额外处理,继续向上通知。
public void notifyLocationChanged() {
mNotifier.notifyCellLocation(this);
}
然后来到DefaultPhoneNotifier中,继续通知TelephonyRegistry,
public void notifyCellLocation(Phone sender) {
......
mRegistry.notifyCellLocationForSubscriber(subId, data);
......
}
然后就在TelephonyRegistry中查询注册了LISTEN_CELL_LOCATION的对象,并进行回调。
public void notifyCellLocationForSubscriber(int subId, Bundle cellLocation) {
......
for (Record r : mRecords) {
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) &&
idMatch(r.subId, subId, phoneId)) {
......
r.callback.onCellLocationChanged(new Bundle(cellLocation));
......
}
通过搜索代码,发现共有如下2个地方注册监听了LISTEN_CELL_LOCATION事件。
一个是和紧急呼叫相关的,在手机启动及关闭飞行模式时进行监听。
EmergencyAffordanceService.java
public void onBootPhase(int phase) {
......
startScanning();
......
}
private BroadcastReceiver mAirplaneModeReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Settings.Global.getInt(context.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0) == 0) {
startScanning();
requestCellScan();
}
}
};
private void startScanning() {
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_INFO
| PhoneStateListener.LISTEN_CELL_LOCATION);
}
另一个就是在Settings中,
RadioInfo.java
protected void onResume() {
......
mTelephonyManager.listen(mPhoneStateListener,
......
| PhoneStateListener.LISTEN_CELL_LOCATION
......);
......
}
Detect languageAfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBengaliBosnianBulgarianCatalanCebuanoChichewaChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEsperantoEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekGujaratiHaitian CreoleHausaHebrewHindiHmongHungarianIcelandicIgboIndonesianIrishItalianJapaneseJavaneseKannadaKazakhKhmerKoreanLaoLatinLatvianLithuanianMacedonianMalagasyMalayMalayalamMalteseMaoriMarathiMongolianMyanmar (Burmese)NepaliNorwegianPersianPolishPortuguesePunjabiRomanianRussianSerbianSesothoSinhalaSlovakSlovenianSomaliSpanishSundaneseSwahiliSwedishTajikTamilTeluguThaiTurkishUkrainianUrduUzbekVietnameseWelshYiddishYorubaZulu |
| AfrikaansAlbanianArabicArmenianAzerbaijaniBasqueBelarusianBengaliBosnianBulgarianCatalanCebuanoChichewaChinese (Simplified)Chinese (Traditional)CroatianCzechDanishDutchEnglishEsperantoEstonianFilipinoFinnishFrenchGalicianGeorgianGermanGreekGujaratiHaitian CreoleHausaHebrewHindiHmongHungarianIcelandicIgboIndonesianIrishItalianJapaneseJavaneseKannadaKazakhKhmerKoreanLaoLatinLatvianLithuanianMacedonianMalagasyMalayMalayalamMalteseMaoriMarathiMongolianMyanmar (Burmese)NepaliNorwegianPersianPolishPortuguesePunjabiRomanianRussianSerbianSesothoSinhalaSlovakSlovenianSomaliSpanishSundaneseSwahiliSwedishTajikTamilTeluguThaiTurkishUkrainianUrduUzbekVietnameseWelshYiddishYorubaZulu |
|
|
|
|
|
| Options : History : Feedback : Donate | Close |