Android O来电call流程

Version:1.0 StartHTML:0000000194 EndHTML:0000209014 StartFragment:0000024273 EndFragment:0000208974 SourceURL:file:///Y:\Desktop\学习\新建文件夹\%5bAndroid%20O来电call流程.docx

Android O来电call流程

 

frameworktelephony

  1. 来电的消息属于主动上报的UnSolicited消息,其对应的事件ID是CALL_STATE_CHANGE,首先会调用RadioIndication.java中的callStateChanged方法来通知上层,这个时候会调用RIL.java中的processIndication方法,来向底层发送确认消息

      public void callStateChanged(int indicationType) {

        mRil.processIndication(indicationType);

        if (RIL.RILJ_LOGD) mRil.unsljLog(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED);

        mRil.mCallStateRegistrants.notifyRegistrants();

}

 

    public void processIndication(int indicationType) {

        if (indicationType == RadioIndicationType.UNSOLICITED_ACK_EXP) {

            sendAck();

            if (RILJ_LOGD) riljLog("Unsol response received; Sending ack to ril.cpp");

        } else {

            // ack is not expected to be sent back. Nothing is required to be done here.

        }

}

 

  1. 这里通知完毕会调用notifyRegistrants方法来通知已注册的观察者(观察者模式)。在GsmCdmaCallTracker初始化的时候,就已经注册了,并传入了自身的handler,用来处理EVENT_CALL_STATE_CHANGE消息。

    public GsmCdmaCallTracker (GsmCdmaPhone phone) {

…………………………

        mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);

…………………….

}

 

    @Override

    public void handleMessage(Message msg) {

        AsyncResult ar;

        switch (msg.what) {

。。。。。。。。。。。。。。。。。

            case EVENT_CALL_STATE_CHANGE:

                pollCallsWhenSafe();

            break;

。。。。。。。。。。。。。。。。。

      }

    }

 

  1. 接下来就会调用pollCallsWhenSafe方法,这里的mCi,实质上可以看成是RIL.java对象,这里调用了它的getCurrentCalls方法来重新去获取了当前call的状态。

    protected void pollCallsWhenSafe() {

        mNeedsPoll = true;

        if (checkNoOperationsPending()) {

            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);

            mCi.getCurrentCalls(mLastRelevantPoll);

        }

    }

 

  1. 来到了RIL.java中的getCurrentCalls方法,这里会创建一个请求消息,然后通过Radio代理来向底层发起请求。

    public void getCurrentCalls(Message result) {

        IRadio radioProxy = getRadioProxy(result);

        if (radioProxy != null) {

//创建一个请求消息

            RILRequest rr = obtainRequest(RIL_REQUEST_GET_CURRENT_CALLS, result,

                    mRILDefaultWorkSource);

…….

//向底层发起请求

            try {

                radioProxy.getCurrentCalls(rr.mSerial);

            } catch (RemoteException | RuntimeException e) {

                handleRadioProxyExceptionForRR(rr, "getCurrentCalls", e);

            }

        }

    }

 

  1. 等待modem层返回结果给RIL层,调用RadioResponse中的responseCurrentCalls方法。(N上的processSolicited的消息回复被抽取到这个类来了),通过底层返回的消息创建了dcCalls对象,也就是当前的Call状态信息,对dc状态进行判断后如果有需要就notify通知,如果没有异常则通过sendMessageResponse方法发送消息

