天天看點

Android TelecomService的來電處理過程

在上一篇文章裡,講到了TelecomService的啟動與初始化,這裡我們着重以來電(Mobile Terminal)過程來分析一下TelecomService是如何傳遞通話資訊并最終與上層UI互動的。主要分以下幾個部分:

  • 來電後,Telephony中間層如何将通話通知到TelecomService;
  • TelecomService如何建立通話連接配接;
  • TelecomService如何告知UI來電資訊
TelecomService的初始化過程:http://blog.csdn.net/jason_wzn/article/details/58164251

下圖是來電在Telecom服務中的處理流程,可以讓我們對整個流程有個感性的認識。

Android TelecomService的來電處理過程

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

了?

TelephonyConnectionService

的作用是Telephony子產品用來記錄以及維護目前通話資訊,當沒有通話時(既不存在來電,也沒有去電),telecom就會解綁

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了,這時使用者就可以再手機上看到一個來電提醒的對話框了。