Android 6.0 MT流程

这段负责通话模块的开发,研究了一下telephony模块,网上参考了些资料加上自己的理解,总结了一下android6.0 MT 流程:。

先放出6.0的MT(来电)时序图大家有个直观感受,下面代码一步步进行分析

这里写图片描述

文章目录

第一部分:RIL–>GSMPhone Call状态变化 -> 发出来电通知(frameworks\opt\telephony)

1. framwork/opt/telephony/…/RIL.java

作用:RIL-Java在本质上就是一个RIL代理,起到一个转发的作用,是Android Java概念空间中的电话系统的起点
RIL接收到RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED消息

private void processUnsolicited (Parcel p) {
...
switch(response) {
...
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
                if (RILJ_LOGD) unsljLog(response);
 2、然后经由mCallStateRegistrants.notifyRegistrants发出通知
               mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));

BaseCommands.java registerForCallStateChanged() mCallStateRegistrants.add()

 @Override
    public void registerForCallStateChanged(Handler h, int what, Object obj) {
        Registrant r = new Registrant (h, what, obj);
        //添加到观察者列表 
        mCallStateRegistrants.add(r);
    }

重点1 这其实是观察者模式的一种实现形式
1.通知者(RegistrantList ) 和观察者(Registrant )是一个一对多的关系,在有事件更新时,凡是在名单上登记过的对象,都会收到通知。
2.RegistrantList通知者支持对通知者的增加(add/addUnique)删除(remove),并且能够发出通知(notifyRegitrants);而Registrant作为观察者,响应通知者发出的notifyRegistrant通知。
3.整体上这个消息注册机制分为两部分,消息注册和消息通知。当调用regist方法时将Message存放进去,当其调用notify方法时将所有Message取出并发送到MessageQueue中等待处理。

3. framwork/opt/telephony/…GSMCallTracker.java

作用:GSMCallTracker在本质上是一个Handler。GSMCallTracker是Android的通话管理层。GSMCallTracker建立了ConnectionList来管理现行的通话连接,并向上层提供电话调用接口。
查找察者被调用的地方, 两处被响应处理,其中一处:GSMCallTracker handleMessage

...//registerForCallStateChanged调用
 mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
...
 @Override
    public void
//响应处理
    handleMessage (Message msg) {
...
 case EVENT_CALL_STATE_CHANGE: //MT第一次
//调用父类CallTracker查询Call List方法
     pollCallsWhenSafe();
     break;

4、pollCallsWhenSafe()方法在CallTracker.java中实现

protected void pollCallsWhenSafe() {
 
        mNeedsPoll = true;
 
        if (checkNoOperationsPending()) {
            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
    5//RIL.java中的getCurrentCalls方法  
            mCi.getCurrentCalls(mLastRelevantPoll);
        }
    }

回到RIL.java getCurrentCalls 将RIL_REQUEST_GET_CURRENT_CALLS 消息封装成RILRequest
类型并发送。

@Override
    public void getCurrentCalls (Message result) {
        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
        send(rr);
    }

RIL.java 有三处接收处理RIL_REQUEST_GET_CURRENT_CALLS消息,真正的逻辑处理在processSolicited方法

private RILRequest processSolicited (Parcel p) {
...
case RIL_REQUEST_GET_CURRENT_CALLS: ret =  responseCallList(p); break;
...
if (rr.mResult != null) {
                    AsyncResult.forMessage(rr.mResult, ret, null);
                    rr.mResult.sendToTarget();//发出handler消息通知
                }

6、回到framworks/opt/telephony/…/telephony/gsm/GSMCallTracker.java

rr.mResult.sendToTarget()发出handler消息通知后,会在GSMCallTracker中的handleMessage方法中响应。并且它的消息类型是“EVENT_POLL_CALLS_RESULT"

@Override
    public void handleMessage (Message msg) {
        ...
        case EVENT_POLL_CALLS_RESULT:
                ar = (AsyncResult)msg.obj;
                if (msg == mLastRelevantPoll) {
                    mNeedsPoll = false;
                    mLastRelevantPoll = null;
         7handlePollCalls((AsyncResult)msg.obj);
                }
            break;

8、handlePollCalls方法根据RIL发出的Call List对象判断Call的状态,并发出不同的通知,

1) 新来电的通知是: phone.notifyNewRingingConnection;
另外两个是 :
2) 通话断开通知 onDisconnected;
3) Call状态变化通知 phone.notifiyPreciseCallStateChanged.
(当状态改变之后便会通过GsmPhone的notifyPreciseCallStateChanged()方法发起响应)
来电的时候发出的是phone.notifyNewRingConnection通知,进入到notifyNewRingConnection方法