private void responseCurrentCalls(RadioResponseInfo responseInfo,

                                      ArrayList<android.hardware.radio.V1_0.Call> calls) {

判断电话状态,进行notify通知

       …………

//发送返回消息

            if (responseInfo.error == RadioError.NONE) {

                sendMessageResponse(rr.mResult, dcCalls);

            }

            mRil.processResponseDone(rr, responseInfo, dcCalls);

        }

    }

 

  1. 之前说过,GsmCdmaCallTracker注册了观察者,这里返回的消息就会发送给他之前注册时候传入的handler来进行处理,这里我们回到GsmCdmaCallTracker中的handleMessage方法中。因为之前我们发送的是EVENT_POLL_CALLS_RESULT消息,所以我们这里只看EVENT_POLL_CALLS_RESULT消息。

    public void handleMessage(Message msg) {

        AsyncResult ar;

        switch (msg.what) {

            case EVENT_POLL_CALLS_RESULT:

                Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");

                if (msg == mLastRelevantPoll) {

                    if (DBG_POLL) log(

                            "handle EVENT_POLL_CALL_RESULT: set needsPoll=F");

                    mNeedsPoll = false;

                    mLastRelevantPoll = null;

                    handlePollCalls((AsyncResult)msg.obj);

                }

            break;

                            ……..

                   }

    }

 

  1. 继续追踪handlePollCalls方法,在这方法中先对底层反馈的消息进行解析,获取其通话状态,判断如果是来电则发出notifyNewRingingConnection响铃消息通知,然后进行一些通话断开连接的操作及更新phone状态。继续跟进notifyNewRingingConnection响铃消息,该消息调用的是phone的方法。

    protected synchronized void handlePollCalls(AsyncResult ar) {

        //解析返回的结果

        for (int i = 0, curDC = 0, dcSize = polledCalls.size()

                ; i < mConnections.length; i++) {

            GsmCdmaConnection conn = mConnections[i];

            DriverCall dc = null;

 

            // polledCall list is sparse

            if (curDC < dcSize) {

                dc = (DriverCall) polledCalls.get(curDC);

 

                if (dc.index == i+1) {

                    curDC++;

                } else {

                    dc = null;

                }

            }

            ...

            if (conn == null && dc != null) {

            ...状态的处理及识别

 

        //响铃消息通知

        if (newRinging != null) {

            mPhone.notifyNewRingingConnection(newRinging);

        }

 

        // clear the "local hangup" and "missed/rejected call"

        // cases from the "dropped during poll" list

        // These cases need no "last call fail" reason

        ArrayList<GsmCdmaConnection> locallyDisconnectedConnections = new ArrayList<>();

        for (int i = mDroppedDuringPoll.size() - 1; i >= 0 ; i--) {

            GsmCdmaConnection conn = mDroppedDuringPoll.get(i);

            //CDMA

            boolean wasDisconnected = false;

            //来电处理,本地挂断或者未接,本地挂断的话直接设置挂断的原因为LOCAL或INVALID_NUMBER

            if (conn.isIncoming() && conn.getConnectTime() == 0) {

                // Missed or rejected call

                int cause;

                if (conn.mCause == DisconnectCause.LOCAL) {

                    cause = DisconnectCause.INCOMING_REJECTED;

                } else {

                    cause = DisconnectCause.INCOMING_MISSED;

                }

 

                if (Phone.DEBUG_PHONE) {

                    log("missed/rejected call, conn.cause=" + conn.mCause);

                    log("setting cause to " + cause);

                }

                mDroppedDuringPoll.remove(i);

                hasAnyCallDisconnected |= conn.onDisconnect(cause);

                wasDisconnected = true;

                locallyDisconnectedConnections.add(conn);

            } else if (conn.mCause == DisconnectCause.LOCAL

                    || conn.mCause == DisconnectCause.INVALID_NUMBER) {

                mDroppedDuringPoll.remove(i);

                hasAnyCallDisconnected |= conn.onDisconnect(conn.mCause);

                wasDisconnected = true;

                locallyDisconnectedConnections.add(conn);

            }

 

            if (!isPhoneTypeGsm() && wasDisconnected && unknownConnectionAppeared

                    && conn == newUnknownConnectionCdma) {

                unknownConnectionAppeared = false;

                newUnknownConnectionCdma = null;

            }

        }

        if (locallyDisconnectedConnections.size() > 0) {

            mMetrics.writeRilCallList(mPhone.getPhoneId(), locallyDisconnectedConnections);

        }

 

        /* Disconnect any pending Handover connections */

        //通话断开的一些处理操作

        ...

        if (newRinging != null || hasNonHangupStateChanged || hasAnyCallDisconnected) {

            internalClearDisconnected();

        }

        //更新phone状态

        if (VDBG) log("handlePollCalls calling updatePhoneState()");

        updatePhoneState();

        ...

    }

 

  1. 查看一下是如何往上通知响铃消息的,同样的观察者模式,通知到注册的人

public void notifyNewRingingConnectionP(Connection cn) {

        if (!mIsVoiceCapable)

            return;

        AsyncResult ar = new AsyncResult(null, cn, null);

        mNewRingingConnectionRegistrants.notifyRegistrants(ar);

}

         查看发现,CallsManager注册了,所以这个时候会同时到CallsManager,

protected void registerForPhoneStates(Phone phone) {

                   …………..

phone.registerForNewRingingConnection(handler, EVENT_NEW_RINGING_CONNECTION,

                mRegistrantidentifier);

}

同样的,来到CallsManager中的handleMessage方法查看EVENT_NEW_RINGING_CONNECTION消息处理。再判断完是否需要挂断之后,会通知到PstnIncommingCallNotifier来处理此消息。这里会调用handleNewRingingConnection方法,来

sendIncomingCallIntent。

    private void handleNewRingingConnection(AsyncResult asyncResult) {

        Log.d(this, "handleNewRingingConnection");

        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()) {

                if (ExtensionManager.getDigitsUtilExt().isConnectionMatched(connection,

                        mPhoneAccountHandle, mPhone.getContext()) == false) {

                    return;

                }

                sendIncomingCallIntent(connection);

            }

        }

    }

 

