前置文章:
《 Android 4.4 Kitkat Phone工作流程浅析(一)__概要和学习计划》《Android 4.4 Kitkat Phone工作流程浅析(二)__UI结构分析》
《Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析》
《Android 4.4 Kitkat Phone工作流程浅析(四)__RILJ工作流程简析》
《Android 4.4 Kitkat Phone工作流程浅析(五)__MT(来电)流程分析》
《Android 4.4 Kitkat Phone工作流程浅析(六)__InCallActivity显示更新流程》
《Android 4.4 Kitkat Phone工作流程浅析(七)__来电(MT)响铃流程》
《Android 4.4 Kitkat Phone工作流程浅析(八)__Phone状态分析》
《Android 4.4 Kitkat Phone工作流程浅析(九)__状态通知流程分析》
概要
无论是在MT (Mobile Termination Call被叫——来电),还是MO (Mobile Origination Call主叫——去电) 流程中,通话界面上都会显示当前通话的名称( 后文以displayName指代 )。通常情况下,如果是一个陌生号码,则会显示为该陌生号码。如果是已知联系人,则会显示该联系人的名称。当然,在会议电话( Conference Call )的情况下则直接显示"会议电话"。但是,在某些特殊情况下,displayName还会显示诸如"私人号码"、"公用电话"、"未知号码"等。
本文主要分析displayName的获取显示流程及显示"未知号码"的原因,如图1:
图 1 通话界面显示Unknown
查询流程
开始查询——CallCardPresenter
displayName是隶属于CallCardFragment的控件,当通话MO/MT流程发起时InCallActivity会显示,此时将会触发CallCardFragment界面更新,在CallCardPresenter的init方法中查询displayName,关键代码如下:
public void init(Context context, Call call) {
//... ...省略
if (call != null) {
mPrimary = call;
final CallIdentification identification = call.getIdentification();
// start processing lookups right away.
if (!call.isConferenceCall()) {
//... ...如果不是ConferenceCall就执行
startContactInfoSearch(identification, PRIMARY,
call.getState() == Call.State.INCOMING);
} else {
//... ..如果是ConferenceCall则执行
updateContactEntry(null, PRIMARY, true);
}
}
}
startContactInfoSearch的具体代码如下:
private void startContactInfoSearch(final CallIdentification identification,
final boolean isPrimary, boolean isIncoming) {
final int type, boolean isIncoming) {
final ContactInfoCache cache = ContactInfoCache.getInstance(mContext);
// ContactInfoCache中开始查找
cache.findInfo(identification, isIncoming, new ContactInfoCacheCallback() {
@Override
public void onContactInfoComplete(int callId, ContactCacheEntry entry) {
// 当查询完毕之后回调并更新ContactEntry,这里最终会去更新界面显示
updateContactEntry(entry, type, false);
if (entry.name != null) {
Log.d(TAG, "Contact found: " + entry);
}
if (entry.personUri != null) {
CallerInfoUtils.sendViewNotification(mContext, entry.personUri);
}
}
@Override
public void onImageLoadComplete(int callId, ContactCacheEntry entry) {
if (getUi() == null) {
return;
}
if (entry.photo != null) {
if (mPrimary != null && callId == mPrimary.getCallId()) {
// 设置第一路通话头像
getUi().setPrimaryImage(entry.photo);
} else if (mSecondary != null && callId == mSecondary.getCallId()) {
// 设置第二路通话头像
getUi().setSecondaryImage(entry.photo);
}
}
}
});
}
异步查询——ContactInfoCache
在CallCardPresenter中发起查询之后会跳转到ContactInfoCache.findInfo()方法中,ContactInfoCache不仅用于查询当前通话的相关信息,还可以将这些信息缓存以备下次查询相同信息时快速返回。findInfo关键代码如下:
public void findInfo(final CallIdentification identification, final boolean isIncoming,
ContactInfoCacheCallback callback) {
//... ...省略
// 查询caller信息,完成之后会回调到FindInfoCallback中,会调用findInfoQueryComplete
final CallerInfo callerInfo = CallerInfoUtils.getCallerInfoForCall(
mContext, identification, new FindInfoCallback(isIncoming));
if(!mExpiredInfoMap.containsKey(callId)) {
// 查询信息完成之后执行
findInfoQueryComplete(identification, callerInfo, isIncoming, false);
}
}
CallerInfo中包含了当前call的基本信息,比如号码、类型、特殊相关服务等,在获取到这些信息之后再进行进一步的联系人数据库查询。
获取CallerInfo——CallerInfoUtils
在getCallerInfoForCall()方法中,除了获取当前Call的基本信息之外,还会根据当前Call的phoneNumber去数据库中查询,关键代码如下:public static CallerInfo getCallerInfoForCall(Context context, CallIdentification c