handlePollCalls(){
...
if (newRinging != null) {
            mPhone.notifyNewRingingConnection(newRinging);
        }

9、framworks/opt/telephony/…/telephony/gsm/GSMPhone.java

 public void notifyNewRingingConnection(Connection c) {
        super.notifyNewRingingConnectionP(c);
    }

调用父类 PhoneBase.java(为com.android.internal.telephony.phone接口实现)
notifyNewRingingConnectionP()发出来电通知
mNewRingingConnectionRegistrants.notifyRegistrants(ar);

/**
     * Notify registrants of a new ringing Connection.
     * Subclasses of Phone probably want to replace this with a
     * version scoped to their packages
     */
    public void notifyNewRingingConnectionP(Connection cn) {
        if (!mIsVoiceCapable)
            return;
        AsyncResult ar = new AsyncResult(null, cn, null);
        mNewRingingConnectionRegistrants.notifyRegistrants(ar);
    }

重点2: RegistrantList.java \frameworks\base\core\java\android\os
notifyRegistrants方法实现

    public /*synchronized*/ void notifyRegistrants(AsyncResult ar){
        internalNotifyRegistrants(ar.result, ar.exception);
    }
    private synchronized void internalNotifyRegistrants (Object result, Throwable exception){
       for (int i = 0, s = registrants.size(); i < s ; i++) {
            Registrant  r = (Registrant) registrants.get(i);
            r.internalNotifyRegistrant(result, exception);
       }
    }
    /*package*/ void internalNotifyRegistrant (Object result, Throwable exception)
    {
        Handler h = getHandler();
 
        if (h == null) {
            clear();
        } else {
            Message msg = Message.obtain();
 
            msg.what = what;
            
            msg.obj = new AsyncResult(userObj, result, exception);
            
            h.sendMessage(msg);
        }
    }   

注册为观察者的方法为:

// Inherited documentation suffices.
    @Override
    public void registerForNewRingingConnection(
            Handler h, int what, Object obj) {
        checkCorrectThread(h);
 
        mNewRingingConnectionRegistrants.addUnique(h, what, obj);
    }

通过log发现PstnIncomingCallNotifier.java调用registerForNewRingingConnection()

01-05 07:10:05.517962  1596  1596 D Telephony: PstnIncomingCallNotifier: handleNewRingingConnection

第二部分:PstnIncomingCallNotifier–>Call 接收Framework层到通知–>准备创建连接

10、packages/services/Telephony/…/PstnIncomingCallNotifier.java(packages\services\telephony)

作用:监听来自相关电话对象的来电事件和通知,Telecom在每次发出的时候,这一实例都为每个电话的通话服务。

registerForNotifications方法调用registerForNewRingingConnection

    private void registerForNotifications() {
        Phone newPhone = mPhoneProxy.getActivePhone();
        if (newPhone != mPhoneBase) {
            unregisterForNotifications();
 
            if (newPhone != null) {
                Log.i(this, "Registering: %s", newPhone);
                mPhoneBase = newPhone;
                //调用registerForNewRingingConnection方法
                mPhoneBase.registerForNewRingingConnection(
                        mHandler, EVENT_NEW_RINGING_CONNECTION, null);
                mPhoneBase.registerForCallWaiting(
                        mHandler, EVENT_CDMA_CALL_WAITING, null);
                mPhoneBase.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION,
                        null);
            }
        }
    }

