这段负责通话模块的开发,研究了一下telephony模块,网上参考了些资料加上自己的理解,总结了一下android6.0 MT 流程:。
先放出6.0的MT(来电)时序图大家有个直观感受,下面代码一步步进行分析
作用:RIL-Java在本质上就是一个RIL代理,起到一个转发的作用,是Android Java概念空间中的电话系统的起点。
RIL接收到RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED消息
private void processUnsolicited (Parcel p) {
...
switch(response) {
...
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
if (RILJ_LOGD) unsljLog(response);
2、然后经由mCallStateRegistrants.notifyRegistrants发出通知
mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
BaseCommands.java registerForCallStateChanged() mCallStateRegistrants.add®;
@Override
public void registerForCallStateChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
//添加到观察者列表
mCallStateRegistrants.add(r);
}
**重点1:**这其实是观察者模式的一种实现形式
1.RegistrantList 通知者 2.Registrant 观察者,这是一个一对多的关系,在有事件更新时,凡是在名单上登记过的对象,都会收到通知。
RegistrantList通知者支持对通知者的增加(add/addUnique)删除(remove),并且能够发出通知(notifyRegitrants);而Registrant作为观察者,响应通知者发出的notifyRegistrant通知。
整体上这个消息注册机制分为两部分,消息注册和消息通知。当调用regist方法时将Message存放进去,当其调用notify方法时将所有Message取出并发送到MessageQueue中等待处理。
作用:GSMCallTracker在本质上是一个Handler。GSMCallTracker是Android的通话管理层。GSMCallTracker建立了ConnectionList来管理现行的通话连接,并向上层提供电话调用接口。
查找察者被调用的地方, 两处被响应处理处理,其中一处:GSMCallTracker handleMessage
...//registerForCallStateChanged调用
mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
...
@Override
public void
//响应处理
handleMessage (Message msg) {
...
case EVENT_CALL_STATE_CHANGE: //MT第一次
//调用父类CallTracker查询Call List方法
pollCallsWhenSafe();
break;
protected void pollCallsWhenSafe() {
mNeedsPoll = true;
if (checkNoOperationsPending()) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
5、 //RIL.java中的getCurrentCalls方法
mCi.getCurrentCalls(mLastRelevantPoll);
}
}
回到RIL.java getCurrentCalls 将RIL_REQUEST_GET_CURRENT_CALLS 消息封装成RILRequest
类型并发送。
@Override
public void getCurrentCalls (Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
send(rr);
}
RIL.java 有三处接收处理RIL_REQUEST_GET_CURRENT_CALLS消息,真正的逻辑处理在processSolicited方法
private RILRequest processSolicited (Parcel p) {
...
case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break;
...
if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, ret, null);
rr.mResult.sendToTarget();//发出handler消息通知
}
rr.mResult.sendToTarget()发出handler消息通知后,会在GSMCallTracker中的handleMessage方法中响应。并且它的消息类型是“EVENT_POLL_CALLS_RESULT"
@Override
public void handleMessage (Message msg) {
...
case EVENT_POLL_CALLS_RESULT:
ar = (AsyncResult)msg.obj;
if (msg == mLastRelevantPoll) {
mNeedsPoll = false;
mLastRelevantPoll = null;
7、 handlePollCalls((AsyncResult)msg.obj);
}
break;
1) 新来电的通知是: phone.notifyNewRingingConnection;
另外两个是
2) 通话断开通知 onDisconnected;
3) Call状态变化通知 phone.notifiyPreciseCallStateChanged.
(当状态改变之后便会通过GsmPhone的notifyPreciseCallStateChanged()方法发起响应)
来电的时候发出的是phone.notifyNewRingConnection通知,进入到notifyNewRingConnection方法
handlePollCalls(){
...
if (newRinging != null) {
mPhone.notifyNewRingingConnection(newRinging);
}
public void notifyNewRingingConnection(Connection c) {
super.notifyNewRingingConnectionP(c);
}
调用父类 PhoneBase.java(为com.android.internal.telephony.phone接口实现。)
notifyNewRingingConnectionP()发出来电通知 mNewRingingConnectionRegistrants.notifyRegistrants(ar);
/**
* Notify registrants of a new ringing Connection.
* Subclasses of Phone probably want to replace this with a
* version scoped to their packages
*/
public void notifyNewRingingConnectionP(Connection cn) {
if (!mIsVoiceCapable)
return;
AsyncResult ar = new AsyncResult(null, cn, null);
mNewRingingConnectionRegistrants.notifyRegistrants(ar);
}
重点2: RegistrantList.java \frameworks\base\core\java\android\os
notifyRegistrants方法实现
public /*synchronized*/ void notifyRegistrants(AsyncResult ar){
internalNotifyRegistrants(ar.result, ar.exception);
}
private synchronized void internalNotifyRegistrants (Object result, Throwable exception){
for (int i = 0, s = registrants.size(); i < s ; i++) {
Registrant r = (Registrant) registrants.get(i);
r.internalNotifyRegistrant(result, exception);
}
}
/*package*/ void internalNotifyRegistrant (Object result, Throwable exception)
{
Handler h = getHandler();
if (h == null) {
clear();
} else {
Message msg = Message.obtain();
msg.what = what;
msg.obj = new AsyncResult(userObj, result, exception);
h.sendMessage(msg);
}
}
注册为观察者的方法为:
// Inherited documentation suffices.
@Override
public void registerForNewRingingConnection(
Handler h, int what, Object obj) {
checkCorrectThread(h);
mNewRingingConnectionRegistrants.addUnique(h, what, obj);
}
通过log发现PstnIncomingCallNotifier.java调用registerForNewRingingConnection()
01-05 07:10:05.517962 1596 1596 D Telephony: PstnIncomingCallNotifier: handleNewRingingConnection
作用:监听来之相关电话对象的来电事件和通知Telecom在每次发生的时候,这一实例的存在为了每个电话的通话服务
registerForNotifications方法调用registerForNewRingingConnection
private void registerForNotifications() {
Phone newPhone = mPhoneProxy.getActivePhone();
if (newPhone != mPhoneBase) {
unregisterForNotifications();
if (newPhone != null) {
Log.i(this, "Registering: %s", newPhone);
mPhoneBase = newPhone;
//调用registerForNewRingingConnection方法
mPhoneBase.registerForNewRingingConnection(
mHandler, EVENT_NEW_RINGING_CONNECTION, null);
mPhoneBase.registerForCallWaiting(
mHandler, EVENT_CDMA_CALL_WAITING, null);
mPhoneBase.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION,
null);
}
}
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
...
case EVENT_NEW_RINGING_CONNECTION:
handleNewRingingConnection((AsyncResult) msg.obj);
break;
private void handleNewRingingConnection(AsyncResult asyncResult) {
Log.d(this, "handleNewRingingConnection");
Connection connection = (Connection) asyncResult.result;
if (connection != null) {
Call call = connection.getCall();
//在发送intent到Telecom之前最后一次验证ringing 状态
if (call != null && call.getState().isRinging()) {
sendIncomingCallIntent(connection);
}
}
}
发送incoming
call intent到telecom,发送的Connection 类型,里面包括isIncoming getState isRinging等
/**
* Sends the incoming call intent to telecom.
*/
private void sendIncomingCallIntent(Connection connection) {
Bundle extras = null;
if (connection.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED &&
!TextUtils.isEmpty(connection.getAddress())) {
extras = new Bundle();
Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, connection.getAddress(), null);
extras.putParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER, uri);
}
TelecomManager.from(mPhoneProxy.getContext()).addNewIncomingCall(
TelecomAccountRegistry.makePstnPhoneAccountHandle(mPhoneProxy), extras);
}
作用:TelecomManager的功能则主要是对TelecomService提供的远程接口的封装,然后提供给应用使用。
来电时触发 addNewIncomingCall方法
@SystemApi
public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
try {
if (isServiceConnected()) {
getTelecomService().addNewIncomingCall(
phoneAccount, extras == null ? new Bundle() : extras);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException adding a new incoming call: " + phoneAccount, e);
}
}
继承自ITelecomService,TelecomService的接口由TeleComManager封装,并其供给应用使用,
重点2:telecom进程讲解
addNewIncomingCall
新建intent 设定intent 的ACTION 、addFalgs等
/**
* @see android.telecom.TelecomManager#addNewIncomingCall
*/
@Override
public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
synchronized (mLock) {
long token = Binder.clearCallingIdentity();
try {
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) {
intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
}
CallIntentProcessor.processIncomingCallIntent(mCallsManager, intent);
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
CallIntentProcessor.java (packages\services\telecomm\src\com\android\server\telecom)
static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
}
作用:
CallManager类提供了一个抽象层,以供phoneApp访问和控制call等操作。它实现了Phone接口。CallManager提供呼叫和连接控制以及Channel能力。CallManager提供三种类型的API:
1,呼叫控制和操作,如dial()和hangup();
2,Channel的能力,如canconference();
3,注册通知。接着将Phone注册进mCM,Phone状态改变之后InCallUI就能够收到变化消息了。
void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
....
Call call = new Call(
mContext,
this,
mLock,
mConnectionServiceRepository,
mContactsAsyncHelper,
mCallerInfoAsyncQueryFactory,
handle,
null /* gatewayInfo */,
null /* connectionManagerPhoneAccount */,
phoneAccountHandle,
true /* isIncoming */,
false /* isConference */);
call.setIntentExtras(extras);
call.addListener(this);
20、new一个Call 对象 把前面的参数传进来,然后调用call中建立连接的方法startCreateConnection
call.startCreateConnection(mPhoneAccountRegistrar);
}
作用:封装的一个给定的电话在其整个生命周期的各个方面,从电话意图被telecom接收开始
开始建立连接队列,一旦完成创建,就应当有一个活动active的连接了存在service里。
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
Preconditions.checkState(mCreateConnectionProcessor == null);
mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
phoneAccountRegistrar, mContext);
mCreateConnectionProcessor.process();
}
void process() {
Log.v(this, "process");
clearTimeout();
mAttemptRecords = new ArrayList<>();
if (mCall.getTargetPhoneAccount() != null) {
mAttemptRecords.add(new CallAttemptRecord(
mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
}
adjustAttemptsForConnectionManager();
adjustAttemptsForEmergency();
mAttemptRecordIterator = mAttemptRecords.iterator();
attemptNextPhoneAccount();
}
private void attemptNextPhoneAccount() {
...
if (mResponse != null && attempt != null) {
Log.i(this, "Trying attempt %s", attempt);
ConnectionServiceWrapper service =
mRepository.getService(
attempt.connectionManagerPhoneAccount.getComponentName());
if (service == null) {
Log.i(this, "Found no connection service for attempt %s", attempt);
attemptNextPhoneAccount();
} else {
mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
mCall.setConnectionService(service);
Log.i(this, "Attempting to call from %s", service.getComponentName());
service.createConnection(mCall, new Response(service));
}
}
void createConnection(final Call call, final CreateConnectionResponse response) {
mBinder.bind(callback);
}
作用:抽象类用来进行绑定和解除绑定到指定的服务接口的工作。子类提供服务的意图和组件名称和这个类调用受保护方法在类绑定,未绑定或者失败的时候
执行绑定到服务的操作(如果还没有绑定)然后执行指定的回调方法
void bind(BindCallback callback, Call call) {
Log.d(ServiceBinder.this, "bind()");
// Reset any abort request if we're asked to bind again.
clearAbort();
if (!mCallbacks.isEmpty()) {
// Binding already in progress, append to the list of callbacks and bail out.
mCallbacks.add(callback);
return;
}
mCallbacks.add(callback);
if (mServiceConnection == null) {
Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
ServiceConnection connection = new ServiceBinderConnection(call);
Log.event(call, Log.Events.BIND_CS, mComponentName);
final int bindingFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
final boolean isBound;
if (mUserHandle != null) {
isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,
mUserHandle);
} else {
isBound = mContext.bindService(serviceIntent, connection, bindingFlags);
}
if (!isBound) {
handleFailedConnection();
return;
}
} else {
Log.d(ServiceBinder.this, "Service is already bound.");
Preconditions.checkNotNull(mBinder);
handleSuccessfulConnection();
}
}
##26、上面的执行完之后,顺序执行到onServiceConnected
onServiceConnected
private final class ServiceBinderConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
ThreadUtil.checkOnMainThread();
Log.i(this, "Service bound %s", componentName);//这句log被打印出来了
// Unbind request was queued so unbind immediately.
if (mIsBindingAborted) {
clearAbort();
logServiceDisconnected("onServiceConnected");
mContext.unbindService(this);
handleFailedConnection();
return;
}
mServiceConnection = this;
setBinder(binder);
handleSuccessfulConnection();
}
##27、
private void handleSuccessfulConnection() {
for (BindCallback callback : mCallbacks) {
callback.onSuccess();
}
mCallbacks.clear();
}
##28、回调上面的onSuccess() 执行mServiceInterface.createConnectioncreateConnection的具体实现在ConnectionService.java (frameworks\base\telecomm\java\android\telecom)
作用:一个提供电话连接到Android设备上运行的进程。
@Override
public void createConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
String id,
ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
//chengzhi
SomeArgs args = SomeArgs.obtain();
args.arg1 = connectionManagerPhoneAccount;
args.arg2 = id;
args.arg3 = request;
args.argi1 = isIncoming ? 1 : 0;
args.argi2 = isUnknown ? 1 : 0;
29、 mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
}
case MSG_CREATE_CONNECTION: {
createConnection(
connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
}
##31、这个方法可以被telecom用来创建呼出电话或者一个已存在的来电。任何一种情况,telecom都会循环经过一系列的服务和 调用createConnection util a connection service取消或者成功完成创建。
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
##32、前面建立连接成功了,后面处理成功的连接,后面执行mAdapter.handleCreateConnectionComplete
ConnectionServiceAdapter>CallsManager 处理这个创建的连接>成功来电
##33~34.ConnectionServiceAdapter.java (frameworks\base\telecomm\java\android\telecom)
作用:提供iconnectionservice实现与系统的手机应用程序的交互方法。
void handleCreateConnectionComplete(
String id,
ConnectionRequest request,
ParcelableConnection connection) {
for (IConnectionServiceAdapter adapter : mAdapters) {
try {
//chengzhi 03
adapter.handleCreateConnectionComplete(id, request, connection);
} catch (RemoteException e) {
}
}
}
CallsManager>Phone 成功来电>准备启动界面
##34. packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java
作用:Telecomm 层的连接管理者
private final class Adapter extends IConnectionServiceAdapter.Stub {
@Override
public void handleCreateConnectionComplete(
String callId,
ConnectionRequest request,
ParcelableConnection connection) {
logIncoming("handleCreateConnectionComplete %s", request);
if (mCallIdMapper.isValidCallId(callId)) {
ConnectionServiceWrapper.this
.handleCreateConnectionComplete(callId, request, connection);
}
}
ConnectionServiceAdapterServant.java (frameworks\base\telecomm\java\android\telecom)
private final IConnectionServiceAdapter mStub = new IConnectionServiceAdapter.Stub() {
@Override
public void handleCreateConnectionComplete(
String id,
ConnectionRequest request,
ParcelableConnection connection) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = id;
args.arg2 = request;
args.arg3 = connection;
mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_COMPLETE, args).sendToTarget();
}
##34、 handleMessage处理消息 MSG_HANDLE_CREATE_CONNECTION_COMPLETE
// Internal method defined to centralize handling of RemoteException
private void internalHandleMessage(Message msg) throws RemoteException {
switch (msg.what) {
case MSG_HANDLE_CREATE_CONNECTION_COMPLETE: {
SomeArgs args = (SomeArgs) msg.obj;
try {
mDelegate.handleCreateConnectionComplete(
(String) args.arg1,
(ConnectionRequest) args.arg2,
(ParcelableConnection) args.arg3);
} finally {
args.recycle();
}
break;
}
##35、 如果成功连接 ConnectionServiceWrapper.java (packages\services\telecomm\src\com\android\server\telecom)
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);
}
}
}
重写 handleCreateConnectionSuccess方法
@Override
public void handleCreateConnectionSuccess(
CallIdMapper idMapper,
ParcelableConnection connection) {
Log.v(this, "handleCreateConnectionSuccessful %s", connection);
mCreateConnectionProcessor = null;
setTargetPhoneAccount(connection.getPhoneAccount());
setHandle(connection.getHandle(), connection.getHandlePresentation());
setCallerDisplayName(
connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation());
setCallCapabilities(connection.getCapabilities());
setVideoProvider(connection.getVideoProvider());
setVideoState(connection.getVideoState());
setRingbackRequested(connection.isRingbackRequested());
setIsVoipAudioMode(connection.getIsVoipAudioMode());
setStatusHints(connection.getStatusHints());
mConferenceableCalls.clear();
for (String id : connection.getConferenceableConnectionIds()) {
mConferenceableCalls.add(idMapper.getCall(id));
}
if (mIsUnknown) {
for (Listener l : mListeners) {
l.onSuccessfulUnknownCall(this, getStateFromConnectionState(connection.getState()));
}
} else if (mIsIncoming) {
// We do not handle incoming calls immediately when they are verified by the connection
// service. We allow the caller-info-query code to execute first so that we can read the
// direct-to-voicemail property before deciding if we want to show the incoming call to
// the user or if we want to reject the call.
mDirectToVoicemailQueryPending = true;
// Timeout the direct-to-voicemail lookup execution so that we dont wait too long before
// showing the user the incoming call screen.
mHandler.postDelayed(mDirectToVoicemailRunnable, Timeouts.getDirectToVoicemailMillis(
mContext.getContentResolver()));
} else {
for (Listener l : mListeners) {
l.onSuccessfulOutgoingCall(this,
getStateFromConnectionState(connection.getState()));
}
}
}
private final Runnable mDirectToVoicemailRunnable = new Runnable() {
@Override
public void run() {
processDirectToVoicemail();
}
##38、processDirectToVoicemail
final class Call implements CreateConnectionResponse {
/**
* Listener for events on the call.
*/
interface Listener {
void onSuccessfulIncomingCall(Call call);
...
private void processDirectToVoicemail() {
if (mDirectToVoicemailQueryPending) {
if (mCallerInfo != null && mCallerInfo.shouldSendToVoicemail) {
Log.i(this, "Directing call to voicemail: %s.", this);
// TODO: Once we move State handling from CallsManager to Call, we
// will not need to set STATE_RINGING state prior to calling reject.
setState(CallState.RINGING);
reject(false, null);
} else {
// TODO: Make this class (not CallsManager) responsible for changing
// the call state to STATE_RINGING.
// TODO: Replace this with state transition to STATE_RINGING.
for (Listener l : mListeners) {
l.onSuccessfulIncomingCall(this);
}
}
mDirectToVoicemailQueryPending = false;
}
}
##39. package/services/Telecomm/src/com/android/server/telecom/CallsManager.java
39.1@Override onSuccessfulIncomingCall if 判断后 addCall()
public final class CallsManager extends Call.ListenerBase {
...
@Override
public void onSuccessfulIncomingCall(Call incomingCall) {
Log.d(this, "onSuccessfulIncomingCall");
setCallState(incomingCall, CallState.RINGING);
if (hasMaximumRingingCalls(incomingCall.getTargetPhoneAccount().getId())) {
incomingCall.reject(false, null);
// since the call was not added to the list of calls, we have to call the missed
// call notifier and the call logger manually.
mMissedCallNotifier.showMissedCallNotification(incomingCall);
mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE);
} else {
incomingCall.mIsActiveSub = true;
addCall(incomingCall);
setActiveSubscription(incomingCall.getTargetPhoneAccount().getId());
}
}
39.2 addCall()
/**
* Adds the specified call to the main list of live calls.
*
* @param call The call to add.
*/
private void addCall(Call call) {
Log.v(this, "addCall(%s)", call);
call.addListener(this);
mCalls.add(call);
// TODO: Update mForegroundCall prior to invoking
// onCallAdded for calls which immediately take the foreground (like the first call).
for (CallsManagerListener listener : mListeners) {
listener.onCallAdded(call);
}
updateForegroundCall();
}
#第四部分:CallList–>InCallActivity 开始启动界面 -->显示来电
##40、package/services/Telecomm/src/com/android/server/telecom/InCallController.java
作用:结合并提供服务,通过它可以将更新发送到呼叫程序。这类被创建和拥有的callsmanager保持绑定到(被调用的应用程序中实现)。
重写onCallAdded -->
@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 entry : mInCallServices.entrySet()) {
ComponentName componentName = entry.getKey();
IInCallService inCallService = entry.getValue();
ParcelableCall parcelableCall = toParcelableCall(call,
true /* includeVideoProvider */);
try {
inCallService.addCall(parcelableCall);
} catch (RemoteException ignored) {
}
}
}
}
##41、bindToServices – bindToInCallService
InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();
private class InCallServiceConnection implements ServiceConnection {
/** {@inheritDoc} */
@Override public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(this, "onServiceConnected: %s", name);
onConnected(name, service);
}
##42 、
private void onConnected(ComponentName componentName, IBinder service) {
addCall(call);
}
##43. framworks/base/telecomm/java/android/telecom/InCallService.java
作用:这个服务可以被任何希望提供管理电话的用户界面的应用实现,
当那个服务存在一个电话telecom就去绑定这个服务并用它去通知任何活动状态和最近断开的呼叫的被调用的应用
@Override
addCall()
/** Manages the binder calls so that the implementor does not need to deal with it. */
private final class InCallServiceBinder extends IInCallService.Stub {
@Override
public void setInCallAdapter(IInCallAdapter inCallAdapter) {
mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
}
@Override
public void addCall(ParcelableCall call) {
mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
}
##44. handleMessage 处理消息 MSG_ADD_CALL
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (mPhone == null && msg.what != MSG_SET_IN_CALL_ADAPTER) {
return;
}
switch (msg.what) {
case MSG_SET_IN_CALL_ADAPTER:
mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
onPhoneCreated(mPhone);
break;
case MSG_ADD_CALL:
mPhone.internalAddCall((ParcelableCall) msg.obj);
break;
##45. framworks/base/telecomm/java/android/telecom/Phone.java
作用:一个统一的虚拟设备提供语音手段(和其他)设备上的通信。
internalAddCall()
final void internalAddCall(ParcelableCall parcelableCall) {
Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
parcelableCall.mIsActiveSub);
mCallByTelecomCallId.put(parcelableCall.getId(), call);
mCalls.add(call);
checkCallTree(parcelableCall);
call.internalUpdate(parcelableCall, mCallByTelecomCallId);
fireCallAdded(call);
}
45.1 fireCallAdded()
private void fireCallAdded(Call call) {
for (Listener listener : mListeners) {
listener.onCallAdded(this, call);
}
}
##46、onCallAdded()@SystemApi系统Api,一个空的实现方法 其他使用的地方会 @Override
@SystemApi
public final class Phone {
public abstract static class Listener {
...
public void onCallAdded(Phone phone, Call call) { }
##47. pacakge/apps/InCallUI/src/com/android/incallui/CallList.java
作用:保持主动呼叫的列表和通知感兴趣的类关于这个列表的变化,因为他们是从堆栈收到电话,
对这个类变化的主要听众是InCallPresenter
@Override
onCallAdded
/**
* Static singleton accessor method.
*/
public static CallList getInstance() {
return sInstance;
}
private Phone.Listener mPhoneListener = new Phone.Listener() {
@Override
public void onCallAdded(Phone phone, android.telecom.Call telecommCall) {
Call call = new Call(telecommCall);
if (call.getState() == Call.State.INCOMING) {
onIncoming(call, call.getCannedSmsResponses());
} else {
onUpdate(call);
}
}
##48、执行了下面的方法,但再往后的步骤不是从这里走的。
onIncoming()
/**
* Called when a single call has changed.
*/
public void onIncoming(Call call, List textMessages) {
Log.d(this, "onIncoming - " + call);
// Update active subscription from call object. it will be set by
// Telecomm service for incoming call and whenever active sub changes.
if (call.mIsActiveSub) {
long sub = call.getSubId();
Log.d(this, "onIncoming - sub:" + sub + " mSubId:" + mSubId);
if (sub != mSubId) {
setActiveSubscription(sub);
}
}
if (updateCallInMap(call)) {
Log.i(this, "onIncoming - " + call);
}
updateCallTextMap(call, textMessages);
for (Listener listener : mListeners) {
listener.onIncomingCall(call);
}
}
##49. //pacakge/apps/InCallUI/src/com/android/incallui/InCallPresenter.java
作用:接受来至CallList的更新并通知InCallActivity(UI)的变化。负责为一个新的呼叫启动活动和当通话断开时结束activity
onIncomingCall是一个接口以下是它的实现
/**
* Called when there is a new incoming call.
*
* @param call
*/
@Override
public void onIncomingCall(Call call) {
InCallState newState = startOrFinishUi(InCallState.INCOMING);
InCallState oldState = mInCallState;
Log.i(this, "Phone switching state: " + oldState + " -> " + newState);
mInCallState = newState;
for (IncomingCallListener listener : mIncomingCallListeners) {
listener.onIncomingCall(oldState, mInCallState, call);
}
if (CallList.getInstance().isDsdaEnabled() && (mInCallActivity != null)) {
mInCallActivity.updateDsdaTab();
}
}
##50、startUi
showInCall(false /* showDialpad */, !showAccountPicker /* newOutgoingCall */);
##51、showInCall
public void showInCall(final boolean showDialpad, final boolean newOutgoingCall) {
Log.i(this, "Showing InCallActivity");
mContext.startActivity(getInCallIntent(showDialpad, newOutgoingCall));
}
以下是MT流程的类图,我们就根据这个图做下最后总结