接上篇博文:Android7.0 Phone应用源码分析(一) phone拨号流程分析

今天我们再来分析下Android7.0 的phone的来电流程

1.1TelephonyFramework

当有来电通知时,首先接收到消息的是Modem层,然后Medoem再上传给RIL层,RIL进程通过sokcet将消息发送给RILJ(framework层的RIL),同样进入RILJ的processResponse方法,根据上一章节去电流程的分析得知,来电属于UnSolicited消息,事件ID是

RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,看看RILJ里的处理

com.android.internal.telephony.RIL
processUnsolicited (Parcel p, int type) {
………………………………
switch(response) {
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret = responseVoid(p);
        break;
………………………………
}
………………………………
switch(response) {
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
if (RILJ_LOGD) unsljLog(response);
mCallStateRegistrants .notifyRegistrants(new AsyncResult(null, null, null));
break;
………………………………
}
………………………………
}

mCallStateRegistrants是RegistrantList实例,这里用到了观察者模式,mCallStateRegistrants将call状态的变化通知给了所有感兴趣的注册者,BaseCommands提供了相关注册接口

com.android.internal.telephony. registerForCallStateChanged
@Override
public void registerForCallStateChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj); mCallStateRegistrants.add(r);
}
}

最后找到GsmCdmaCallTracker在创建的时候注册了该事件

com.android.internal.telephony. GsmCdmaCallTracker
public GsmCdmaCallTracker (GsmCdmaPhone phone) {
this.mPhone = phone;
mCi = phone.mCi;
mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
mCi.registerForOn(this, EVENT_RADIO_AVAILABLE, null);
mCi.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);
...... ...... }

收到EVENT_CALL_STATE_CHANGE消息后进入pollCallsWhenSafe方法

protected void pollCallsWhenSafe() {
mNeedsPoll = true; if (checkNoOperationsPending()) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
mCi.getCurrentCalls(mLastRelevantPoll);
}}
}

这里的处理流程跟之前拨号类似,同样是通过RILJ获取当前call状态,收到回应后进入handlePollCalls方法

protected synchronized void handlePollCalls(AsyncResult ar) {
………………………………
if (newRinging != null) { // 新来电通知
mPhone.notifyNewRingingConnection(newRinging);
}
………………………………
updatePhoneState(); // 更新phone状态
………………………………
if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) {
mPhone.notifyPreciseCallStateChanged(); // 发出call状态变化通知 }
}

新来电进入phone的notifyNewRingingConnection的方法

com.android.internal.telephony.Phone
public void notifyNewRingingConnectionP(Connection cn) {
if (!mIsVoiceCapable)
return;
AsyncResult ar = new AsyncResult(null, cn, null);
mNewRingingConnectionRegistrants.notifyRegistrants(ar);}
}

又是一个观察者模式,最后找到是注册了该事件的监听对象PstnIncomingCallNotifier

1.2TelephonyService

com.android.services.telephony. PstnIncomingCallNotifier
private void registerForNotifications() {
if (mPhone != null) {
Log.i(this, "Registering: %s", mPhone);
mPhone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
mPhone.registerForCallWaiting(mHandler, EVENT_CDMA_CALL_WAITING, null);
mPhone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null);
}
}

Handler处理消息进入handleNewRingingConnection方法

private void handleNewRingingConnection(AsyncResult asyncResult) {
Log.d(this, "handleNewRingingConnection");
Connection connection = (Connection) asyncResult.result;
if (connection != null) {
Call call = connection.getCall(); // Final verification of the ringing state before sending the intent to Telecom.
if (call != null && call.getState().isRinging()) {
sendIncomingCallIntent(connection);
}
}
}

获取到call对象以后,最后进入sendIncomingCallIntent

private void sendIncomingCallIntent(Connection connection) {
………………………………
PhoneAccountHandle handle = findCorrectPhoneAccountHandle();
if (handle == null) {
try {
connection.hangup();
} catch (CallStateException e) {
// connection already disconnected. Do nothing
}
} else {
TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras);
}
}

通过aidl接口调用telecomservice的的addNewIncomingCall方法

1.3 TelecomService

TelecomServiceImpl的成员变量mBinderImpl是具体实现类

com.android.server.telecom.TelecomServiceImpl
private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub(){
public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
………………………………
Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, true);
if (extras != null) {
extras.setDefusable(true);
intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
}
mCallIntentProcessorAdapter.processIncomingCallIntent(mCallsManager, intent); }
……………………………… }