11、handle 处理EVENT_NEW_RINGING_CONNECTION消息

private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
        ...
            case EVENT_NEW_RINGING_CONNECTION:
                    handleNewRingingConnection((AsyncResult) msg.obj);
                    break;

12、从之前的log看: 由handleNewRingingConnection方法,处理新的来电连接。

    private void handleNewRingingConnection(AsyncResult asyncResult) {
        Log.d(this, "handleNewRingingConnection");
        Connection connection = (Connection) asyncResult.result;
        if (connection != null) {
            Call call = connection.getCall();
            //在发送intent到Telecom之前最后一次验证ringing 状态
            if (call != null && call.getState().isRinging()) {
                sendIncomingCallIntent(connection);
            }
        }
    }

13、sendIncomingCallIntent方法

发送incoming call intent到telecom,发送的Connection 类型,里面包括isIncoming getState isRinging等

    /**
     * Sends the incoming call intent to telecom.
     */
    private void sendIncomingCallIntent(Connection connection) {
        Bundle extras = null;
        if (connection.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED &&
                !TextUtils.isEmpty(connection.getAddress())) {
            extras = new Bundle();
            Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, connection.getAddress(), null);
            extras.putParcelable(TelephonyManager.EXTRA_INCOMING_NUMBER, uri);
        }
        TelecomManager.from(mPhoneProxy.getContext()).addNewIncomingCall(
                TelecomAccountRegistry.makePstnPhoneAccountHandle(mPhoneProxy), extras);
    }

14、addNewIncomingCall()定义在: framworks/base/telecomm/java/android/telecom/TelecomManager.java

作用:TelecomManager的功能则主要是对TelecomService提供的远程接口的封装,然后提供给应用使用。
来电时触发 addNewIncomingCall方法

    @SystemApi
    public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
        try {
            if (isServiceConnected()) {
                getTelecomService().addNewIncomingCall(
                        phoneAccount, extras == null ? new Bundle() : extras);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException adding a new incoming call: " + phoneAccount, e);
        }
    }

15、 packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java

继承自ITelecomService,TelecomService的接口由TeleComManager封装,并其供给应用使用,
重点2:telecom进程讲解
addNewIncomingCall
新建intent 设定intent 的ACTION 、addFalgs等

        /**
         * @see android.telecom.TelecomManager#addNewIncomingCall
         */
        @Override
        public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
            synchronized (mLock) {
                    long token = Binder.clearCallingIdentity();
                    try {
                        Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
                        intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
                            phoneAccountHandle);
                        intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, true);
                        if (extras != null) {
                            intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
                        }
                        CallIntentProcessor.processIncomingCallIntent(mCallsManager, intent);
                    } finally {
                        Binder.restoreCallingIdentity(token);
                    }
            }
        }

CallIntentProcessor.java (packages\services\telecomm\src\com\android\server\telecom)

    static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
        callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
    }

19、packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java

作用:
CallManager类提供了一个抽象层,以供phoneApp访问和控制call等操作;
它实现了Phone接口;
CallManager提供呼叫和连接控制以及Channel能力;
CallManager提供三种类型的API:
1,呼叫控制和操作,如dial()和hangup();
2,Channel的能力,如canconference();
3,注册通知。接着将Phone注册进mCM,Phone状态改变之后InCallUI就能够收到变化消息了。

    void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
        ....
        Call call = new Call(
                mContext,
                this,
                mLock,
                mConnectionServiceRepository,
                mContactsAsyncHelper,
                mCallerInfoAsyncQueryFactory,
                handle,
                null /* gatewayInfo */,
                null /* connectionManagerPhoneAccount */,
                phoneAccountHandle,
                true /* isIncoming */,
                false /* isConference */);
        call.setIntentExtras(extras);
        call.addListener(this);
20new一个Call 对象 把前面的参数传进来,然后调用call中建立连接的方法startCreateConnection
        call.startCreateConnection(mPhoneAccountRegistrar);
    }

21、packages/services/Telecomm/src/com/android/server/telecom/Call.java