Telephony-Service

  1. 在sendIncomingCallIntent方法中,获取了teltecom的服务,调用到了telecomService 的addNewIncomingCall方法。

    private void sendIncomingCallIntent(Connection connection) {

        Bundle extras = new Bundle();

        //extras填充一些数据

        ...

        PhoneAccountHandle handle = findCorrectPhoneAccountHandle();

        if (handle == null) {

          //挂断

        } else {

            TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras);

        }

    }

    //获取telecomm服务

    public static TelecomManager from(Context context) {

        return (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);

}

 

  1. 接下来来到了TelecomServiceImpl类中,在addNewIncomingCall方法中调用了CallIntentProcessor的processIncomingCallIntent方法,再往后就调用了package中telecom中的callsManager的processIncomingCallIntent方法

void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {

        Log.d(this, "processIncomingCallIntent");

        ...

        Call call = new Call(

                getNextCallId(),

                mContext,

                this,

                mLock,

                mConnectionServiceRepository,

                mContactsAsyncHelper,

                mCallerInfoAsyncQueryFactory,

                mPhoneNumberUtilsAdapter,

                handle,

                null /* gatewayInfo */,

                null /* connectionManagerPhoneAccount */,

                phoneAccountHandle,

                Call.CALL_DIRECTION_INCOMING /* callDirection */,

                false /* forceAttachToExistingConnection */,

                false, /* isConference */

                mClockProxy);

 

        ...

        call的一些状态设置

        ...

        call.initAnalytics();

        if (getForegroundCall() != null) {

            getForegroundCall().getAnalytics().setCallIsInterrupted(true);

            call.getAnalytics().setCallIsAdditional(true);

        }

        setIntentExtrasAndStartTime(call, extras);

        //添加监听

        // TODO: Move this to be a part of addCall()

        call.addListener(this);

 

        if (!isHandoverAllowed || (call.isSelfManaged() && !isIncomingCallPermitted(call,

                call.getTargetPhoneAccount()))) {

            notifyCreateConnectionFailed(phoneAccountHandle, call);

        } else {

            //成功上报上去建立连接

            call.startCreateConnection(mPhoneAccountRegistrar);

        }

    }

 

  1. 来到CallsManager的processIncomingCallIntent方法中,在这个方法中,会创建一个call对象,创建完毕之后会调用startCreateConnection去创建connection,这里会调用到ConnectionService中的createConnection方法。(注意,无论是什么都会在这里建立连接)

 

  1. 这里只管incomingcall的情况,会调用onCreateIncomingConnection方法。

 

   Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)

      : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)

      : onCreateOutgoingConnection(callManagerAccount, request);

 

    public Connection onCreateIncomingConnection(

            PhoneAccountHandle connectionManagerPhoneAccount,

            ConnectionRequest request) {

        return null;

}

 

  1. 在这里并没有实现,该方法的实现应该在该类的子类中,跟进到其子类TelephonyConnectionService中,在onCreateIncomingConnection方法中,调用了createConnectionFor来创建连接。

 

  1. 创建完毕之后,会通知到ConnectionServiceWrapper中,调用handleCreateConnectionComplete方法、

        public void handleCreateConnectionComplete(String callId, ConnectionRequest request,

                ParcelableConnection connection, Session.Info sessionInfo) {

                ...

                    logIncoming("handleCreateConnectionComplete %s", callId);

                    ConnectionServiceWrapper.this

                            .handleCreateConnectionComplete(callId, request, connection);

                ...

        }

 

         跟进handleCreateConnectionComplete,mPendingResponses是hashMap容器,每次在 createConnection 的时候会将对象加入该容器,如果此时connection还未断开的,会移除此connection,调用hanleCreateConnectionSuccess方法。 往上追溯createConnection跟踪到mService.createConnection(mCall, this); CreateConnectionProcessor.java会把自身传入,发现该类也实现了 CreateConnectionResponse ,所以这里的 handleCreateConnectionSuccess

