在上一篇文章裡,講到了TelecomService的啟動與初始化,這裡我們着重以來電(Mobile Terminal)過程來分析一下TelecomService是如何傳遞通話資訊并最終與上層UI互動的。主要分以下幾個部分:
- 來電後,Telephony中間層如何将通話通知到TelecomService;
- TelecomService如何建立通話連接配接;
- TelecomService如何告知UI來電資訊
TelecomService的初始化過程:http://blog.csdn.net/jason_wzn/article/details/58164251
下圖是來電在Telecom服務中的處理流程,可以讓我們對整個流程有個感性的認識。
Telephony将來電通知TelcomService
Phone程序初始化時,會建立兩個CALL相關的通知類
PstnIncomingCallNotifier
(接受來電相關的資訊)以及
PstnCallNotifier
(主要用于處理CDMA相關的來電資訊)用于向
TelecomService
發送來電資訊:
public class TelephonyGlobals {
private static TelephonyGlobals sInstance;
....
public void onCreate() {
// Make this work with Multi-SIM devices
Phone[] phones = PhoneFactory.getPhones();
for (Phone phone : phones) {
mTtyManagers.add(new TtyManager(mContext, phone));
}
//添加Telecom賬戶(通話相關的資料管理)
TelecomAccountRegistry.getInstance(mContext).setupOnBoot();
AdvancedEmergencyManager.getInstance(mContext).setupOnBoot();
}
}
初始化Telecom通話相關的賬号,每個賬号都包含了一個
PstnIncomingCallNotifier
成員對象:
final class TelecomAccountRegistry {
private List<AccountEntry> mAccounts = new LinkedList<AccountEntry>();
AccountEntry(Context context, Phone phone, boolean isEmergency, boolean isDummy) {
mPhone = phone;
mIsEmergency = isEmergency;
mIsDummy = isDummy;
// 建立用于通話的PhoneAccount
mAccount = registerPstnPhoneAccount(isEmergency, isDummy);
// 來電通知類,有來電時CallManager會通知它
mIncomingCallNotifier = new PstnIncomingCallNotifier((Phone) mPhone);
mPhoneCapabilitiesNotifier = new PstnPhoneCapabilitiesNotifier((Phone) mPhone,
this);
mPstnCallNotifier = new PstnCallNotifier(context, (Phone) mPhone);
}
/**
* Sets up all the phone accounts for SIMs on first boot.
*/
void setupOnBoot() {
// setup accounts immediately on boot if it's encryption mode or airplane mode.
setupOnBootImmediately();
....
}
private void setupOnBootImmediately() {
if ((TeleServiceFeature.hasFeature(TeleServiceFeature.MultiSIM.FEATURE_MULTISIM)
|| TeleServiceFeature.hasFeature(TeleServiceFeature.Function.SUPPORT_WFC))
&& (PhoneUtils.isEncryptionMode() || PhoneUtils.isAirplaneModeOn())) {
Log.i(this, "setupOnBootImmediately");
//建立PhoneAccount
setupAccounts();
}
}
//建立通話相關的PhoneAccount
private void setupAccounts() {
Phone[] phones = PhoneFactory.getPhones();
Log.d(this, "Found %d phones. Attempting to register.", phones.length);
final boolean phoneAccountsEnabled = mContext.getResources().getBoolean(
R.bool.config_pstn_phone_accounts_enabled);
synchronized (mAccountsLock) {
if (phoneAccountsEnabled) {
for (Phone phone : phones) {
int subscriptionId = phone.getSubId();
//建立新的PhoneAccount
if ((subscriptionId >= && PhoneUtils.getFullIccSerialNumber(phone) != null)
|| TeleServiceFeature.hasFeature(TeleServiceFeature.MultiSIM.FEATURE_MULTISIM)) {
mAccounts.add(new AccountEntry(mContext, phone, false /* emergency */,
false /* isDummy */));
}
}
}
// 注冊PhoneAccount用于緊急撥号
if (mAccounts.isEmpty()) {
Log.w(this, "adding account for emergency ");
mAccounts.add(new AccountEntry(mContext, PhoneFactory.getDefaultPhone(), true /* emergency */,
false /* isDummy */));
}
....
}
}
}
這裡建立的PhoneAccount對象的ComponetName是:
ComponentName PSTN_CONNECTION_SERVICE_COMPONENT = new ComponentName("com.android.phone","com.android.services.telephony.TelephonyConnectionService")
;
在綁定Telephony層的通話連接配接服務時需要用到該元件名
建立
PstnIncomingCallNotifier
來電通知對象:
final class PstnIncomingCallNotifier {
/** The phone object to listen to. */
private final Phone 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;
....
default:
break;
}
}
};
PstnIncomingCallNotifier(Phone phone) {
Preconditions.checkNotNull(phone);
mPhone = phone;
registerForNotifications();
}
// 監聽Phone(由PhoneFactory建立)中的事件
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);
mPhone.registerForSuppServiceNotification(mHandler, EVENT_SUPP_SERVICE_NOTIFY, null);
}
}
上述初始化過程準備完後,Telecom就可以收到來自Phone程序的來電資訊了:隻要telephony中有來電,
Phone
就會發送消息到
PstnIncomingCallNotifier
中的線程消息隊列,由
Handler
對消息進行處理:
final class PstnIncomingCallNotifier {
private void handleNewRingingConnection(AsyncResult asyncResult) {
//通話連接配接,裡邊包含了所有來電的資訊
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()) {
PhoneUtils.hideMmiDialog();
// 告知Telecom來電資訊
sendIncomingCallIntent(connection);
}
}
}
// 将來電資訊發送給Telecom
private void sendIncomingCallIntent(Connection connection) {
Bundle extras = TelephonyConnectionUtils.makeIncomingSecCallExtra(mPhone.getContext(), connection);
if (connection.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED &&
!TextUtils.isEmpty(connection.getAddress())) {
Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, connection.getAddress(), null);
extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, uri);
}
//查找mPhone對應的PhoneAccountHandle對象
PhoneAccountHandle handle = findCorrectPhoneAccountHandle();
if (handle == null) {
try {
connection.hangup();
} catch (CallStateException e) {
// connection already disconnected. Do nothing
}
} else {
// 向TelecomService發送來電資訊
TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras);
}
}
}
TelecomService建立通話連接配接
調用TelecomManager的接口
addNewIncomingCall
,發送IPC請求到
TelecomService
,告知其由來電資訊:
public class TelecomManager {
private ITelecomService getTelecomService() {
if (mTelecomServiceOverride != null) {
return mTelecomServiceOverride;
}
return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
}
public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
try {
if (isServiceConnected()) {
// 調用TelecomServiceImpl的IBinder接口添加來電資訊
getTelecomService().addNewIncomingCall(
phoneAccount, extras == null ? new Bundle() : extras);
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException adding a new incoming call: " + phoneAccount, e);
}
}
}
在
TelecomService
綁定時,我們了解到,實際注冊到系統的
IBinder
接口是
getTelecomServiceImpl().getBinder()
,即
TelecomServiceImpl
中的一個服務端實作:
public class TelecomServiceImpl {
private final CallIntentProcessor.Adapter mCallIntentProcessorAdapter;
private CallsManager mCallsManager;
public ITelecomService.Stub getBinder() {
return mBinderImpl;
}
// ITelecomService.aidl接口的實作
private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() {
public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
try {
synchronized (mLock) {
if (phoneAccountHandle != null &&
phoneAccountHandle.getComponentName() != null) {
....
TelecomUtils.boostCPU();
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) {
extras.setDefusable(true);
intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
}
//調用CallIntentProcessor的Adapter接口處理來電intent
mCallIntentProcessorAdapter.processIncomingCallIntent(
mCallsManager, intent);
} finally {
Binder.restoreCallingIdentity(token);
}
}
}
} finally {
Log.endSession();
}
}
}
}
}
調用CallIntentProcessor的Adapter接口處理來電intent:
public class CallIntentProcessor {
public interface Adapter {
void processOutgoingCallIntent(Context context, CallsManager callsManager,
Intent intent);
void processIncomingCallIntent(CallsManager callsManager, Intent intent);
void processUnknownCallIntent(CallsManager callsManager, Intent intent);
}
public static class AdapterImpl implements Adapter {
@Override
public void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
CallIntentProcessor.processIncomingCallIntent(callsManager, intent);
}
....
}
static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
....
Bundle clientExtras = null;
if (intent.hasExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS)) {
clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS);
}
//調用CallsManager處理來電資訊
callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
}
}
調用
CallsManager
的接口,建立一個
Call
對象,并着手建立與
ConnectionService
之間的連接配接:
public class CallsManager extends Call.ListenerBase
implements VideoProviderProxy.Listener, CallFilterResultCallback {
void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
mIsIncomingPreProcessing = true;
// 擷取來電号碼
Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS);
// 建立一個Call對象表示來電資訊
Call call = TelecomUtils.makeCall(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 */), extras
);
call.addListener(this);
call.startCreateConnection(mPhoneAccountRegistrar);
// Set current calling subscription as default subscription
changeDefaultVoiceSubId(call, false, false, null);
}
}
}
建立
Call
對象後,将其發送給
CreateConnectionProcessor
進一步處理,
public class Call implements CreateConnectionResponse {
....
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
if (mCreateConnectionProcessor != null) {
Log.w(this, "mCreateConnectionProcessor in startCreateConnection is not null. This is" +
" due to a race between NewOutgoingCallIntentBroadcaster and " +
"phoneAccountSelected, but is harmlessly resolved by ignoring the second " +
"invocation.");
return;
}
mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
phoneAccountRegistrar, mContext);
mCreateConnectionProcessor.process();
}
}
得到一個
Call
對象後,
CreateConnectionProcessor
負責檢查所有PhoneAccount中是否有需要處理的通話,
CallAttemptRecord
中儲存了維持一路通話的所有資訊:
public class CreateConnectionProcessor implements CreateConnectionResponse {
private final ConnectionServiceRepository mRepository;
private ConnectionServiceWrapper mService;
....
public void process() {
Log.v(this, "process");
clearTimeout();
mAttemptRecords = new ArrayList<>();
if (mCall.getTargetPhoneAccount() != null) {
mAttemptRecords.add(new CallAttemptRecord(
mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
}
adjustAttemptsForConnectionManager();
adjustAttemptsForEmergency(mCall.getTargetPhoneAccount());
mAttemptRecordIterator = mAttemptRecords.iterator();
// 處理下一個PhoneAccount
attemptNextPhoneAccount();
}
// 檢查下一個PhoneAccount是否有一路通話請求
private void attemptNextPhoneAccount() {
CallAttemptRecord attempt = null;
if ((mAttemptRecordIterator != null) && mAttemptRecordIterator.hasNext()) {
attempt = mAttemptRecordIterator.next();
}
if (mCallResponse != null && attempt != null) {
PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
// 從通話連接配接服務池中搜尋相應的連接配接服務(該連接配接服務池在CallsManager中建立)
mService = mRepository.getService(phoneAccount.getComponentName(),
phoneAccount.getUserHandle());
if (mService == null) {
Log.i(this, "Found no connection service for attempt %s", attempt);
attemptNextPhoneAccount();
} else {
mConnectionAttempt++;
mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
mCall.setConnectionService(mService);
setTimeoutIfNeeded(mService, attempt);
// 建立一路通話連結
mService.createConnection(mCall, this);
}
} else {
Log.v(this, "attemptNextPhoneAccount, no more accounts, failing");
DisconnectCause disconnectCause = mLastErrorDisconnectCause != null ?
mLastErrorDisconnectCause : new DisconnectCause(DisconnectCause.ERROR);
notifyCallConnectionFailure(disconnectCause);
}
}
}
準備綁定CALL APP中的
ConnectionService
服務,并且設定回調函數,這裡
Binder2
是
ServiceBinder
中的私有類,
public class ConnectionServiceWrapper extends ServiceBinder {
private final class Adapter extends IConnectionServiceAdapter.Stub {
// 通話連接配接成功後的回調接口
@Override
public void handleCreateConnectionComplete(String callId, ConnectionRequest request,
ParcelableConnection connection) {
try {
synchronized (mLock) {
logIncoming("handleCreateConnectionComplete %s", callId);
ConnectionServiceWrapper.this
.handleCreateConnectionComplete(callId, request, connection);
}
} finally {
Binder.restoreCallingIdentity(token);
Log.endSession();
}
}
}
....
}
ConnectionServiceWrapper(
ComponentName componentName,
ConnectionServiceRepository connectionServiceRepository,
PhoneAccountRegistrar phoneAccountRegistrar,
CallsManager callsManager,
Context context,
TelecomSystem.SyncRoot lock,
UserHandle userHandle) {
super(ConnectionService.SERVICE_INTERFACE, componentName, context, lock, userHandle);
....
}
private final Adapter mAdapter = new Adapter();
private Binder2 mBinder = new Binder2();
private IConnectionService mServiceInterface;
// 設定IConnectionService接口
@Override
protected void setServiceInterface(IBinder binder) {
mServiceInterface = IConnectionService.Stub.asInterface(binder);
Log.v(this, "Adding Connection Service Adapter.");
// 添加連接配接後的回調Adapter接口
addConnectionServiceAdapter(mAdapter);
}
public void createConnection(final Call call, final CreateConnectionResponse response) {
//建立 綁定通話連接配接服務的回調接口
BindCallback callback = new BindCallback() {
@Override
public void onSuccess() {
if (call == null) return;
String callId = mCallIdMapper.getCallId(call);
mPendingResponses.put(callId, response);
Bundle extras = call.getIntentExtras();
extras = updateIntentExtras(call, extras);
// 發送IPC請求到通話連結服務,告知其來電資訊
try {
mServiceInterface.createConnection(
call.getConnectionManagerPhoneAccount(),
callId,
new ConnectionRequest(
call.getTargetPhoneAccount(),
call.getHandle(),
extras,
call.getVideoState(),
callId),
call.shouldAttachToExistingConnection(),
call.isUnknown());
} catch (RemoteException e) {
.....
}
}
@Override
public void onFailure() {
....
}
};
// 綁定通話連接配接服務,并設定綁定回調函數
mBinder.bind(callback, call);
}
}
向通話賬戶中指定的元件
mComponentName
(在建立PhoneAccount時指定,實際是
TelephonyConnectionService
對象)發送綁定服務的請求,請求其處理動作名為:
"android.telecom.ConnectionService";
的消息:
// 用于綁定通話連結服務的抽象類
abstract class ServiceBinder {
// 綁定回調
interface BindCallback {
void onSuccess();
void onFailure();
}
// 執行綁定操作的Helper類
final class Binder2 {
void bind(BindCallback callback, Call call) {
mCallbacks.add(callback);
if (mServiceConnection == null) {
Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
ServiceConnection connection = new ServiceBinderConnection(call);
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();
}
}
}
// 綁定成功後的回調對象
private final class ServiceBinderConnection implements ServiceConnection {
private Call mCall;
ServiceBinderConnection(Call call) {
mCall = call;
}
@Override
public void onServiceConnected(ComponentName componentName, IBinder binder) {
try {
synchronized (mLock) {
mCall = null;
// 設定IBinder接口
mServiceConnection = this;
setBinder(binder);
handleSuccessfulConnection();
}
} finally {
Log.endSession();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
try {
synchronized (mLock) {
mServiceConnection = null;
handleServiceDisconnected();
}
} finally {
Log.endSession();
}
}
}
private void setBinder(IBinder binder) {
if (mBinder != binder) {
if (binder == null) {
removeServiceInterface();
mBinder = null;
} else {
mBinder = binder;
// 設定IBinder接口,即ConnectionServiceWrapper中的mService
setServiceInterface(binder);
}
}
}
}
為什麼這裡需要綁定一個了?
TelephonyConnectionService
的作用是Telephony子產品用來記錄以及維護目前通話資訊,當沒有通話時(既不存在來電,也沒有去電),telecom就會解綁
TelephonyConnectionService
。
TelephonyConnectionService
到現在,通過調用
ConnectionService
的接口
createConnection
,一個通話對象
Call
就跟
ConnectionService
建立了一個具體的連接配接,同時建立一個通話連接配接對象
connnection
傳回給
ConnectionServiceWrapper
:
public abstract class ConnectionService extends 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);
connection.setTelecomCallId(callId);
if (connection.getState() != Connection.STATE_DISCONNECTED) {
addConnection(callId, connection);
}
// 注意,mAdapter就是設定IConnectionService接口時設定的回調
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()));
}
}
調用
Adapter
中的接口調用
handleCreateConnectionComplete
,接着繼續調用
ConnectionServiceWrapper
中的函數
handleCreateConnectionComplete
繼續回調過程。調用
CreateConnectionProcessor
的接口
handleCreateConnectionSuccess
,以此繼調用
Call
中的回調接口
handleCreateConnectionSuccess
:
public class ConnectionServiceWrapper extends ServiceBinder {
// 儲存了上層調用CreateConnectionProcessor的接口
private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
private final class Adapter extends IConnectionServiceAdapter.Stub {
@Override
public void handleCreateConnectionComplete(String callId, ConnectionRequest request,
ParcelableConnection connection) {
long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
ConnectionServiceWrapper.this
.handleCreateConnectionComplete(callId, request, connection);
}
} finally {
Binder.restoreCallingIdentity(token);
Log.endSession();
}
}
}
private void handleCreateConnectionComplete(
String callId,
ConnectionRequest request,
ParcelableConnection connection) {
if (connection.getState() == Connection.STATE_DISCONNECTED) {
// fail
removeCall(callId, connection.getDisconnectCause());
} else {
// Successful connection
if (mPendingResponses.containsKey(callId)) {
mPendingResponses.remove(callId)
.handleCreateConnectionSuccess(mCallIdMapper, connection);
}
}
}
}
通話連接配接成功回調到了
Call
之後,會繼續通過回調的方式将消息傳給
CallsManager
:
public class Call implements CreateConnectionResponse {
private final Set<Listener> mListeners = Collections.newSetFromMap(
new ConcurrentHashMap<Listener, Boolean>(, f, ));
@Override
public void handleCreateConnectionSuccess(CallIdMapper idMapper,ParcelableConnection connection) {
setTargetPhoneAccount(connection.getPhoneAccount());
setHandle(connection.getHandle(), connection.getHandlePresentation());
setCallerDisplayName(
connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation());
....
switch (mCallDirection) {
case CALL_DIRECTION_INCOMING:
for (Listener l : mListeners) {
// 告訴CallsManager通話連接配接建立成功
l.onSuccessfulIncomingCall(this);
}
break;
....
}
}
}
Telecom與Call APP之間的互動
Telecom将來電與
ConnectionService
綁定後,就要講來電資訊告知上層UI了。作為Telecom服務的通話的管家,
CallsManager
收到連接配接建立成功的消息後,首先會對來電進行過濾操作(檢查通話是否需要轉接到語音信箱或者阻斷通話),如果來電是正常的,則準備将該通話與CALL APP的UI界面進行連接配接:
public class CallsManager extends Call.ListenerBase
implements VideoProviderProxy.Listener, CallFilterResultCallback {
private final List<CallsManagerListener> mListeners = new CopyOnWriteArrayList<>();
@Override
public void onSuccessfulIncomingCall(Call incomingCall) {
List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();
// 添加通話過濾類
filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));
filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter()));
// 確定可以連上UI界面
filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar,
mDefaultDialerManagerAdapter,
new ParcelableCallUtils.Converter(), mLock));
// 對來電進行過濾操作,完成後調用回調函數
new IncomingCallFilter(mContext, this, incomingCall, mLock,
mTimeoutsAdapter, filters).performFiltering();
}
@Override
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");
}
if (result.shouldAllowCall) {
// 通話路數超限,直接挂斷
if (hasMaximumRingingCalls()) {
rejectCallAndLog(incomingCall);
} else if (hasMaximumDialingCalls()) {
rejectCallAndLog(incomingCall);
} else {
// 添加通話
if (addSuccessfulIncomingCall(incomingCall)) {
if (incomingCall != null) addCall(incomingCall);
}
}
} else {
....
}
}
}
函數
addSuccessfulIncomingCall()
針對不同的使用者模式對通話進行處理,并打開話筒,處理傳回成功後,接着
addCall()
會将此路通話跟CALL APP的UI服務
ICallScreeningService
進行綁定,
private void addCall(Call call) {
if (call == null) {
return;
}
call.addListener(this);
mCalls.add(call);
// 更新call,狀态有變化時,通知監聽對象
updateCanAddCall();
// 調用監聽接口onCallAdded(),通知上層來電資訊
for (CallsManagerListener listener : mListeners) {
listener.onCallAdded(call);
}
....
}
}
在
CallsManager
初始化時,會添加一個叫
InCallController
的監聽類,其實作了
CallsManagerListenerBase
的接口;該監聽接口就是用于綁定上層通話界面的服務
IncallService
:
public final class InCallController extends CallsManagerListenerBase {
....
@Override
public void onCallAdded(Call call) {
// 服務沒有綁定,則重新綁定,綁定成功後,将通話添加到Incall
if (!isBoundToServices()) {
bindToServices(call);
} else {
// 記錄通話狀态,并打開audio
addCall(call);
List<ComponentName> componentsUpdated = new ArrayList<>();
for (Map.Entry<InCallServiceInfo, IInCallService> entry : mInCallServices.entrySet()) {
InCallServiceInfo info = entry.getKey();
componentsUpdated.add(info.getComponentName());
IInCallService inCallService = entry.getValue();
ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
true /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar(),
info.isExternalCallsSupported());
try {
//将此路通話添加IncallService
inCallService.addCall(parcelableCall);
} catch (RemoteException ignored) {
}
}
}
}
}
至此
CallsManager
就将來電告知InCallUI了,這時使用者就可以再手機上看到一個來電提醒的對話框了。