这里调用到的是CallIntentProcessor 的processIncomingCallIntent方法

com.android.server.telecom. CallIntentProcessor
static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
………………………………
Log.d(CallIntentProcessor.class,
"Processing incoming call from connection service [%s]",
phoneAccountHandle.getComponentName());
callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
}

进入callsmanager的processIncomingCallIntent方法

void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
………………………………
Call call = new Call(
getNextCallId(),
mContext,
this,
mLock,
mConnectionServiceRepository,
mContactsAsyncHelper,
mCallerInfoAsyncQueryFactory,
handle,
null /* gatewayInfo */,
null /* connectionManagerPhoneAccount */,
phoneAccountHandle,
Call.CALL_DIRECTION_INCOMING /* callDirection */,
false /* forceAttachToExistingConnection */,
false /* isConference */
);
………………………………
call.addListener(this);
call.startCreateConnection(mPhoneAccountRegistrar);
}

走到这一步,跟之前分析的拨号流程一样,创建了一个call对象,然后调用

startCreateConnection创建连接,根据之前拨号的流程分析最后会进入 ConnectionService的createConnection方法

1.4 TelecommFramework

再把实现代码贴一遍:

private void createConnection(final PhoneAccountHandle callManagerAccount, final String callId, 
             final ConnectionRequest request,  boolean isIncoming,  boolean isUnknown) {
………………………………
Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
: isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
: onCreateOutgoingConnection(callManagerAccount, request);
              ………………………………
mAdapter.handleCreateConnectionComplete(
callId,
request,
new ParcelableConnection(
request.getAccountHandle(),
connection.getState(),
connection.getConnectionCapabilities(),
connection.getConnectionProperties(),
connection.getAddress(),
connection.getAddressPresentation(),
connection.getCallerDisplayName(),
connection.getCallerDisplayNamePresentation(),
connection.getVideoProvider() == null ?
null : connection.getVideoProvider().getInterface(),
connection.getVideoState(),
connection.isRingbackRequested(),
connection.getAudioModeIsVoip(),
connection.getConnectTimeMillis(),
connection.getStatusHints(),
connection.getDisconnectCause(),
createIdList(connection.getConferenceables()),
connection.getExtras(),
connection.getUserData()));//MOTO Calling Code - IKPIM-1774 (ftr 33860)
if (isUnknown) {
triggerConferenceRecalculate();
}
}

这里由于是来电,所以调用onCreateIncomingConnection方法,该方法同样返回null,所以具体是由其子类实现的,也就是TelephonyConnectionService

public Connection onCreateIncomingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
ConnectionRequest request) { Connection connection = createConnectionFor(phone, originalConnection, false /* isOutgoing */,
request.getAccountHandle(), request.getTelecomCallId(),
request.getAddress());
if (connection == null) {
return Connection.createCanceledConnection();
} else {
return connection;
}
}

最后根据GMS或是CDMA返回对应Connection对象,最后进入ConnectionServiceAdapter处理

android.telecom. ConnectionServiceAdapter
void handleCreateConnectionComplete(
String id,
ConnectionRequest request,
ParcelableConnection connection) {
for (IConnectionServiceAdapter adapter : mAdapters) {
try {
adapter.handleCreateConnectionComplete(id, request, connection);
} catch (RemoteException e) {
}
}
}

这里的adapter实际上就是ConnectionServiceWrapper的内部类Adapter,需要注意的是之前拨号的时候创建完connection并呼出之后,后续也会走到这个流程里

public void handleCreateConnectionComplete(String callId, ConnectionRequest request,
ParcelableConnection connection) {
Log.startSession("CSW.hCCC");
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
logIncoming("handleCreateConnectionComplete %s", callId);
ConnectionServiceWrapper.this
handleCreateConnectionComplete(callId, request, connection);
}
} finally {
Binder.restoreCallingIdentity(token);
Log.endSession();
}
}

最后进入handleCreateConnectionComplete方法

private void handleCreateConnectionComplete(
String callId,
ConnectionRequest request,
ParcelableConnection connection) {
// TODO: Note we are not using parameter "request", which is a side effect of our tacit
// assumption that we have at most one outgoing connection attempt per ConnectionService.
// This may not continue to be the case.
if (connection.getState() == Connection.STATE_DISCONNECTED) {
// A connection that begins in the DISCONNECTED state is an indication of
// failure to connect; we handle all failures uniformly
removeCall(callId, connection.getDisconnectCause());
} else {
// Successful connection
if (mPendingResponses.containsKey(callId)) {
mPendingResponses.remove(callId).handleCreateConnectionSuccess(mCallIdMapper, connection);
}
}
}