调用的是CreateConnectionProcessor类里面的方法

 

    private void handleCreateConnectionComplete(

            String callId,

            ConnectionRequest request,

            ParcelableConnection connection) {

        ...

        if (connection.getState() == Connection.STATE_DISCONNECTED) {

            removeCall(callId, connection.getDisconnectCause());

        } else {

            // Successful connection

            if (mPendingResponses.containsKey(callId)) {

                String num = connection.getHandle().getSchemeSpecificPart();

                /// M: add for CMCC L + C ecc retry

                if (PhoneNumberUtils.isEmergencyNumber(num)) {

                    mPendingResponses.get(callId).

                             handleCreateConnectionSuccess(mCallIdMapper, connection);

                } else {

                    mPendingResponses.remove(callId)

                            .handleCreateConnectionSuccess(mCallIdMapper, connection);

                }

            }

        }

}

 

  1. 继续跟进 CreateConnectionProcessor 中的此方法,这里根据来电类型,触发回调,监听者会收到通知,之前在CallManager中执行 processIncomingCallIntent 方法创建Call的时候就添加了监听,所以最后会回调到 CallsManager中

    public void handleCreateConnectionSuccess(

            CallIdMapper idMapper,

            ParcelableConnection connection) {

        if (mCallResponse == null) {

            mService.abort(mCall);

        } else {

 

            mCallResponse.handleCreateConnectionSuccess(idMapper, connection);

 

            String number = connection == null || connection.getHandle() == null ?

                    null : connection.getHandle().getSchemeSpecificPart();

            if (!PhoneNumberUtils.isEmergencyNumber(number)) {

                mCallResponse = null;

            }

        }

  1. 创建成功,调用CallsManager中的onSuccessfulIncomingCall方法,将此消息传递到其他地方去

    public void onSuccessfulIncomingCall(Call incomingCall) {

        Log.d(this, "onSuccessfulIncomingCall");

        if (incomingCall.hasProperty(Connection.PROPERTY_EMERGENCY_CALLBACK_MODE)) {

            Log.i(this, "Skipping call filtering due to ECBM");

            onCallFilteringComplete(incomingCall, new CallFilteringResult(true, false, true, true));

            return;

        }

 

        //迭代器模式

        List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();

        filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));

        filters.add(new AsyncBlockCheckFilter(mContext, new BlockCheckerAdapter()));

        filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar,

                mDefaultDialerCache, new ParcelableCallUtils.Converter(), mLock));

 

        //IncomingCallFilter创建并执行 performFiltering

        new IncomingCallFilter(mContext, this, incomingCall, mLock,

                mTimeoutsAdapter, filters).performFiltering();

}

 

  1. 这里用到了迭代器模式,一个来电触发三个对象的处理, 最后创建一个IncomingCallFilter并调用performFiltering

    public void performFiltering() {

        Log.addEvent(mCall, LogUtils.Events.FILTERING_INITIATED);

        for (CallFilter filter : mFilters) {

            //遍历调用,依次执行异步查询方法

            filter.startFilterLookup(mCall, this);

        }

        // synchronized to prevent a race on mResult and to enter into Telecom.

        mHandler.postDelayed(new Runnable("ICF.pFTO", mTelecomLock) { // performFiltering time-out

            @Override

            public void loggedRun() {

                if (mIsPending) {

                    //超时处理的方法

                    Log.i(IncomingCallFilter.this, "Call filtering has timed out.");

                    Log.addEvent(mCall, LogUtils.Events.FILTERING_TIMED_OUT);

                    //回CallsManager中的监听事件

                    mListener.onCallFilteringComplete(mCall, mResult);

                    mIsPending = false;

                }

            }

        }.prepare(), mTimeoutsAdapter.getCallScreeningTimeoutMillis(mContext.getContentResolver()));

    }

 

  1. 如果没有超时则在异步查询结束后,会通过回调方法将CallFilterResult传回onCallFilteringComplete.,接下来回到CallsManager中进行onCallFilteringComplete处理,正常的话会将Call状态置为ring,并且添加Call,继续跟进addCall

    private void addCall(Call call) {

 

        call.addListener(this);

        mCalls.add(call);

 

        // Specifies the time telecom finished routing the call. This is used by the dialer for

        // analytics.

        Bundle extras = call.getIntentExtras();

        extras.putLong(TelecomManager.EXTRA_CALL_TELECOM_ROUTING_END_TIME_MILLIS,

                SystemClock.elapsedRealtime());

 

        updateCanAddCall();

        // onCallAdded for calls which immediately take the foreground (like the first call).

        for (CallsManagerListener listener : mListeners) {

            //通知监听Call添加的观察者,这里的mListeners在CallsManager初始化的时候就已经添加

            listener.onCallAdded(call);

        }

 

        /// M: single video call mode

        if (MtkUtil.isInSingleVideoCallMode(call)) {

            for (Call c : mCalls) {

                c.refreshConnectionCapabilities();

            }

        }

 

}

 

  1. 查看onCallAdded方法,在InCallController中进行了实现。在InCallController的onCallAdded方法中,会调用到IInCallService中的addCall方法,发送出MSG_ADD_CALL消息,然后调用Phone的internalAddCall方法。

    final void internalAddCall(ParcelableCall parcelableCall) {

        //创建Call

        Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,

                parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);

 

        mCallByTelecomCallId.put(parcelableCall.getId(), call);

        //添加到列表中

        mCalls.add(call);

        checkCallTree(parcelableCall);

        call.internalUpdate(parcelableCall, mCallByTelecomCallId);

        //调用phone的监听者的onCallAdded

        fireCallAdded(call);

     }

 

    private void fireCallAdded(Call call) {

        for (Listener listener : mListeners) {

            listener.onCallAdded(this, call);

        }

}

 

  1. 在 InCallService 中handleMessage处理MSG_SET_IN_CALL_ADAPTER消息的时候就注册了监听,这里继续跟进到InCallService中的实现去