作用:封装的一个给定的电话对象,在其整个生命周期的各个方面,从电话意图被telecom接收开始
建立连接队列,一旦完成创建,就应当有一个存在service里的活动(active)连接。

    void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
        Preconditions.checkState(mCreateConnectionProcessor == null);
        mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
                phoneAccountRegistrar, mContext);
        mCreateConnectionProcessor.process();
    }

第三部分:ConnectionServicesAdapter–>CallsManager 处理这个创建的连接–>成功来电 CallsManager–>Phone 成功来电–>准备启动界面

22、packages/services/Telecomm/src/com/android/server/telecom/CreateConnectionProcessor.java

    void process() {
        Log.v(this, "process");
        clearTimeout();
        mAttemptRecords = new ArrayList<>();
        if (mCall.getTargetPhoneAccount() != null) {
            mAttemptRecords.add(new CallAttemptRecord(
                    mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
        }
        adjustAttemptsForConnectionManager();
        adjustAttemptsForEmergency();
        mAttemptRecordIterator = mAttemptRecords.iterator();
        attemptNextPhoneAccount();
    }

23、service试图建立连接

private void attemptNextPhoneAccount() {
...
if (mResponse != null && attempt != null) {
            Log.i(this, "Trying attempt %s", attempt);
            ConnectionServiceWrapper service =
                    mRepository.getService(
                            attempt.connectionManagerPhoneAccount.getComponentName());
            if (service == null) {
                Log.i(this, "Found no connection service for attempt %s", attempt);
                attemptNextPhoneAccount();
            } else {
                mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
                mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
                mCall.setConnectionService(service);
                Log.i(this, "Attempting to call from %s", service.getComponentName());
                service.createConnection(mCall, new Response(service));
            }
        } 

24、packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java 为拨出的电话建立连接或者attach一个已经存在的来电。

    void createConnection(final Call call, final CreateConnectionResponse response) {
        mBinder.bind(callback);
    }

25、ServiceBinder.java (packages\services\telecomm\src\com\android\server\telecom)

作用
抽象类用来进行绑定和解绑到指定的服务接口的工作。
子类提供服务的意图和组件名,这个类调用受保护方法在类绑定、未绑定或失败的时候,执行绑定到服务的操作(如果还没有绑定)然后执行指定的回调方法。

       void bind(BindCallback callback, Call call) {
            Log.d(ServiceBinder.this, "bind()");
            // Reset any abort request if we're asked to bind again.
            clearAbort();
            if (!mCallbacks.isEmpty()) {
                // Binding already in progress, append to the list of callbacks and bail out.
                mCallbacks.add(callback);
                return;
            }
            mCallbacks.add(callback);
            if (mServiceConnection == null) {
                Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
                ServiceConnection connection = new ServiceBinderConnection(call);
                Log.event(call, Log.Events.BIND_CS, mComponentName);
                final int bindingFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
                final boolean isBound;
                if (mUserHandle != null) {
                    isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,
                            mUserHandle);
                } else {
                    isBound = mContext.bindService(serviceIntent, connection, bindingFlags);
                }
                if (!isBound) {
                    handleFailedConnection();
                    return;
                }
            } else {
                Log.d(ServiceBinder.this, "Service is already bound.");
                Preconditions.checkNotNull(mBinder);
                handleSuccessfulConnection();
            }
        }

26、上面的执行完之后,顺序执行到onServiceConnected

onServiceConnected

 private final class ServiceBinderConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder binder) {
            ThreadUtil.checkOnMainThread();
            Log.i(this, "Service bound %s", componentName);//这句log被打印出来了
            // Unbind request was queued so unbind immediately.
            if (mIsBindingAborted) {
                clearAbort();
                logServiceDisconnected("onServiceConnected");
                mContext.unbindService(this);
                handleFailedConnection();
                return;
            }
            mServiceConnection = this;
            setBinder(binder);
            handleSuccessfulConnection();
        }

27、handleSuccessfulConnection()

    private void handleSuccessfulConnection() {
        for (BindCallback callback : mCallbacks) {
            callback.onSuccess();
        }
        mCallbacks.clear();
    }

28、回调上面的onSuccess() 执行mServiceInterface.createConnectioncreateConnection的具体实现在ConnectionService.java (frameworks\base\telecomm\java\android\telecom)

作用:一个提供电话连接到Android设备上运行的进程。

        @Override
        public void createConnection(
                PhoneAccountHandle connectionManagerPhoneAccount,
                String id,
                ConnectionRequest request,
                boolean isIncoming,
                boolean isUnknown) {
            //chengzhi
            SomeArgs args = SomeArgs.obtain();
            args.arg1 = connectionManagerPhoneAccount;
            args.arg2 = id;
            args.arg3 = request;
            args.argi1 = isIncoming ? 1 : 0;
            args.argi2 = isUnknown ? 1 : 0;
29、        mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
        }

30、MSG_CREATE_CONNECTION

case MSG_CREATE_CONNECTION: {
                         createConnection(
                                    connectionManagerPhoneAccount,
                                    id,
                                    request,
                                    isIncoming,
                                    isUnknown);
}

31、这个方法可以被telecom用来创建呼出电话或者一个已存在的来电。任何一种情况,telecom都会循环经过一系列的服务和 调用createConnection util a connection service取消或者成功完成创建。

    private void createConnection(
            final PhoneAccountHandle callManagerAccount,
            final String callId,
            final ConnectionRequest request,
            boolean isIncoming,
            boolean isUnknown) {
        Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
                : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
                : onCreateOutgoingConnection(callManagerAccount, request);
        .....
        mAdapter.handleCreateConnectionComplete

32、前面建立连接成功了,后面处理成功的连接,后面执行mAdapter.handleCreateConnectionComplete

ConnectionServiceAdapter>CallsManager 处理这个创建的连接>成功来电

33~34.ConnectionServiceAdapter.java (frameworks\base\telecomm\java\android\telecom)

作用:提供iconnectionservice实现与系统的手机应用程序的交互方法。

    void handleCreateConnectionComplete(
            String id,
            ConnectionRequest request,
            ParcelableConnection connection) {
        for (IConnectionServiceAdapter adapter : mAdapters) {
            try {
                //chengzhi 03
                adapter.handleCreateConnectionComplete(id, request, connection);
            } catch (RemoteException e) {
            }
        }
    }

CallsManager>Phone 成功来电>准备启动界面

33. packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java

作用:Telecomm 层的连接管理者

    private final class Adapter extends IConnectionServiceAdapter.Stub {
 
        @Override
        public void handleCreateConnectionComplete(
                String callId,
                ConnectionRequest request,
                ParcelableConnection connection) {
            logIncoming("handleCreateConnectionComplete %s", request);
                    if (mCallIdMapper.isValidCallId(callId)) {
                        ConnectionServiceWrapper.this
                                .handleCreateConnectionComplete(callId, request, connection);
                    }
        }

ConnectionServiceAdapterServant.java (frameworks\base\telecomm\java\android\telecom)

    private final IConnectionServiceAdapter mStub = new IConnectionServiceAdapter.Stub() {
        @Override
        public void handleCreateConnectionComplete(
                String id,
                ConnectionRequest request,
                ParcelableConnection connection) {
            SomeArgs args = SomeArgs.obtain();
            args.arg1 = id;
            args.arg2 = request;
            args.arg3 = connection;
            mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_COMPLETE, args).sendToTarget();
        }

34、 handleMessage处理消息 MSG_HANDLE_CREATE_CONNECTION_COMPLETE

        // Internal method defined to centralize handling of RemoteException
        private void internalHandleMessage(Message msg) throws RemoteException {
            switch (msg.what) {
                case MSG_HANDLE_CREATE_CONNECTION_COMPLETE: {
                    SomeArgs args = (SomeArgs) msg.obj;
                    try {
                        mDelegate.handleCreateConnectionComplete(
                                (String) args.arg1,
                                (ConnectionRequest) args.arg2,
                                (ParcelableConnection) args.arg3);
                    } finally {
                        args.recycle();
                    }
                    break;
                }

35、 如果成功连接 ConnectionServiceWrapper.java (packages\services\telecomm\src\com\android\server\telecom)

    private void handleCreateConnectionComplete(
            String callId,
            ConnectionRequest request,
            ParcelableConnection connection) {
        // TODO: Note we are not using parameter "request", which is a side effect of our tacit
        // assumption that we have at most one outgoing connection attempt per ConnectionService.
        // This may not continue to be the case.
        if (connection.getState() == Connection.STATE_DISCONNECTED) {
            // A connection that begins in the DISCONNECTED state is an indication of
            // failure to connect; we handle all failures uniformly
            removeCall(callId, connection.getDisconnectCause());
        } else {
            // Successful connection
            if (mPendingResponses.containsKey(callId)) {
                mPendingResponses.remove(callId)
                        .handleCreateConnectionSuccess(mCallIdMapper, connection);
            }
        }
    }

重写 handleCreateConnectionSuccess方法

36. packages/services/Telecomm/src/com/android/server/telecom/Call.java handleCreateConnetionSucess()

@Override
    public void handleCreateConnectionSuccess(
            CallIdMapper idMapper,
            ParcelableConnection connection) {
        Log.v(this, "handleCreateConnectionSuccessful %s", connection);
        mCreateConnectionProcessor = null;
        setTargetPhoneAccount(connection.getPhoneAccount());
        setHandle(connection.getHandle(), connection.getHandlePresentation());
        setCallerDisplayName(
                connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation());
        setCallCapabilities(connection.getCapabilities());
        setVideoProvider(connection.getVideoProvider());
        setVideoState(connection.getVideoState());
        setRingbackRequested(connection.isRingbackRequested());
        setIsVoipAudioMode(connection.getIsVoipAudioMode());
        setStatusHints(connection.getStatusHints());
 
        mConferenceableCalls.clear();
        for (String id : connection.getConferenceableConnectionIds()) {
            mConferenceableCalls.add(idMapper.getCall(id));
        }
 
        if (mIsUnknown) {
            for (Listener l : mListeners) {
                l.onSuccessfulUnknownCall(this, getStateFromConnectionState(connection.getState()));
            }
        } else if (mIsIncoming) {
            // We do not handle incoming calls immediately when they are verified by the connection
            // service. We allow the caller-info-query code to execute first so that we can read the
            // direct-to-voicemail  property before deciding if we want to show the incoming call to
            // the user or if we want to reject the call.
            mDirectToVoicemailQueryPending = true;
 
            // Timeout the direct-to-voicemail lookup execution so that we dont wait too long before
            // showing the user the incoming call screen.
            mHandler.postDelayed(mDirectToVoicemailRunnable, Timeouts.getDirectToVoicemailMillis(
                    mContext.getContentResolver()));
        } else {
            for (Listener l : mListeners) {
                l.onSuccessfulOutgoingCall(this,
                        getStateFromConnectionState(connection.getState()));
            }
        }
    }

37、 Runnable mDirectToVoicemailRunnable

    private final Runnable mDirectToVoicemailRunnable = new Runnable() {
        @Override
        public void run() {
            processDirectToVoicemail();
        }

38、processDirectToVoicemail

final class Call implements CreateConnectionResponse {
    /**
     * Listener for events on the call.
     */
    interface Listener {
        void onSuccessfulIncomingCall(Call call);
...
    private void processDirectToVoicemail() {
        if (mDirectToVoicemailQueryPending) {
            if (mCallerInfo != null && mCallerInfo.shouldSendToVoicemail) {
                Log.i(this, "Directing call to voicemail: %s.", this);
                // TODO: Once we move State handling from CallsManager to Call, we
                // will not need to set STATE_RINGING state prior to calling reject.
                setState(CallState.RINGING);
                reject(false, null);
            } else {
                // TODO: Make this class (not CallsManager) responsible for changing
                // the call state to STATE_RINGING.
                // TODO: Replace this with state transition to STATE_RINGING.
                for (Listener l : mListeners) {
                    l.onSuccessfulIncomingCall(this);
                }
            }
            mDirectToVoicemailQueryPending = false;
        }
    }

39. package/services/Telecomm/src/com/android/server/telecom/CallsManager.java

39.1onSuccessfulIncomingCall if 判断后 addCall()

public final class CallsManager extends Call.ListenerBase {
...
    @Override
    public void onSuccessfulIncomingCall(Call incomingCall) {
        Log.d(this, "onSuccessfulIncomingCall");
        setCallState(incomingCall, CallState.RINGING);
 
        if (hasMaximumRingingCalls(incomingCall.getTargetPhoneAccount().getId())) {
            incomingCall.reject(false, null);
            // since the call was not added to the list of calls, we have to call the missed
            // call notifier and the call logger manually.
            mMissedCallNotifier.showMissedCallNotification(incomingCall);
            mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE);
        } else {
            incomingCall.mIsActiveSub = true;
            addCall(incomingCall);
            setActiveSubscription(incomingCall.getTargetPhoneAccount().getId());
        }
    }

39.2 addCall()

    /**
     * Adds the specified call to the main list of live calls.
     *
     * @param call The call to add.
     */
    private void addCall(Call call) {
        Log.v(this, "addCall(%s)", call);
 
        call.addListener(this);
        mCalls.add(call);
 
        // TODO: Update mForegroundCall prior to invoking
        // onCallAdded for calls which immediately take the foreground (like the first call).
        for (CallsManagerListener listener : mListeners) {
            listener.onCallAdded(call);
        }
        updateForegroundCall();
    }

第四部分:CallList–>InCallActivity 开始启动界面 -->显示来电

40、package/services/Telecomm/src/com/android/server/telecom/InCallController.java

作用:结合并提供服务,通过它可以将更新发送到呼叫程序。这类被创建和拥有的callsmanager保持绑定到(被调用的应用程序中实现)。

重写onCallAdded -->

    @Override
    public void onCallAdded(Call call) {
        if (!isBoundToServices()) {
            bindToServices(call);
        } else {
            adjustServiceBindingsForEmergency();
            Log.i(this, "onCallAdded: %s", call);
            // Track the call if we don't already know about it.
            addCall(call);
            for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
                ComponentName componentName = entry.getKey();
                IInCallService inCallService = entry.getValue();
                ParcelableCall parcelableCall = toParcelableCall(call,
                        true /* includeVideoProvider */);
                try {
                    inCallService.addCall(parcelableCall);
                } catch (RemoteException ignored) {
                }
            }
        }
    }

41、bindToServices – bindToInCallService

    InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();

    private class InCallServiceConnection implements ServiceConnection {
        /** {@inheritDoc} */
        @Override public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(this, "onServiceConnected: %s", name);
            onConnected(name, service);
        }

42 、onConnected()

    private void onConnected(ComponentName componentName, IBinder service) {
        addCall(call);
    }

43. framworks/base/telecomm/java/android/telecom/InCallService.java

作用:这个服务可以被任何希望提供管理电话的用户界面的应用实现,
当那个服务存在一个电话telecom就去绑定这个服务并用它去通知任何活动状态和最近断开的呼叫的被调用的应用
addCall()

    /** Manages the binder calls so that the implementor does not need to deal with it. */
    private final class InCallServiceBinder extends IInCallService.Stub {
        @Override
        public void setInCallAdapter(IInCallAdapter inCallAdapter) {
            mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
        }
 
        @Override
        public void addCall(ParcelableCall call) {
            mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
        }

44. handleMessage 处理消息 MSG_ADD_CALL

    /** Default Handler used to consolidate binder method calls onto a single thread. */
    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            if (mPhone == null && msg.what != MSG_SET_IN_CALL_ADAPTER) {
                return;
            }
 
            switch (msg.what) {
                case MSG_SET_IN_CALL_ADAPTER:
                    mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
                    onPhoneCreated(mPhone);
                    break;
                case MSG_ADD_CALL:
                    mPhone.internalAddCall((ParcelableCall) msg.obj);
                    break;

45. framworks/base/telecomm/java/android/telecom/Phone.java

作用:一个统一的虚拟设备提供语音手段(和其他)设备上的通信。
internalAddCall()

    final void internalAddCall(ParcelableCall parcelableCall) {
        Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
                parcelableCall.mIsActiveSub);
        mCallByTelecomCallId.put(parcelableCall.getId(), call);
        mCalls.add(call);
        checkCallTree(parcelableCall);
        call.internalUpdate(parcelableCall, mCallByTelecomCallId);
        fireCallAdded(call);
     }

45.1、fireCallAdded()

    private void fireCallAdded(Call call) {
        for (Listener listener : mListeners) {
            listener.onCallAdded(this, call);
        }
    }

46、onCallAdded()@SystemApi系统Api,一个空的实现方法 其他使用的地方会

@SystemApi
public final class Phone {

    public abstract static class Listener {
    ...
    public void onCallAdded(Phone phone, Call call) { }

47. pacakge/apps/InCallUI/src/com/android/incallui/CallList.java

作用:保持主动呼叫的列表和通知感兴趣的类关于这个列表的变化,因为他们是从堆栈收到电话,
对这个类变化的主要听众是InCallPresenter
@Override
onCallAdded

    /**
     * Static singleton accessor method.
     */
    public static CallList getInstance() {
        return sInstance;
    }
 
    private Phone.Listener mPhoneListener = new Phone.Listener() {
        @Override
        public void onCallAdded(Phone phone, android.telecom.Call telecommCall) {
            Call call = new Call(telecommCall);
            if (call.getState() == Call.State.INCOMING) {
                onIncoming(call, call.getCannedSmsResponses());
            } else {
                onUpdate(call);
            }
        }

48、执行了下面的方法,但再往后的步骤不是从这里走的。

onIncoming()

    /**
     * Called when a single call has changed.
     */
    public void onIncoming(Call call, List<String> textMessages) {
        Log.d(this, "onIncoming - " + call);
 
        // Update active subscription from call object. it will be set by
        // Telecomm service for incoming call and whenever active sub changes.
        if (call.mIsActiveSub) {
            long sub = call.getSubId();
            Log.d(this, "onIncoming - sub:" + sub + " mSubId:" + mSubId);
            if (sub != mSubId) {
                setActiveSubscription(sub);
            }
        }
 
        if (updateCallInMap(call)) {
            Log.i(this, "onIncoming - " + call);
        }
        updateCallTextMap(call, textMessages);
 
        for (Listener listener : mListeners) {
            listener.onIncomingCall(call);
        }
    }

49. //pacakge/apps/InCallUI/src/com/android/incallui/InCallPresenter.java

作用:接受来至CallList的更新并通知InCallActivity(UI)的变化。负责为一个新的呼叫启动活动和当通话断开时结束activity

onIncomingCall是一个接口以下是它的实现

    /**
     * Called when there is a new incoming call.
     *
     * @param call
     */
    @Override
    public void onIncomingCall(Call call) {
        InCallState newState = startOrFinishUi(InCallState.INCOMING);
        InCallState oldState = mInCallState;
 
        Log.i(this, "Phone switching state: " + oldState + " -> " + newState);
        mInCallState = newState;
 
        for (IncomingCallListener listener : mIncomingCallListeners) {
            listener.onIncomingCall(oldState, mInCallState, call);
        }
 
        if (CallList.getInstance().isDsdaEnabled() && (mInCallActivity != null)) {
            mInCallActivity.updateDsdaTab();
        }
    }

50、startUi

  showInCall(false /* showDialpad */, !showAccountPicker /* newOutgoingCall */);

51、showInCall

    public void showInCall(final boolean showDialpad, final boolean newOutgoingCall) {
        Log.i(this, "Showing InCallActivity");
        mContext.startActivity(getInCallIntent(showDialpad, newOutgoingCall));
    }

总结

以下是MT流程的类图,我们就根据这个图做下最后总结

这里写图片描述

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值