这里的mPendingResponses是map容器

private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();

ConnectionServiceWrapper在调用createConnection的时候会往该容器里添加对象,也就是CreateConnectionProcessor对象

public void handleCreateConnectionSuccess(
CallIdMapper idMapper,
ParcelableConnection connection) {
if (mCallResponse == null) {
// Nobody is listening for this connection attempt any longer; ask the responsible
// ConnectionService to tear down any resources associated with the call
mService.abort(mCall);
} else {
// Success -- share the good news and remember that we are no longer interested
// in hearing about any more attempts
mCallResponse.handleCreateConnectionSuccess(idMapper, connection);
mCallResponse = null;
// If there's a timeout running then don't clear it. The timeout can be triggered
// after the call has successfully been created but before it has become active.
}
}

这个mCallResponse是CreateConnectionProcessor创建的时候引入的,也就是call对象

com.android.server.telecom.Call
public void handleCreateConnectionSuccess(
CallIdMapper idMapper,
ParcelableConnection connection) { switch (mCallDirection) {
case CALL_DIRECTION_INCOMING: for (Listener l : mListeners) {
l.onSuccessfulIncomingCall(this);
}
break;
case CALL_DIRECTION_OUTGOING:
for (Listener l : mListeners) {
l.onSuccessfulOutgoingCall(this,
getStateFromConnectionState(connection.getState()));
}
break;
case CALL_DIRECTION_UNKNOWN:
for (Listener l : mListeners) {
l.onSuccessfulUnknownCall(this, getStateFromConnectionState(connection .getState()));
}
break;
}
}

这里根据是来电还是去电类型,执行相应回调,监听者会收到通知,来电事件则触发onSuccessfulIncomingCall的回调

1.5 TelecommService

前面提到CallsManager在执行processIncomingCallIntent方法时候会创建call,之后就会给call添加监听,所以最后会回调到CallsManager类

public void onSuccessfulIncomingCall(Call incomingCall) {
Log.d(this, "onSuccessfulIncomingCall");
List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();
filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));
filters.add(new

AsyncBlockCheckFilter

(mContext, new BlockCheckerAdapter()));
filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar,
mDefaultDialerManagerAdapter,
new ParcelableCallUtils.Converter(), mLock));
new

IncomingCallFilter

(mContext, this, incomingCall, mLock,
mTimeoutsAdapter, filters).performFiltering();
}

这里用到了一个迭代器模式,一个来电操作触发这三个对象的处理:

DirectToVoicemailCallFilter,AsyncBlockCheckFilter,CallScreeningServiceFilter

生成一个IncomingCallFilter对象,调用performFiltering方法

com.android.server.telecom.callfiltering. IncomingCallFilter
public void performFiltering() {
Log.event(mCall, Log.Events.FILTERING_INITIATED);
for (CallFilter filter : mFilters) {
filter.startFilterLookup(mCall, this);
}
mHandler.postDelayed(new Runnable("ICF.pFTO") { // performFiltering time-out
@Override
public void loggedRun() {
// synchronized to prevent a race on mResult and to enter into Telecom.
synchronized (mTelecomLock) {
if (mIsPending) {
Log.i(IncomingCallFilter.this, "Call filtering has timed out.");
Log.event(mCall, Log.Events.FILTERING_TIMED_OUT);
mListener.onCallFilteringComplete(mCall, mResult);
mIsPending = false;
}
}
}
}.prepare(), mTimeoutsAdapter.getCallScreeningTimeoutMillis(mContext.getContentResolver()));
}

他们依次执行startFilterLookup异步查询方法,通过回调方法并将结果CallFilteringResult传回onCallFilteringComplete将CallFilteringResult对象传递回来

public class CallFilteringResult {