Private  Phone.Listener mPhoneListener = new Phone.Listener()

        ...

        @Override

        public void onCallAdded(Phone phone, Call call) {

            //调用InCallService对象的onCallAdded方法

            InCallService.this.onCallAdded(call);

        }

  1. 这里调用的InCallService中的onCallAdded方法并未实现,而是在子类中进行了实现。

    public class InCallServiceImpl extends InCallService

 

  @Override

  public void onCallAdded(Call call) {

 

    if ((CallList.getInstance().getVideoUpgradeRequestCall() != null ||

            CallList.getInstance().getSendingVideoUpgradeRequestCall() != null ||

            /// M: When is cancel upgrade progress,we can't add another call in calllist. @{

            CallList.getInstance().getSendingCancelUpgradeRequestCall() != null)

            ///@}

            && !isEmergency(call)) {

       ...

    } else {

        InCallPresenter.getInstance().onCallAdded(call);

    }

  }

 

  1. 从这里开始,就完全属于我们dialer上层来进行处理了,InCallPresenter是InCallUI用于处理通话逻辑的核心类,继续跟进查看onCallAdded方法

public void onCallAdded(final android.telecom.Call call) {

    LatencyReport latencyReport = new LatencyReport(call);

    if (shouldAttemptBlocking(call)) {

      maybeBlockCall(call, latencyReport);

    } else {

      if (call.getDetails().hasProperty(CallCompat.Details.PROPERTY_IS_EXTERNAL_CALL)) {

        mExternalCallList.onCallAdded(call);

      } else {

        latencyReport.onCallBlockingDone();

        //CallList(Call的维护列表)调用onCallAdded

        mCallList.onCallAdded(mContext, call, latencyReport);

      }

    }

 

    // Since a call has been added we are no longer waiting for Telecom to send us a call.

    setBoundAndWaitingForOutgoingCall(false, null);

    call.registerCallback(mCallCallback);

  }

  1. 调用calllist中的onCallAdded方法

  public void onCallAdded(

      final Context context, final android.telecom.Call telecomCall, LatencyReport latencyReport) {

    Trace.beginSection("onCallAdded");

    ...

     if (call.getState() == DialerCall.State.INCOMING

            || call.getState() == DialerCall.State.CALL_WAITING) {

          //来电调用

          onIncoming(call);

        } else {

          dialerCallListener.onDialerCallUpdate();

    }

    ...

}

 

  1. 接着调用onIncoming方法,调用listener的onIncomingCall方法,实质上就是InCallPreSenter的onIncomingCall方法。在这里,会调用startOrFinishUi方法来启动InCallActivity。

  private void onIncoming(DialerCall call) {

    if (updateCallInMap(call)) {

      LogUtil.i("CallList.onIncoming", String.valueOf(call));

    }

 

    ///M:add for Dual ringing of DSDA. @{

    updateIncomingCallList(call);

    /// @}

    for (Listener listener : mListeners) {

      listener.onIncomingCall(call);

    }

  }

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值