一、概要
无论是在MT (Mobile Termination Call被叫——来电),还是MO (Mobile Origination Call主叫——去电) 流程中,通话界面上都会显示当前通话的名称( 后文以displayName指代 )。通常情况下,如果是一个陌生号码,则会显示为该陌生号码。如果是已知联系人,则会显示该联系人的名称。当然,在会议电话( Conference Call )的情况下则直接显示”会议电话”。但是,在某些特殊情况下,displayName还会显示诸如”私人号码”、”公用电话”、”未知号码”等。
本文主要分析displayName的获取显示流程及显示”未知号码”的原因
二、查询流程
1、开始查询——CallCardPresenter
displayName是隶属于CallCardFragment的控件,当通话MO/MT流程发起时InCallActivity会显示,此时将会触发CallCardFragment界面更新,在CallCardPresenter的init方法中查询displayName,关键代码如下:
CallCardPresenter.java (\packages\apps\incallui\src\com\android\incallui)
public void init(Context context, Call call) {
// Call may be null if disconnect happened already.
if (call != null) {
mPrimary = call;
// start processing lookups right away.
if (!call.isConferenceCall()) {
startContactInfoSearch(call, CallEnum.PRIMARY, call.getState() == Call.State.INCOMING);
} else {
/// M: Modified this for MTK DSDA feature. @{
/* Google Code:
updateContactEntry(null, true);
*/
updateContactEntry(null, CallEnum.PRIMARY, true);
/// @}
}
}
}
startContactInfoSearch的具体代码如下:
/**
* Starts a query for more contact data for the save primary and secondary calls.
*/
private void startContactInfoSearch(final Call call, CallEnum type,
boolean isIncoming) {
final ContactInfoCache cache = ContactInfoCache.getInstance(mContext);
// ContactInfoCache中开始查找
cache.findInfo(call, isIncoming, new ContactLookupCallback(this, type));
}
2、异步查询——ContactInfoCache
在CallCardPresenter中发起查询之后会跳转到ContactInfoCache.findInfo()方法中,ContactInfoCache不仅用于查询当前通话的相关信息,还可以将这些信息缓存以备下次查询相同信息时快速返回。findInfo关键代码如下:
/**
* Requests contact data for the Call object passed in.
* Returns the data through callback. If callback is null, no response is made, however the
* query is still performed and cached.
*
* @param callback The function to call back when the call is found. Can be null.
*/
public void findInfo(final Call call, final boolean isIncoming,
ContactInfoCacheCallback callback) {
// 查询caller信息,完成之后会回调到FindInfoCallback中,会调用findInfoQueryComplete
final CallerInfo callerInfo = CallerInfoUtils.getCallerInfoForCall(
mContext, call, new FindInfoCallback(isIncoming));
// 当查询完毕之后回调并更新ContactEntry,这里最终会去更新界面显示
findInfoQueryComplete(call, callerInfo, isIncoming, false);
}
CallerInfo中包含了当前call的基本信息,比如号码、类型、特殊相关服务等,在获取到这些信息之后再进行进一步的联系人数据库查询。
3、获取CallerInfo——CallerInfoUtils
在getCallerInfoForCall()方法中,除了获取当前Call的基本信息之外,还会根据当前Call的phoneNumber去数据库中查询,关键代码如下:
ContactInfoCache.java (\packages\apps\incallui\src\com\android\incallui)
/**
* This is called to get caller info for a call. This will return a CallerInfo
* object immediately based off information in the call, but
* more information is returned to the OnQueryCompleteListener (which contains
* information about the phone number label, user's name, etc).
*/
public static CallerInfo getCallerInfoForCall(Context context, Call call,
CallerInfoAsyncQuery.OnQueryCompleteListener listener) {
// 获取当前Call的基本信息并创建CallerInfo对象
CallerInfo info = buildCallerInfo(context, call);
// 根据phoneNumber在CallerInfoAsyncQuery中开启具体查询
if (info.numberPresentation == TelecomManager.PRESENTATION_ALLOWED) {
// Start the query with the number provided from the call.
Log.d(TAG, "==> Actually starting CallerInfoAsyncQuery.startQuery()...");
CallerInfoAsyncQuery.startQuery(QUERY_TOKEN, context, info, listener, call);
}
return info;
}
在以上代码中,有两个重要的方法,即buildCallerInfo()和CallerInfoAsyncQuery.startQuery(),先查询看buildCallerInfo()的关键代码:
public static CallerInfo buildCallerInfo(Context context, Call call) {
CallerInfo info = new CallerInfo();
// Store CNAP information retrieved from the Connection (we want to do this
// here regardless of whether the number is empty or not).
// 获取当前Call的CNAP name
info.cnapName = call.getCnapName();
info.name = info.cnapName;
info.numberPresentation = call.getNumberPresentation();
info.namePresentation = call.getCnapNamePresentation();
String numbe