    public boolean shouldAllowCall;          // 是否允许通话
public boolean shouldReject; // 是否拒接
public boolean shouldAddToCallLog; // 是否添加至通话记
public boolean shouldShowNotification; // 是否显示通知栏消息
………………………………
………………………………
} public void onCallFilteringComplete(Call call, CallFilteringResult result) {
synchronized (mTelecomLock) { // synchronizing to prevent race on mResult
mNumPendingFilters--;
mResult = result.combine(mResult);
if (mNumPendingFilters == 0) {
mHandler.post(new Runnable("ICF.oCFC") {
@Override
public void loggedRun() {
// synchronized to enter into Telecom.
synchronized (mTelecomLock) {
if (mIsPending) {
mListener.onCallFilteringComplete(mCall, mResult);
mIsPending = false;
}
}
}
}.prepare());
}
}
}

先看看DirectToVoicemailCallFilter对象,它处理的是voicemail相关信息,

实际上是由CallerInfoLookupHelper完成查询的,内部调用CallerInfoAsyncQueryFactory的startQuery方法,而CallerInfoAsyncQueryFactory是个接口类,在CallsManager创建的时候由外部传参进来,最后找到是TelecomService的initializeTelecomSystem里创建的

com.android.server.telecom.components. TelecomService
static void initializeTelecomSystem(Context context) {
new CallerInfoAsyncQueryFactory() {
@Override
public CallerInfoAsyncQuery startQuery(
int token, Context context, String number,
CallerInfoAsyncQuery.OnQueryCompleteListener listener,
Object cookie) {
Log.i(TelecomSystem.getInstance(),
"CallerInfoAsyncQuery.startQuery number=%s cookie=%s",
Log.pii(number), cookie);
return CallerInfoAsyncQuery.startQuery(
token, context, number, listener, cookie);
}
}

进入CallerInfoAsyncQuery的startQuery方法

com.android.internal.telephony.CallerInfoAsyncQuery
public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
OnQueryCompleteListener listener, Object cookie, int subId) { final Uri contactRef = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
.appendPath(number)
.appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS,
String.valueOf(PhoneNumberUtils.isUriNumber(number)))
.build();
}

查询的uri是PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI

返回cursor结果集后转化成CallerInfo,其中shouldSendToVoicemail变量查询的

是PhoneLookup.SEND_TO_VOICEMAIL字段

public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) {
...... ......
...... ......
columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL);
info.shouldSendToVoicemail = (columnIndex != -1) &&
((cursor.getInt(columnIndex)) == 1);
info.contactExists = true;
...... ......
}

最后回到DirectToVoicemailCallFilter的查询回调,shouldSendToVoicemail为true时表示允许通话,否则是拒接

if (info.shouldSendToVoicemail) {
result = new CallFilteringResult(
false, // shouldAllowCall
true, // shouldReject
true, // shouldAddToCallLog
true // shouldShowNotification
);
} else {
result = new CallFilteringResult(
true, // shouldAllowCall
false, // shouldReject
true, // shouldAddToCallLog
true // shouldShowNotification
);
}
}

再看看AsyncBlockCheckFilter,它处理的是黑名单事件

判断一个电话号码是否在黑名单里调用到了BlockChecker的isBlocked方法

com.android.internal.telephony. BlockChecker
public static boolean isBlocked(Context context, String phoneNumber) {
boolean isBlocked = false;
long startTimeNano = System.nanoTime(); try {
if (BlockedNumberContract.SystemContract.shouldSystemBlockNumber(
context, phoneNumber)) {
Rlog.d(TAG, phoneNumber + " is blocked.");
isBlocked = true;
}
} catch (Exception e) {
Rlog.e(TAG, "Exception checking for blocked number: " + e);
} int durationMillis = (int) ((System.nanoTime() - startTimeNano) / 1000000);
if (durationMillis > 500 || VDBG) {
Rlog.d(TAG, "Blocked number lookup took: " + durationMillis + " ms.");
}
return isBlocked;
}

BlockedNumberContract.SystemContract是framework里的一个黑名单协议类

public static final String AUTHORITY = "com.android.blockednumber";
public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER =
"should_system_block_number"; public static boolean shouldSystemBlockNumber(Context context, String phoneNumber) {
final Bundle res = context.getContentResolver().call(
AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, null);
return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
}

黑名单是BlockedNumberProvider数据库, 调用call方法

com.android.providers.blockednumber. BlockedNumberProvider
@Override
public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
final Bundle res = new Bundle();
switch (method) {
case SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER:
enforceSystemReadPermissionAndPrimaryUser();
res.putBoolean(
BlockedNumberContract.RES_NUMBER_IS_BLOCKED, shouldSystemBlockNumber(arg));
break;
............
............
} } private boolean shouldSystemBlockNumber(String phoneNumber) {
if (getBlockSuppressionStatus().isSuppressed) {
return false;
}
if (isEmergencyNumber(phoneNumber)) {
return false;
} return isBlocked(phoneNumber);
}

