《Android 4.4 Kitkat Phone工作流程浅析(二)__UI结构分析》
《Android 4.4 Kitkat Phone工作流程浅析(三)__MO(去电)流程分析》
《Android 4.4 Kitkat Phone工作流程浅析(四)__RILJ工作流程简析》
《Android 4.4 Kitkat Phone工作流程浅析(五)__MT(来电)流程分析》
01-01 18:11:47.039 1061 1061 D RILJ : RIL(1) :[0147]> DIAL ... ...省略 01-01 18:11:47.044 682 692 D use-Rlog/RLOG-AT: AT> ATD13800138000; 01-01 18:11:47.044 682 696 I use-Rlog/RLOG-RIL: RIL_URC2_PROXY wakeup 01-01 18:11:47.044 682 692 D use-Rlog/RLOG-AT: ATD13800138000; ... ...省略 01-01 18:11:47.047 682 707 D use-Rlog/RLOG-AT: OK 01-01 18:11:47.047 682 707 D use-Rlog/RLOG-AT: AT< OK 01-01 18:11:47.047 682 707 D use-Rlog/RLOG-AT: RIL_CMD_READER_2:OK 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: +CIEV: 5, 1 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: +ECPI: 1,130,0,0,0,0,"13800138000",129,"" 01-01 18:11:47.047 682 707 D use-Rlog/RLOG-AT: RIL_CMD_READER_2 Enter processLine 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: AT< +CIEV: 5, 1 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: RIL_URC_READER:+CIEV: 5, 1 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: RIL_URC_READER Enter processLine 01-01 18:11:47.047 682 707 I use-Rlog/RLOG-AT: AT read start 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-RIL: Nw URC:+CIEV: 5, 1 01-01 18:11:47.047 682 705 E use-Rlog/RLOG-RIL: Unhandled unsolicited result code: +CIEV: 5, 1 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: AT< +ECPI: 1,130,0,0,0,0,"13800138000",129,"" 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: RIL_URC_READER:+ECPI: 1,130,0,0,0,0,"13800138000",129,"" 01-01 18:11:47.047 682 692 D use-Rlog/RLOG-AT: response received on RIL_CMD_READER_2, tid:3086469296 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: RIL_URC_READER Enter processLine 01-01 18:11:47.047 682 705 D use-Rlog/RLOG-RIL: Nw URC:+ECPI: 1,130,0,0,0,0,"13800138000",129,"" ... ...省略 01-01 18:11:47.048 1061 1274 D RILJ : RIL(1) :[0147]< DIAL 01-01 18:11:47.048 1061 1274 V RILJ : RIL(1) :[UNSL RIL]< UNSOL_CALL_PROGRESS_INFO {1, 130, 0, 0, 0, 0, 13800138000, 129, }这里简单的分析一下重要的log信息:
RIL(1) :[0147]> DIAL这表示发起DIAL请求,紧接着执行ATD即AT拨号指令:
01-01 18:11:47.044 682 692 D use-Rlog/RLOG-AT: AT> ATD13800138000;我们在《 Android 4.4 Kitkat Phone工作流程浅析(四)__RILJ工作流程简析》文章中有讲过,可以根据serial号查看AT指令的配对,同时也提到了Log中的“>”和“<”所代表的含义,即“>”表示request,“<”表示response,上面两条log信息可以解释为RILJ发起了两次request请求。根据第一条AT指令的serial号"0147"我们可以在后面找到对应的response:
01-01 18:11:47.048 1061 1274 D RILJ : RIL(1) :[0147]< DIAL这表明整个拨号的request和response已经完成,在此期间Modem主动返回了以下信息:
01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: AT< +ECPI: 1,130,0,0,0,0,"13800138000",129,""该条AT指令+ECPI是MTK添加的,在标准AT指令中查询不到,具体含义如下:
01-01 18:11:47.047 682 705 D use-Rlog/RLOG-AT: AT< +ECPI: 1,130,0,0,0,0,"13800138000",129,""以上log重要信息如下:
01-01 18:11:47.048 1061 1274 V RILJ : RIL(1) :[UNSL RIL]< UNSOL_CALL_PROGRESS_INFO {1, 130, 0, 0, 0, 0, 13800138000, 129, }这是一条UnSolicited response消息,处理方法是RIL.java中的 processUnsolicited(),类型为:UNSOL_PROGRESS_INFO。
//... ... 省略部分代码 if (msgType == 132 || msgType == 6) dc.state = DriverCall.State.ACTIVE; else if (msgType == 131) dc.state = DriverCall.State.HOLDING; else if (msgType == 130 && callId != 254) //从log中可以看到msgType=130,call_id=1 dc.state = DriverCall.State.DIALING; else if (msgType == 2) dc.state = DriverCall.State.ALERTING; else if (msgType == 0) { for (j = 0; j < MAX_CONNECTIONS; j++) { if (mConnections[j] != null) { count ++; } } if (mState == PhoneConstants.State.IDLE || (count == 0 && mForegroundCall.getState() == GsmCall.State.DIALING)) { /* if the 2nd condition is true, that means we make a MO call, receiving +ECPI: 130, * then receiving +ECPI: 133 immediately due to MT call (+ECPI: 0) is receiving*/ if (count == 0 && mForegroundCall.getState() == GsmCall.State.DIALING) log("MO/MT conflict!!"); dc.state = DriverCall.State.INCOMING; } else dc.state = DriverCall.State.WAITING; }当状态改变之后便会通过GsmPhone的 notifyPreciseCallStateChanged()方法发起响应,如下:
if ((hasNonHangupStateChanged || newRinging != null) && crssAction != CrssAction.SWAP && !(hasPendingReplaceRequest && msgType == 133)) { log("notify precise call state changed"); mPhone.notifyPreciseCallStateChanged(); }之后会通过观察者模式方式调用到CallManager的 handleMessage()方法中,case为 EVENT_PRECISE_CALL_STATE_CHANGED,代码如下:
case EVENT_PRECISE_CALL_STATE_CHANGED: //... ...省略部分代码 index = (msg.what - EVENT_PRECISE_CALL_STATE_CHANGED) / NOTIFICATION_ID_OFFSET; mPreciseCallStateRegistrantsGemini[index].notifyRegistrants((AsyncResult) msg.obj); mPreciseCallStateRegistrants.notifyRegistrants((AsyncResult) msg.obj); handle3GSwitchLock();这里会有MTK的Gemini处理,即双卡处理,通过同样的观察者模式将状态改变信息通过notifyRegistrants()方法发送到TeleService中。整个流程如下图:
if (!ignoreUpdate()) { if (updatedCalls.size() > 0) { for (int i = 0; i < mListeners.size(); ++i) { mListeners.get(i).onUpdate(updatedCalls); } } }这里会触发BluetoothManager、 CallHandlerServiceProxy、DTMFTonePlayer三个类中的 onUpdate()方法回调,这里我们查看CallHandlerServiceProxy中的onUpdate()方法即可。对于上面的代码再多说几句,原生Android 4.4中,CallModeler的onPhoneStateChanged方法并没有 ignoreUpdate()方法,这是MTK加入的主要目的是用于判断是否忽略本次界面更新,用于自动拒接和快速挂断正在响铃的电话两种场景。代码如下:
/* * The function to judge whether should skip update calls to InCallUI, * for auto reject case, or quick hang up ringing case. * When 1A + 1R, if ringing call is hanged up while query(ringtone), * CallNotifier will not notify InCallUI the onIncoming(), then we should ignore update calls to InCallUI; * or will show callcard with ringing call information but no AnswerFragment shown. */ private boolean ignoreUpdate() { boolean shouldIgnore = false; final boolean hasActiveFgCall = mCallManager.hasActiveFgCall(); final boolean hasActiveBgCall = mCallManager.hasActiveBgCall(); shouldIgnore = (hasActiveFgCall || hasActiveBgCall) && PhoneGlobals.getInstance().notifier.hasPendingCallerInfoQuery(); Log.i(TAG, "ignoreUpdate()... shouldIgnore: " + shouldIgnore); return shouldIgnore; }通过代码可以很清楚的知道,当CallerInfo没有查询完毕时 hasPendingCallerInfoQuery()返回true,则忽略本次界面更新。
@Override public void onUpdate(List<Call> calls) { synchronized (mServiceAndQueueLock) { if (mCallHandlerServiceGuarded == null) { //设置更新类型为METHOD_UPDATE enqueueUpdate(calls); //与CallHandlerService建立连接 setupServiceConnection(); return; } } //执行更新 processUpdate(calls); }更新类型包括:
@Override public void onUpdate(List<Call> calls) { try { Log.i(TAG, "onUpdate: " + calls); //注意:这里的类型是ON_UPDATE_MULTI_CALL mMainHandler.sendMessage(mMainHandler.obtainMessage(ON_UPDATE_MULTI_CALL, calls)); } catch (Exception e) { Log.e(TAG, "Error processing onUpdate() call.", e); } }这里很奇怪的一点是,类型居然是ON_UPDATE_MULTI_CALL,而代码中也有ON_UPDATE_CALL类型,这是google原生的,MTK没有改过,不知道是何用意。
/** * Sends a generic notification to all listeners that something has changed. * It is up to the listeners to call back to determine what changed. */ private void notifyListenersOfChange() { for (Listener listener : mListeners) { listener.onCallListChange(this); } }这里会执行listener的回调,分别在 AnswerPresenter和 InCallPresenter中。CallList只是负责将状态改变通知到listener,是否处理则由listener们自己决定。AnswerPresenter只有在incoming的时候才会处理,因此这里应该查看 InCallPresenter的 onCallListChange()方法:
@Override public void onCallListChange(CallList callList) { if (callList == null) { return; } InCallState newState = getPotentialStateFromCallList(callList); //这里去判断是否显示/关闭InCallActivity newState = startOrFinishUi(newState); //... ...省略部分代码 }这里会跳转到 startOrFinishUi()中进行判断,因为是第一次启动 InCallActivity界面,最后会通过 startActivity()的方式启动InCallActivity,到此整个InCallActivity的界面显示流程就结束了。后续Modem侧状态改变则根据该流程传递到InCallPresenter,由InCallPresenter来响应不同的状态所需要启动/关闭的界面。整个流程如下图:
public void updateCalls() { final List<Call> updatedCalls = Lists.newArrayList(); doUpdate(true, updatedCalls); if (!ignoreUpdate()) { if (updatedCalls.size() > 0) { for (int i = 0; i < mListeners.size(); ++i) { mListeners.get(i).onUpdate(updatedCalls); } } } }注意:该方法是MTK自己加入的,原生AOSP并没有,如果想使用也可以仿照这种方式添加。