http://blog.csdn.net/aaa111/article/details/52876403
电话管理是Android 系统支持的重要的业务之一,提供接听电话,收发短信、电话薄、网络事件监听、读取用户信息等功能。
从下到上可以分为四层:硬件驱动层、RIL daemon层、Telephony框架实现层、 PHONE应用层,下层为上层提供服务,每层之间采用不同的通讯方式交互。RIL daemon层实现为单独的一个开机启动的进程(rild命令),通过AT命令硬件驱动层交互,TelephonyJava框架实现层包括一个RIL抽象层,RIL抽象层中通过一个本地socket与RIL daemon层(rild)交互,PHONE应用层通过BINDER机制与Telephony框架交互。
一、framework telephony层:
android/frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL
RIL层:radio interface layer 多媒体接口层, 主要是与modem进行串口通信,手机网络、通话、短信方面的
功能:接收unsolicited 和solicited 信息
主要由phone进程创建
现在主要了解callTracker这个通话方面的内容(ServiceStateTracker、DataConnectionTracker)
modem传来的来电通知
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
if (RILJ_LOGD) unsljLog(response);
mCallStateRegistrants
.notifyRegistrants(new AsyncResult(null, null, null));
RIL的父类,主要是定义各个观察者 RegistrantList
BaseCommands.java
mCallStateRegistrants
GsmCdmaCallTracker.java (Handler类,说明calltracker只是一个信息的集中转发中心而已)
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);
@Override
public void handleMessage(Message msg) {
case EVENT_CALL_STATE_CHANGE:
pollCallsWhenSafe();
break;
CallTracker.java
protected void pollCallsWhenSafe() {
mNeedsPoll = true;
if (checkNoOperationsPending()) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
mCi.getCurrentCalls(mLastRelevantPoll);
}
}
由于一开始的RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED只是一个通知,并没有附加其他消息
所以这里会下发一个查询当前所有通话的状态表
RIL.java
解析并填充DriverCall
private Object
responseCallList(Parcel p) {
ArrayList<DriverCall> response;
DriverCall dc;
response.add(dc);
return response;
GsmCdmaCallTracker.java
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_POLL_CALLS_RESULT:
Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");
if (msg == mLastRelevantPoll) {
if (DBG_POLL) log(
"handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
mNeedsPoll = false;
mLastRelevantPoll = null;
handlePollCalls((AsyncResult)msg.obj);
}
break;
首先查看DriverCall类
DriverCall实际反映了Modem端真实的通话连接信息
+CLCC:List current calls 列出当前所有的通话
+CLIP:Calling line identified presented 来电显示
//+CLCC: 1,0,2,0,0,\"+18005551212\",145
// index,isMT,state,mode,isMpty(,number,TOA)?
//+CLIP: "02151082965",129,"",,"",0
GsmCdmaCallTracker.java
处理轮询得到的所有通话(进行当前modem端与上层端的通话同步--GsmCdmaConnection<-->DriverCall)
@Override
protected synchronized void handlePollCalls(AsyncResult ar) {
for (int i = 0, curDC = 0, dcSize = polledCalls.size()
; i < mConnections.length; i++) {
GsmCdmaConnection conn = mConnections[i];
DriverCall dc = null;
if (conn == null && dc != null) {
mConnections[i] = new GsmCdmaConnection(mPhone, dc, this, i);//(1)
if (newRinging != null) {
mPhone.notifyNewRingingConnection(newRinging);//(2)
}
updatePhoneState();//(3)
if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) {
mPhone.notifyPreciseCallStateChanged();//(4)
updateMetrics(mConnections);
}
(1) :
基本每一个DriverCall都对应一个通话链接GsmCdmaConnection
GsmCdmaConnection.java
//DriverCall ---> GsmCdmaCall
/** This is probably an MT call that we first saw in a CLCC response or a hand over. */
GsmCdmaCallTracker mOwner;
GsmCdmaCall mParent;
public GsmCdmaConnection (GsmCdmaPhone phone, DriverCall dc, GsmCdmaCallTracker ct, int index) {
mOwner = ct;
mParent = parentFromDCState(dc.state);
mParent.attach(this, dc);
private GsmCdmaCall
parentFromDCState (DriverCall.State state) {
switch (state) {
case ACTIVE:
case DIALING:
case ALERTING:
return mOwner.mForegroundCall;
//break;
case HOLDING:
return mOwner.mBackgroundCall;
//break;
case INCOMING:
case WAITING:
return mOwner.mRingingCall;
//break;
default:
throw new RuntimeException("illegal call state: " + state);
}
}
GsmCdmaCallTracker.java
//***** Constants
public static final int MAX_CONNECTIONS_GSM = 19; //7 allowed in GSM + 12 from IMS for SRVCC
private static final int MAX_CONNECTIONS_PER_CALL_GSM = 5; //only 5 connections allowed per call
private static final int MAX_CONNECTIONS_CDMA = 8;
private static final int MAX_CONNECTIONS_PER_CALL_CDMA = 1; //only 1 connection allowed per call
public GsmCdmaCall mRingingCall = new GsmCdmaCall(this);
// A call that is ringing or (call) waiting
public GsmCdmaCall mForegroundCall = new GsmCdmaCall(this);
public GsmCdmaCall mBackgroundCall = new GsmCdmaCall(this);
GsmCdmaCall.java
//mRingingCall / mForegroundCall / mBackgroundCall 每一种类型的call对应多路通话链接, 而且很明显DriverCall ---》GsmCdmaCall
//***** Called from GsmCdmaConnection
public void attach(Connection conn, DriverCall dc) {
mConnections.add(conn);
mState = stateFromDCState (dc.state);
}
//双模单待无线语音呼叫连续性 Single Radio Voice Call Continuity (SRVCC)
//Hand Over -- 切换,属于移动通信网络中的技术术语。
所谓切换,就是指当移动台在通话过程中从一个基站覆盖区移动到另一个基站覆盖区,或者由于外界干扰而造成通话质量下降时,必须改变原有的话音信道而转接到一条新的空闲话音信道上去,以继续保持通话的过程。切换是移动通信系统中一项非常重要的技术,切换失败会导致掉话,影响网络的运行质量。因此,切换成功率(包括切入和切出)是我们网络考核的一项重要指标,如何提高切换成功率,降低切换掉话率是我们网络优化工作的重点之一
(2):
GsmCdmaPhone.java
public void notifyNewRingingConnection(Connection c) {
super.notifyNewRingingConnectionP(c);
}
Phone.java
private final RegistrantList mNewRingingConnectionRegistrants
= new RegistrantList();
/**
* Notifies when a new ringing or waiting connection has appeared.<p>
*
* Messages received from this:
* Message.obj will be an AsyncResult
* AsyncResult.userObj = obj
* AsyncResult.result = a Connection. <p>
* Please check Connection.isRinging() to make sure the Connection
* has not dropped since this message was posted.
* If Connection.isRinging() is true, then
* Connection.getCall() == Phone.getRingingCall()
*/
public void registerForNewRingingConnection(
Handler h, int what, Object obj) {
checkCorrectThread(h);
mNewRingingConnectionRegistrants.addUnique(h, what, obj);
}
/**
* 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);
}
android/frameworks/opt/telephony/src/java/com/android/internal/telephony/CallManager.java:580: phone.registerForNewRingingConnection(handler, EVENT_NEW_RINGING_CONNECTION,
android/packages/services/Telephony/src/com/android/services/telephony/PstnIncomingCallNotifier.java:111: mPhone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
----------------
4.framworks/opt/telephony/.../telephony/CallManager.java 5.0之前是这里处理,新版本由PstnIncomingCallNotifier处理
前面:RIL发出Call状态变化消息通知,GSMPhone发出来电通知
二、packages telephony层
packages\services\Telephony\src\com\android\services\telephony
PstnIncomingCallNotifier.java
android/packages/services/Telephony/src/com/android/services/telephony/TelecomAccountRegistry.java:107: mIncomingCallNotifier = new PstnIncomingCallNotifier((Phone) mPhone);
/**
* Register for notifications from the base phone.
*/
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);
}
}
/**
* Used to listen to events from {@link #mPhone}.
*/
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
case EVENT_NEW_RINGING_CONNECTION:
handleNewRingingConnection((AsyncResult) msg.obj);
break;
/**
* Sends the incoming call intent to telecom.
*/
private void sendIncomingCallIntent(Connection connection) {
TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras);
三、framework telecomm层
android\frameworks\base\telecomm\java\android\telecom
TelecomManager.java
/**
*Once invoked, this
* method will cause the system to bind to the {@link ConnectionService} associated with the
* {@link PhoneAccountHandle} and request additional information about the call
* (See {@link ConnectionService#onCreateIncomingConnection}) before starting the incoming
* call UI.
public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
if (isServiceConnected()) {
getTelecomService().addNewIncomingCall(
phoneAccount, extras == null ? new Bundle() : extras);
}
四、packages telecomm层
packages\services\Telecomm\src\com\android\server\telecom
TelecomServiceImpl.java
private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
/**
* @see android.telecom.TelecomManager#addNewIncomingCall
*/
@Override
public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
try {
Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
mCallIntentProcessorAdapter.processIncomingCallIntent(mCallsManager, intent);
//去电、来电的必经通道口
CallIntentProcessor.java
* Single point of entry for all outgoing and incoming calls.
public static class AdapterImpl implements Adapter {
@Override
public void processOutgoingCallIntent(Context context, CallsManager callsManager,
Intent intent) {
CallIntentProcessor.processOutgoingCallIntent(context, callsManager, intent);
}
@Override
public void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
CallIntentProcessor.processIncomingCallIntent(callsManager, intent);
}
static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
CallsManager.java
/**
* Starts the process to attach the call to a connection service.
void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
Call call = new Call(
getNextCallId(),
mContext,
this,
mLock,
mConnectionServiceRepository,
mContactsAsyncHelper,
mCallerInfoAsyncQueryFactory,
mPhoneNumberUtilsAdapter,
handle,
null /* gatewayInfo */,
null /* connectionManagerPhoneAccount */,
phoneAccountHandle,
Call.CALL_DIRECTION_INCOMING /* callDirection */,
false /* forceAttachToExistingConnection */,
false /* isConference */
);
call.startCreateConnection(mPhoneAccountRegistrar);
Call.java
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
phoneAccountRegistrar, mContext);
mCreateConnectionProcessor.process();
}
CreateConnectionProcessor.java
private void attemptNextPhoneAccount() {
mConnectionAttempt++;
mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
mCall.setConnectionService(mService);
setTimeoutIfNeeded(mService, attempt);
mService.createConnection(mCall, this);
ConnectionServiceWrapper.java
* Creates a connection service.
* IConnectionService 的包装类
/**
* Creates a new connection for a new outgoing call or to attach to an existing incoming call.
*/
@VisibleForTesting
public void createConnection(final Call call, final CreateConnectionResponse response) {
mBinder.bind(callback, call);
ServiceBinder.java
/**
* Helper class to perform on-demand binding.
*/
final class Binder2 {
/**
* Performs an asynchronous bind to the service (only if not already bound) and executes the
* specified callback.
void bind(BindCallback callback, Call call) {
ServiceConnection connection = new ServiceBinderConnection(call);
isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,mUserHandle);
private final class ServiceBinderConnection implements ServiceConnection {
/**
* The initial call for which the service was bound.
*/
private Call mCall;
ServiceBinderConnection(Call call) {
mCall = call;
}
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
try {
mServiceConnection = this;
setBinder(binder);
handleSuccessfulConnection();
/**
* Sets the (private) binder and updates the child class.
*
* @param binder The new binder value.
*/
private void setBinder(IBinder binder) {
if (mBinder != binder) {
mBinder = binder;
setServiceInterface(binder);//(1)
}
/**
* Notifies all the outstanding callbacks that the service is successfully bound. The list of
* outstanding callbacks is cleared afterwards.
*/
private void handleSuccessfulConnection() {
for (BindCallback callback : mCallbacks) {
callback.onSuccess();//(2)
}
mCallbacks.clear();
}
ConnectionServiceWrapper.java
(1):
/** {@inheritDoc} */
@Override
protected void setServiceInterface(IBinder binder) {
mServiceInterface = IConnectionService.Stub.asInterface(binder);
Log.v(this, "Adding Connection Service Adapter.");
addConnectionServiceAdapter(mAdapter);
}
(2):
BindCallback callback = new BindCallback() {
@Override
public void onSuccess() {
mPendingResponses.put(callId, response);
mServiceInterface.createConnection(
call.getConnectionManagerPhoneAccount(),
callId,
new ConnectionRequest(
call.getTargetPhoneAccount(),
call.getHandle(),
extras,
call.getVideoState(),
callId),
call.shouldAttachToExistingConnection(),
call.isUnknown());
mPendingResponses.put(callId, response);
mServiceInterface.createConnection(
call.getConnectionManagerPhoneAccount(),
callId,
new ConnectionRequest(
call.getTargetPhoneAccount(),
call.getHandle(),
extras,
call.getVideoState(),
callId),
call.shouldAttachToExistingConnection(),
call.isUnknown());
三、framework telecomm层
frameworks\base\telecomm\java\android\telecom
ConnectionService.java
private final IBinder mBinder = new IConnectionService.Stub() {
public void createConnection(
case MSG_CREATE_CONNECTION: {
createConnection(
connectionManagerPhoneAccount,
id,
request,
isIncoming,
isUnknown);
/**
* This can be used by telecom to either create a new outgoing call or attach to an existing
* incoming call. In either case, telecom will cycle through a set of services and call
* createConnection util a connection service cancels the process or completes it successfully.
*/
private void createConnection(
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.getSupportedAudioRoutes(),
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()));
onCreateIncomingConnection(callManagerAccount, request)
: onCreateOutgoingConnection(callManagerAccount, request);
mAdapter.handleCreateConnectionComplete(
callId,
request,
new ParcelableConnection(
request.getAccountHandle(),
connection.getState(),
connection.getConnectionCapabilities(),
connection.getConnectionProperties(),
connection.getSupportedAudioRoutes(),
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()));
二、packages telephony层
android/packages/services/Telephony/src/com/android/services/telephony/TelephonyConnectionService.java
TelephonyConnectionService.java
/**
* Service for making GSM and CDMA connections.
*/
public class TelephonyConnectionService extends ConnectionService {
@Override
public Connection onCreateIncomingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
ConnectionRequest request) {
Call call = phone.getRingingCall();//GsmCdmaCallTracker.mRingingCall
//framework层originalConnection关联到 packages层connection
Connection connection =
createConnectionFor(phone, originalConnection, false /* isOutgoing */,
request.getAccountHandle(), request.getTelecomCallId(),
request.getAddress(), videoState);
connection.updateState();
private TelephonyConnection createConnectionFor(
Phone phone,
com.android.internal.telephony.Connection originalConnection,
boolean isOutgoing,
PhoneAccountHandle phoneAccountHandle,
String telecomCallId,
Uri address,
int videoState) {
if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
returnConnection = new GsmConnection(originalConnection, telecomCallId);
if (returnConnection != null) {
// Listen to Telephony specific callbacks from the connection
returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
returnConnection.setVideoPauseSupported(
TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
phoneAccountHandle));
}
originalConnection, telecomCallId);
if (returnConnection != null) {
// Listen to Telephony specific callbacks from the connection
returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
returnConnection.setVideoPauseSupported(
TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
phoneAccountHandle));
}
GsmConnection.java
/**
* Manages a single phone call handled by GSM.
*/
final class GsmConnection extends TelephonyConnection {
GsmConnection(Connection connection, String telecomCallId) {
super(connection, telecomCallId);//connection 属于framework层的com.android.internal.telephony.Connection
TelephonyConnection.java
//根据framework层的originalConnection信息更新当前
void updateState() {
if (mOriginalConnection == null) {
return;
}
updateStateInternal();
updateStatusHints();
updateConnectionCapabilities();
updateConnectionProperties();
updateAddress();
updateMultiparty();
}
originalConnection信息更新当前
void updateState() {
if (mOriginalConnection == null) {
return;
}
updateStateInternal();
updateStatusHints();
updateConnectionCapabilities();
updateConnectionProperties();
updateAddress();
updateMultiparty();
}
三、framework telecomm层
frameworks\base\telecomm\java\android\telecom
ConnectionServiceAdapter.java
/**
* Provides methods for IConnectionService implementations to interact with the system phone app.
*
* @hide
*/
final class ConnectionServiceAdapter implements DeathRecipient {
void handleCreateConnectionComplete(
String id,
ConnectionRequest request,
ParcelableConnection connection) {
for (IConnectionServiceAdapter adapter : mAdapters) {
try {
adapter.handleCreateConnectionComplete(id, request, connection);
} catch (RemoteException e) {
}
}
}
四、packages telecomm层
packages\services\Telecomm\src\com\android\server\telecom
ConnectionServiceWrapper.java
* * ConnectionService.java --->ConnectionServiceAdapter.java --->ConnectionServiceWrapper.Adapter
private final class Adapter extends IConnectionServiceAdapter.Stub {
public void handleCreateConnectionComplete(String callId, ConnectionRequest request,
ParcelableConnection connection) {
try {
synchronized (mLock) {
ConnectionServiceWrapper.this
.handleCreateConnectionComplete(callId, request, connection);
}
}
private void handleCreateConnectionComplete(
String callId,
ConnectionRequest request,
ParcelableConnection connection) {
// Successful connection
if (mPendingResponses.containsKey(callId)) {
mPendingResponses.remove(callId) //CreateConnectionProcessor
.handleCreateConnectionSuccess(mCallIdMapper, connection);
}
mPendingResponses.remove(callId) //CreateConnectionProcessor
.handleCreateConnectionSuccess(mCallIdMapper, connection);
}
CreateConnectionProcessor.java
* This class creates connections to place new outgoing calls or to attach to an existing incoming
* call.
public void handleCreateConnectionSuccess(
CallIdMapper idMapper,
ParcelableConnection connection) {
// Success -- share the good news and remember that we are no longer interested
// in hearing about any more attempts
mCallResponse.handleCreateConnectionSuccess(idMapper, connection);//Call.java
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.handleCreateConnectionSuccess(idMapper, connection);//Call.java
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.
}
Call.java
public void handleCreateConnectionSuccess(
CallIdMapper idMapper,
ParcelableConnection connection) {
Log.v(this, "handleCreateConnectionSuccessful %s", connection);
//**
setTargetPhoneAccount(connection.getPhoneAccount());
setHandle(connection.getHandle(), connection.getHandlePresentation());
setCallerDisplayName(
connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation());
setConnectionCapabilities(connection.getConnectionCapabilities());
setConnectionProperties(connection.getConnectionProperties());
setSupportedAudioRoutes(connection.getSupportedAudioRoutes());
setVideoProvider(connection.getVideoProvider());
setVideoState(connection.getVideoState());
setRingbackRequested(connection.isRingbackRequested());
setIsVoipAudioMode(connection.getIsVoipAudioMode());
setStatusHints(connection.getStatusHints());
putExtras(SOURCE_CONNECTION_SERVICE, connection.getExtras());
//** 这一段主要是更新call信息
// GsmCdmaCall --->GsmCdmaConnection ---> ---> TelephonyConnection --->Call
switch (mCallDirection) {
case CALL_DIRECTION_INCOMING:
// Listeners (just CallsManager for now) will be responsible for checking whether
// the call should be blocked.
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;
}
CallsManager.java
public void onSuccessfulIncomingCall(Call incomingCall) {
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();
}
IncomingCallFilter.java
//过滤完成后
public void onCallFilteringComplete(Call call, CallFilteringResult result) {
synchronized (mTelecomLock) { // synchronizing to prevent race on mResult
mNumPendingFilters--;
mResult = result.combine(mResult);
if (mNumPendingFilters == 0) {
// synchronized on mTelecomLock to enter into Telecom.
mHandler.post(new Runnable("ICF.oCFC", mTelecomLock) {
@Override
public void loggedRun() {
if (mIsPending) {
Log.event(mCall, Log.Events.FILTERING_COMPLETED, mResult);
mListener.onCallFilteringComplete(mCall, mResult);
mIsPending = false;
}
}
}.prepare());
}
}
}
CallsManager.java
/**
* Initializes the required Telecom components.
*/
CallsManager(
SystemVibrator systemVibrator = new SystemVibrator(context);
mInCallController = new InCallController(
context, mLock, this, systemStateProvider, defaultDialerAdapter, mTimeoutsAdapter);
mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer,
ringtoneFactory, systemVibrator, mInCallController);
mCallAudioManager = new CallAudioManager(callAudioRouteStateMachine,
this,new CallAudioModeStateMachine((AudioManager)
mContext.getSystemService(Context.AUDIO_SERVICE)),
playerFactory, mRinger, new RingbackPlayer(playerFactory), mDtmfLocalTonePlayer);
public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) {
// Only set the incoming call as ringing if it isn't already disconnected. It is possible
// that the connection service disconnected the call before it was even added to Telecom, in
// which case it makes no sense to set it back to a ringing state.
if (incomingCall.getState() != CallState.DISCONNECTED &&
incomingCall.getState() != CallState.DISCONNECTING) {
(1) setCallState(incomingCall, CallState.RINGING,
result.shouldAllowCall ? "successful incoming call" : "blocking call");
(2) addCall(incomingCall);
setActiveSubscription(incomingCall.getTargetPhoneAccount().getId());
}
(1)
/**
* Sets the specified state on the specified call.
*
* @param call The call.
* @param newState The new state of the call.
*/
private void setCallState(Call call, int newState, String tag) {
call.setState(newState, tag);
listener.onCallStateChanged(call, oldState, newState);
(2)
/**
* Adds the specified call to the main list of live calls.
*
* @param call The call to add.
*/
private void addCall(Call call) {
Trace.beginSection("addCall");
Log.v(this, "addCall(%s)", call);
call.addListener(this);//监听call状态操作变化,以便更新call状态
mCalls.add(call);
// Specifies the time telecom finished routing the call. This is used by the dialer for
// analytics.
Bundle extras = call.getIntentExtras();
extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,
SystemClock.elapsedRealtime());
updateCanAddCall();
// 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);//先只看InCallController
if (Log.SYSTRACE_DEBUG) {
Trace.endSection();
}
SystemVibrator(context);
mInCallController = new InCallController(
context, mLock, this, systemStateProvider, defaultDialerAdapter, mTimeoutsAdapter);
mRinger = new Ringer(playerFactory, context, systemSettingsUtil, asyncRingtonePlayer,
ringtoneFactory, systemVibrator, mInCallController);
mCallAudioManager = new CallAudioManager(callAudioRouteStateMachine,
this,new CallAudioModeStateMachine((AudioManager)
mContext.getSystemService(Context.AUDIO_SERVICE)),
playerFactory, mRinger, new RingbackPlayer(playerFactory), mDtmfLocalTonePlayer);
public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) {
// Only set the incoming call as ringing if it isn't already disconnected. It is possible
// that the connection service disconnected the call before it was even added to Telecom, in
// which case it makes no sense to set it back to a ringing state.
if (incomingCall.getState() != CallState.DISCONNECTED &&
incomingCall.getState() != CallState.DISCONNECTING) {
(1) setCallState(incomingCall, CallState.RINGING,
result.shouldAllowCall ? "successful incoming call" : "blocking call");
(2) addCall(incomingCall);
setActiveSubscription(incomingCall.getTargetPhoneAccount().getId());
}
(1)
/**
* Sets the specified state on the specified call.
*
* @param call The call.
* @param newState The new state of the call.
*/
private void setCallState(Call call, int newState, String tag) {
call.setState(newState, tag);
listener.onCallStateChanged(call, oldState, newState);
(2)
/**
* Adds the specified call to the main list of live calls.
*
* @param call The call to add.
*/
private void addCall(Call call) {
Trace.beginSection("addCall");
Log.v(this, "addCall(%s)", call);
call.addListener(this);//监听call状态操作变化,以便更新call状态
mCalls.add(call);
// Specifies the time telecom finished routing the call. This is used by the dialer for
// analytics.
Bundle extras = call.getIntentExtras();
extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,
SystemClock.elapsedRealtime());
updateCanAddCall();
// 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);//先只看InCallController
if (Log.SYSTRACE_DEBUG) {
Trace.endSection();
}
mListeners.add(mInCallWakeLockController);
mListeners.add(statusBarNotifier);
mListeners.add(mCallLogManager);
mListeners.add(mPhoneStateBroadcaster);
mListeners.add(mInCallController);
mListeners.add(mCallAudioManager);
mListeners.add(missedCallNotifier);
mListeners.add(mHeadsetMediaButton);
mListeners.add(mProximitySensorManager);
mListeners.add(mViceNotificationImpl);
InCallController.java
/**
* Binds to {@link IInCallService} and provides the service to {@link CallsManager} through which it
* can send updates to the in-call app. This class is created and owned by CallsManager and retains
* a binding to the {@link IInCallService} (implemented by the in-call app).
*/
public final class InCallController extends CallsManagerListenerBase {
public void onCallAdded(Call call) {
android.util.Log.e("InCallPresenter","incallcontroller onCallAdded",new RuntimeException("here").fillInStackTrace());
if (!isBoundToServices()) {
bindToServices(call);//第一次bind InCallService
} else {
// Track the call if we don't already know about it.//监听改call
addCall(call);
inCallService.addCall(parcelableCall);
}
//bindToServices --》mContext.bindServiceAsUser --->onServiceConnected--->onConnected
/**
* Persists the {@link IInCallService} instance and starts the communication between
* this class and in-call app by sending the first update to in-call app. This method is
* called after a successful binding connection is established.
*
* @param info Info about the service, including its {@link ComponentName}.
* @param service The {@link IInCallService} implementation.
* @return True if we successfully connected.
*/
private boolean onConnected(InCallServiceInfo info, IBinder service) {
IInCallService inCallService = IInCallService.Stub.asInterface(service);
mInCallServices.put(info, inCallService);
inCallService.setInCallAdapter(
new InCallAdapter(
mCallsManager,
mCallIdMapper,
mLock,
info.getComponentName().getPackageName()));
// Track the call if we don't already know about it.
addCall(call);
numCallsSent += 1;
inCallService.addCall(ParcelableCallUtils.toParcelableCall(
call,
true /* includeVideoProvider */,
mCallsManager.getPhoneAccountRegistrar(),
info.isExternalCallsSupported()));
inCallService.onCallAudioStateChanged(mCallsManager.getAudioState());
inCallService.onCanAddCallChanged(mCallsManager.canAddCall());
addCall(ParcelableCallUtils.toParcelableCall(
call,
true /* includeVideoProvider */,
mCallsManager.getPhoneAccountRegistrar(),
info.isExternalCallsSupported()));
inCallService.onCallAudioStateChanged(mCallsManager.getAudioState());
inCallService.onCanAddCallChanged(mCallsManager.canAddCall());
三、framework telecomm层
frameworks\base\telecomm\java\android\telecom
InCallService.java
/** Manages the binder calls so that the implementor does not need to deal with it. */
private final class InCallServiceBinder extends IInCallService.Stub {
public void addCall(ParcelableCall call) {
mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
}
case MSG_ADD_CALL:
mPhone.internalAddCall((ParcelableCall) msg.obj);
Phone.java
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);//listener.onCallAdded(this, call);
}
InCallService.java
private Phone.Listener mPhoneListener = new Phone.Listener() {
@Override
public void onCallAdded(Phone phone, Call call) {
InCallService.this.onCallAdded(call);
}
五、Dialer / InCallUI
packages\apps\Dialer\InCallUI\src\com\android\incallui
InCallServiceImpl.java
/**
* Used to receive updates about calls from the Telecom component. This service is bound to
* Telecom while there exist calls which potentially require UI. This includes ringing (incoming),
* dialing (outgoing), and active calls. When the last call is disconnected, Telecom will unbind to
* the service triggering InCallActivity (via CallList) to finish soon after.
*/
public class InCallServiceImpl extends InCallService {
public void onCallAdded(Call call) {
InCallPresenter.getInstance().onCallAdded(call);
}
InCallPresenter.java
public void onCallAdded(final android.telecom.Call call) {
mCallList.onCallAdded(call);
}
CallList.java
Dialer call ----------- framework/base/telecomm/ call
/**
* Maintains the list of active calls and notifies interested classes of changes to the call list
* as they are received from the telephony stack. Primary listener of changes to this class is
* InCallPresenter.
*/
public class CallList {
public void onCallAdded(final android.telecom.Call telecomCall) {
final Call call = new Call(telecomCall);
if (call.getState() == Call.State.INCOMING ||
call.getState() == Call.State.CALL_WAITING) {
onIncoming(call, call.getCannedSmsResponses());//listener.onIncomingCall(call);
} else {
onUpdate(call);
}
onIncoming(call, call.getCannedSmsResponses());//listener.onIncomingCall(call);
} else {
onUpdate(call);
}
InCallPresenter.java
/**
* Called when there is a new incoming call.
*
* @param call
*/
@Override
public void onIncomingCall(Call call) {
InCallState newState = startOrFinishUi(InCallState.INCOMING);//显示InCallActivity界面
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();
}
if (isActivityStarted()) {
wakeUpScreen();
}
}
startOrFinishUi(InCallState.INCOMING);//显示InCallActivity界面
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();
}
if (isActivityStarted()) {
wakeUpScreen();
}
}
二、IncallUI
android\packages\apps\Dialer\InCallUI\src\com\android\incallui
CallAudioManager
InCallServiceImpl
CallList
InCallPresenter
FilteredNumberAsyncQueryHandler