最后调用isBlocked方法查询blocked表中是否存在该number

查询得到结果后返回

CallFilteringResult result;
if (isBlocked) {
result = new CallFilteringResult(
false, // shouldAllowCall
true, //shouldReject
false, //shouldAddToCallLog
false // shouldShowNotification
);
} else {
result = new CallFilteringResult(
true, // shouldAllowCall
false, // shouldReject
true, // shouldAddToCallLog
true // shouldShowNotification
);
}

如果号码在黑名单里则拦截

最后是CallScreeningServiceFilter不知道是处理什么,内部绑定一个抽象服务

CallScreeningService但是却找不到哪个子类继承了它,这里先忽略它

回到前面IncomingCallFilter的onCallFilteringCompletev方法,结果集会做个逻辑运算

mResult = result.combine(mResult);看看它的实现

com.android.server.telecom.callfilteringCallFilteringResult
public CallFilteringResult combine(CallFilteringResult other) {
if (other == null) {
return this;
} return new CallFilteringResult(
shouldAllowCall && other.shouldAllowCall,
shouldReject || other.shouldReject,
shouldAddToCallLog && other.shouldAddToCallLog,
shouldShowNotification && other.shouldShowNotification);
}

只有三个过滤结果都是允许通话才允许通话,添加至通话记录以及是否显示到通知栏同理

当然这里的查询操作也有超时限制,时间是5秒,超过5秒后忽略还未查询到的过滤器则被忽略mTimeoutsAdapter.getCallScreeningTimeoutMillis(mContext.getContentResolver()));

最后过滤结果被回调到CallsManager的onCallFilteringComplete

public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) {
………………………………
if (incomingCall.getState() != CallState.DISCONNECTED &&
incomingCall.getState() != CallState.DISCONNECTING) {
setCallState(incomingCall, CallState.RINGING,
result.shouldAllowCall

? "successful incoming call" : "blocking call"

);
} else {
Log.i(this, "onCallFilteringCompleted: call already disconnected.");
} if (result.shouldAllowCall) {
if (hasMaximumRingingCalls()) {
rejectCallAndLog(incomingCall);
} else if (hasMaximumDialingCalls()) {
rejectCallAndLog(incomingCall);
} else {
addCall(incomingCall);
}
} else {
if (result.shouldReject) {
incomingCall.reject(false, null);
}
if (result.shouldAddToCallLog) { mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE,
result.shouldShowNotification);
} else if (result.shouldShowNotification) { mMissedCallNotifier.showMissedCallNotification(incomingCall);
}
}
}

调用setCallState设置通话状态为CallState.RINGING,接着判断是否拒接,是否写入通话记录等, 正常情况下调用addCall方法

private void addCall(Call call) {
………………………………
updateCallsManagerState();
// onCallAdded for calls which immediately take the foreground (like the first call).
for (CallsManagerListener listener : mListeners) {
if (Log.SYSTRACE_DEBUG) {
Trace.beginSection(listener.getClass().toString() + " addCall");
}
listener.onCallAdded(call);
if (Log.SYSTRACE_DEBUG) {
Trace.endSection();
}
}
Trace.endSection();
}

遍历回调监听者的onCallAdded方法,InCallController是其中一个观察者,看看它的实现

com.android.server.telecom. InCallController
@Override
public void onCallAdded(Call call) {
if (!isBoundToServices()) {
bindToServices(call);
} else {
adjustServiceBindingsForEmergency();
Log.i(this, "onCallAdded: %s", call);
// Track the call if we don't already know about it.
addCall(call);
for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
ComponentName componentName = entry.getKey();
IInCallService inCallService = entry.getValue();
ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
true,mCallsManager.getPhoneAccountRegistrar());
try {
inCallService.addCall(parcelableCall);
} catch (RemoteException ignored) {
}
}
}
}

这里的inCallService是个aidl接口,抽象服务InCallService的嵌套类InCallServiceBinder 实现了该接口

1.6 TelecommFramework

android.telecom. InCallService
private final class InCallServiceBinder extends IInCallService.Stub {
@Override
public void addCall(ParcelableCall call) {
mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
}
...... ......
...... ......
}

handle对象处理消息MSG_ADD_CALL

