Android TelecomServiceの着信処理

55120 ワード

前回の記事では、TelecomServiceの起動と初期化について説明しましたが、ここでは、TelecomServiceがどのように通話情報を伝達し、最終的に上位UIとインタラクティブになるかを、電話(Mobile Terminal)プロセスで分析することに重点を置いています.主に以下の部分に分けられます.
  • から電話がかかってきた後、Telephony中間層はどのようにTelecomServiceに通話を通知しますか?
  • TelecomServiceはどのように通話接続を確立しますか?
  • TelecomServiceがUI着信情報
  • を通知する方法
    TelecomServiceの初期化プロセス:http://blog.csdn.net/jason_wzn/article/details/58164251
    次の図はTelecomサービスにおける着信処理の流れであり、プロセス全体を感性的に認識することができる.
    Telephony将来電報通知TelcomService
    Phoneプロセスが初期化されると、2つの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 mAccounts = new LinkedList();
    
                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 >= 0 && 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オブジェクトのComponentNameは、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に着信がある限り、PhonePstnIncomingCallNotifierのスレッドメッセージキューにメッセージを送信し、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();
                        }
                    }
                }
            }
    
        }
    

    CallInentProcessorの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の中で1つの通話を維持するすべての情報を保存した.
    
        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サービスをバインドし、コールバック関数を設定します.ここでBinder2ServiceBinderのプライベートクラスです.
    
        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を呼び出すことによって、1つの通話オブジェクトCallConnectionServiceと特定の接続を確立し、同時に1つの通話接続オブジェクト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 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 mListeners = Collections.newSetFromMap(
                    new ConcurrentHashMap(8, 0.9f, 1));
    
            @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アプリ間のインタラクション
    Telecomは将来、ConnectionServiceに接続された後、着信情報を話して上位UIに通知します.Telecomサービスの通話の執事として、CallsManagerは接続が成功したというメッセージを受け取った後、まず着信をフィルタリングし(通話が音声メールに転送される必要があるかどうか、または通話を遮断する必要があるかどうかを確認する)、着信が正常であれば、この通話をCALLアプリのUIインタフェースに接続する準備をしている.
    
        public class CallsManager extends Call.ListenerBase
                implements VideoProviderProxy.Listener, CallFilterResultCallback {
    
            private final List mListeners = new CopyOnWriteArrayList<>();
    
            @Override
            public void onSuccessfulIncomingCall(Call incomingCall) {
                List 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 componentsUpdated = new ArrayList<>();
                    for (Map.Entry 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に電話で通知され、ユーザーは携帯電話で着信通知のダイアログボックスを見ることができます.