private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
case MSG_ADD_CALL:
mPhone.internalAddCall((ParcelableCall) msg.obj);
break;
}
} candroid.telecom.Phone
final void internalAddCall(ParcelableCall parcelableCall) {
Call call

= new Call(this

, parcelableCall.getId(), mInCallAdapter,
parcelableCall.getState());
mCallByTelecomCallId.put(parcelableCall.getId(), call);
mCalls.add(call);
checkCallTree(parcelableCall);
call.internalUpdate(parcelableCall, mCallByTelecomCallId);
fireCallAdded(call);
} private void fireCallAdded(Call call) {
for (Listener listener : mListeners) {
listener.onCallAdded(this, call);
}
}

mPhone对象内部新建了一个call对象,获取并转化ParcelableCall的相关信息,并将call对象加入列表,最后回调Phone的监听者的onCallAdded方法,这里就是InCallService的

mPhoneListener成员变量

private Phone.Listener mPhoneListener = new Phone.Listener() {
/** ${inheritDoc} */
...... ...... /** ${inheritDoc} */
@Override
public void onCallAdded(Phone phone, Call call) {
InCallService.this.onCallAdded(call);
}
...... ......
};

这里InCallService的onCallAdded方法是一个抽象方法,具体实现在它的子类

1.7 Dialer

InCallServiceImpl继承了InCallService,该服务在Dialer工程的manifest文件里有声明

<service android:name="com.android.incallui.InCallServiceImpl"
android:permission="android.permission.BIND_INCALL_SERVICE"
android:directBootAware="true" >
<meta-data android:name="android.telecom.IN_CALL_SERVICE_UI"
android:value="true" />
<meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
android:value="false"/>
<intent-filter>
<action android:name="

android.telecom.InCallService

"/>
</intent-filter>
</service>

看看InCallServiceImpl的onCallAdded方法

com.android.incallui. InCallServiceImpl
@Override
public void onCallAdded(Call call) {
InCallPresenter.getInstance().onCallAdded(call);
}

InCallPresenter是incallui用于处理通话逻辑的核心类,内部就是各种业务逻辑操作,看看onCallAdded方法

com.android.incallui. InCallPresenter
public void onCallAdded(final android.telecom.Call call) {
if (shouldAttemptBlocking(call)) {
maybeBlockCall(call);
} else {
mCallList.onCallAdded(call);
} // Since a call has been added we are no longer waiting for Telecom to send us a call.
setBoundAndWaitingForOutgoingCall(false, null);
call.registerCallback(mCallCallback);
}

mCallList维护了call列表

com.android.incallui.CallList
public void onCallAdded(final android.telecom.Call telecomCall) {
Trace.beginSection("onCallAdded");
final Call call = new Call(telecomCall);
Log.d(this, "onCallAdded: callState=" + call.getState()); if (call.getState() == Call.State.INCOMING ||
call.getState() == Call.State.CALL_WAITING) {
onIncoming(call, call.getCannedSmsResponses());
} else {
onUpdate(call);
} call.logCallInitiationType();
Trace.endSection();
}

来电则调用onIncoming方法,其它call状态则调用onUpdate方法,具体过程这里就不详述了,最终incallui拉起来电界面显示,至此,一个来电的整体流程都分析完了,大致流程如下:

RIL→TelephonyFramework →TeleponyService→ TeleComService→

TeleComFramework→ TeleComService→TeleComFramework-->InCallUI

下一章节:Android7.0 Phone应用源码分析(三) phone拒接流程分析

Android7.0 Phone应用源码分析(二) phone来电流程分析的更多相关文章

  1. Android7.0 Phone应用源码分析(一) phone拨号流程分析

    1.1 dialer拨号 拨号盘点击拨号DialpadFragment的onClick方法会被调用 public void onClick(View view) { int resId = view. ...

  2. Android7.0 Phone应用源码分析(三) phone拒接流程分析

    本文主要分析Android拒接电话的流程,下面先来看一下拒接电话流程时序图 步骤1:滑动按钮到拒接图标,会调用到AnswerFragment的onDecline方法 com.android.incal ...

  3. Android7.0 Phone应用源码分析(四) phone挂断流程分析

    电话挂断分为本地挂断和远程挂断,下面我们就针对这两种情况各做分析 先来看下本地挂断电话的时序图: 步骤1:点击通话界面的挂断按钮,会调用到CallCardPresenter的endCallClicke ...

  4. spring-boot-2.0.3启动源码篇二 - run方法(一)之SpringApplicationRunListener

    前言 Springboot启动源码系列还只写了一篇,已经过去一周,又到了每周一更的时间了(是不是很熟悉?),大家有没有很期待了?我会尽量保证启动源码系列每周一更,争取不让大家每周的期望落空.一周之中可 ...

  5. Android7.0 拨号盘应用源码分析(一) 界面浅析

    前言 android拨号盘的源码目录在package/app/Dialer 自7.0以后Incallui的源码直接放到了Dialer目录下,虽然在7.0以前incallui有自己独立的目录,但实际编译 ...

  6. spring-boot-2.0.3启动源码篇 - 阶段总结

    前言 开心一刻 朋友喜欢去按摩,第一次推门进来的是一个学生美眉,感觉还不错:后来经常去,有时是护士,有时是空姐,有时候是教师.昨天晚上推门进去的是一个女警察,长得贼好看,身材也很好,朋友嗷的一声就扑上 ...

  7. Solr4.8.0源码分析(5)之查询流程分析总述

    Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilt ...

  8. 如何分析SpringBoot源码模块及结构?--SpringBoot源码(二)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 前言 本篇接 如何搭建自己的SpringBoot源码调试环境?--SpringBoot源码(一). 前面搭建好了自己本地的S ...

  9. Dubbo源码学习(二)

    @Adaptive注解 在上一篇ExtensionLoader的博客中记录了,有两种扩展点,一种是普通的扩展实现,另一种就是自适应的扩展点,即@Adaptive注解的实现类. @Documented ...

随机推荐

  1. _set_invalid_parameter_handler异常处理函数

    VS2005之后的版本,微软增加了一些新的异常机制,新机制在出现错误时默认不通知应用程序,这时程序就崩溃了.所以这种情况下,必须调用_set_invalid_parameter_handler._se ...

  2. linux 多台 主机的免登录ssh的配置

    1.首先检查 有没有安装ssh rpm-qa | grep ssh 如果没有安装 yum install ssh 2.在每一台机器上执行  ssh-keygen -t rsa  会在root/.ssh ...

  3. Hadoop入门进阶课程1--Hadoop1.X伪分布式安装

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,博主为石山园,博客地址为 http://www.cnblogs.com/shishanyuan  ...

  4. python函数式编程

    函数式编程是使用一系列函数去解决问题,按照一般编程思维,面对问题时我们的思考方式是“怎么干”,而函数函数式编程的思考方式是我要“干什么”. 至于函数式编程的特点暂不总结,我们直接拿例子来体会什么是函数 ...

  5. Tiff – 值得你体验一下的可视化的字体对比工具

    Tiff 是一款字体对比工具,可视化对比两种字体之间的差异.这是一个工具来帮助比较两种字体,同时学习排版.在这一点上,谷歌 Web 字体作为 Tiff 外部字体文件的唯一来源.由于应用程序使用的一些功 ...

  6. mysql-5.6.14-winx64免安装配置

    MySQL5.6.11安装步骤(Windows7 64位) 1. 下载MySQL Community Server 5.6.14 2. 解压MySQL压缩包 将以下载的MySQL压缩包解压到自定义目录 ...

  7. Spring重点—— IOC 容器中 Bean 的生命周期

    一.理解 Bean 的生命周期,对学习 Spring 的整个运行流程有极大的帮助. 二.在 IOC 容器中,Bean 的生命周期由 Spring IOC 容器进行管理. 三.在没有添加后置处理器的情况 ...

  8. Gradle学习系列之四——增量式构建

    在本系列的上篇文章中,我们讲到了如何读懂Gradle的语法,在本篇文章中,我们将讲到增量式地构建项目. 请通过以下方式下载本系列文章的Github示例代码: git clone https://git ...

  9. 订餐APP第二次sprint+燃尽图

    MY-HR 成员: 角色分配 学号 博客园 团队贡献分 围观其他小组评论 丘惠敏 PM项目经理 201406114203 http://www.cnblogs.com/qiuhuimin/ 21 ht ...

  10. DecimalFormat 中的 # 与 0 的区别(中文帮助文档中翻译可能是错误的)

    想对数字进行格式化的时候,可能会使用到 java.text.DecimalFormat 类.中文帮助文档中,有如下符号 位置 本地化 含义 0 数字 是 阿拉伯数字 # 数字 是 阿拉伯数字,如果不存 ...