Android 挂断电话流程

转载 2012年03月21日 23:43:27

今天试图解决android挂断电话没有响应的一个bug,跟踪了一下Android 挂断电话流程,在此做个记录


有电话打入是RIL会通知CallNotifier, CallNotifier会调用InCallScreen,这些不再我们今天讨论的范围内,简单提一下。

CallNotifier会调用InCallScreen 代码

  1. PhoneUtils.showIncomingCallUi(mPhone); 


然后InCallScreen会显示InCallTouchUI , InCallTouchUI 就是可以拖动接听和挂断的那个界面 ,这个页面持有一个SlidingTab控件,这个就是可以左右拖动的控件了。

InCallTouchUI实现了 SlidingTab.OnTriggerListener, 在该监听者的OnTrigge方法里面处理接听和挂断的动作,代码如下

  1. // 
  2. // SlidingTab.OnTriggerListener implementation 
  3. // 
  4.  
  5. /**
  6. * Handles "Answer" and "Reject" actions for an incoming call.
  7. * We get this callback from the SlidingTab
  8. * when the user triggers an action.
  9. *
  10. * To answer or reject the incoming call, we call
  11. * InCallScreen.handleOnscreenButtonClick() and pass one of the
  12. * special "virtual button" IDs:
  13. *   - R.id.answerButton to answer the call
  14. * or
  15. *   - R.id.rejectButton to reject the call.
  16. */ 
  17. public void onTrigger(View v, int whichHandle) { 
  18.     log("onDialTrigger(whichHandle = " + whichHandle + ")..."); 
  19.  
  20.     switch (whichHandle) { 
  21.         case SlidingTab.OnTriggerListener.LEFT_HANDLE: 
  22.             if (DBG) log("LEFT_HANDLE: answer!"); 
  23.  
  24.             hideIncomingCallWidget(); 
  25.  
  26.             // ...and also prevent it from reappearing right away. 
  27.             // (This covers up a slow response from the radio; see updateState().) 
  28.             mLastIncomingCallActionTime = SystemClock.uptimeMillis(); 
  29.  
  30.             // Do the appropriate action. 
  31.             if (mInCallScreen != null) { 
  32.                 // Send this to the InCallScreen as a virtual "button click" event: 
  33.                 mInCallScreen.handleOnscreenButtonClick(R.id.answerButton); 
  34.             } else
  35.                 Log.e(LOG_TAG, "answer trigger: mInCallScreen is null"); 
  36.             } 
  37.             break
  38.  
  39.         case SlidingTab.OnTriggerListener.RIGHT_HANDLE: 
  40.             if (DBG) log("RIGHT_HANDLE: reject!"); 
  41.  
  42.             hideIncomingCallWidget(); 
  43.  
  44.             // ...and also prevent it from reappearing right away. 
  45.             // (This covers up a slow response from the radio; see updateState().) 
  46.             mLastIncomingCallActionTime = SystemClock.uptimeMillis(); 
  47.  
  48.             // Do the appropriate action. 
  49.             if (mInCallScreen != null) { 
  50.                 // Send this to the InCallScreen as a virtual "button click" event: 
  51.                 mInCallScreen.handleOnscreenButtonClick(R.id.rejectButton);   //看到了吧,这个就是挂断电话的代码了,继续往下看 
  52.             } else
  53.                 Log.e(LOG_TAG, "reject trigger: mInCallScreen is null"); 
  54.             } 
  55.             break
  56.  
  57.         default
  58.             Log.e(LOG_TAG, "onDialTrigger: unexpected whichHandle value: " + whichHandle); 
  59.             break
  60.     } 
  61.  
  62.     // Regardless of what action the user did, be sure to clear out 
  63.     // the hint text we were displaying while the user was dragging. 
  64.     mInCallScreen.updateSlidingTabHint(0, 0); 


InCallScreen的 handleOnscreenButtonClick方法

  1. /**
  2. * Handles button clicks from the InCallTouchUi widget.
  3. */ 
  4. /* package */ void handleOnscreenButtonClick(int id) { 
  5.     if (DBG) log("handleOnscreenButtonClick(id " + id + ")..."); 
  6.  
  7.     switch (id) { 
  8.         // TODO: since every button here corresponds to a menu item that we 
  9.         // already handle in onClick(), maybe merge the guts of these two 
  10.         // methods into a separate helper that takes an ID (of either a menu 
  11.         // item *or* touch button) and does the appropriate user action. 
  12.  
  13.         // Actions while an incoming call is ringing: 
  14.         case R.id.answerButton: 
  15.             internalAnswerCall(); 
  16.             break
  17.         case R.id.rejectButton: 
  18.             internalHangupRingingCall();             //挂断电话的方法 
  19.             break
  20.  
  21.         // The other regular (single-tap) buttons used while in-call: 
  22.         case R.id.holdButton: 
  23.             onHoldClick(); 
  24.             break
  25.         case R.id.swapButton: 
  26.             internalSwapCalls(); 
  27.             break
  28.         case R.id.endButton: 
  29.             internalHangup(); 
  30.             break
  31.         case R.id.dialpadButton: 
  32.             onShowHideDialpad(); 
  33.             break
  34.         case R.id.bluetoothButton: 
  35.             onBluetoothClick(); 
  36.             break
  37.         case R.id.muteButton: 
  38.             onMuteClick(); 
  39.             break
  40.         case R.id.speakerButton: 
  41.             onSpeakerClick(); 
  42.             break
  43.         case R.id.addButton: 
  44.             PhoneUtils.startNewCall(mCM);  // Fires off an ACTION_DIAL intent 
  45.             break
  46.         case R.id.mergeButton: 
  47.         case R.id.cdmaMergeButton: 
  48.             PhoneUtils.mergeCalls(mCM); 
  49.             break
  50.         case R.id.manageConferencePhotoButton: 
  51.             // Show the Manage Conference panel. 
  52.             setInCallScreenMode(InCallScreenMode.MANAGE_CONFERENCE); 
  53.             break
  54.  
  55.         default
  56.             Log.w(LOG_TAG, "handleOnscreenButtonClick: unexpected ID " + id); 
  57.             break
  58.     } 
  59.  
  60.     // Just in case the user clicked a "stateful" menu item (i.e. one 
  61.     // of the toggle buttons), we force the in-call buttons to update, 
  62.     // to make sure the user sees the *new* current state. 
  63.     // 
  64.     // (But note that some toggle buttons may *not* immediately change 
  65.     // the state of the Phone, in which case the updateInCallTouchUi() 
  66.     // call here won't have any visible effect.  Instead, those 
  67.     // buttons will get updated by the updateScreen() call that gets 
  68.     // triggered when the onPhoneStateChanged() event comes in.) 
  69.     // 
  70.     // TODO: updateInCallTouchUi() is overkill here; it would be 
  71.     // more efficient to update *only* the affected button(s). 
  72.     // Consider adding API for that.  (This is lo-pri since 
  73.     // updateInCallTouchUi() is pretty cheap already...) 
  74.     updateInCallTouchUi(); 


然后调用 PhoneUtils.hangupRingingCall(mCM.getFirstActiveRingingCall()); 方法

  1. /**
  2. * Hang up the ringing call (aka "Don't answer").
  3. */ 
  4. /* package */ void internalHangupRingingCall() { 
  5.     if (DBG) log("internalHangupRingingCall()..."); 
  6.     if (VDBG) PhoneUtils.dumpCallManager(); 
  7.     // In the rare case when multiple calls are ringing, the UI policy 
  8.     // it to always act on the first ringing call.v 
  9.     PhoneUtils.hangupRingingCall(mCM.getFirstActiveRingingCall()); 

  1. static boolean hangupRingingCall(Call ringing) { 
  2.     if (DBG) log("hangup ringing call"); 
  3.     int phoneType = ringing.getPhone().getPhoneType(); 
  4.  
  5.     if (phoneType == Phone.PHONE_TYPE_CDMA) { 
  6.         // CDMA: Ringing call and Call waiting hangup is handled differently. 
  7.         // For Call waiting we DO NOT call the conventional hangup(call) function 
  8.         // as in CDMA we just want to hungup the Call waiting connection. 
  9.         Call.State state = ringing.getState(); 
  10.         if (state == Call.State.INCOMING) { 
  11.             if (DBG) log("hangup ringing call"); 
  12.             return hangup(ringing); 
  13.         } else if (state == Call.State.WAITING) { 
  14.             if (DBG) log("hangup Call waiting call"); 
  15.             final CallNotifier notifier = PhoneApp.getInstance().notifier; 
  16.             notifier.sendCdmaCallWaitingReject(); 
  17.             return true
  18.         } else
  19.             // This should never happen cause hangupRingingCall should always be called 
  20.             // if the call.isRinging() returns TRUE, which basically means that the call 
  21.             // should either be in INCOMING or WAITING state 
  22.             if (DBG) log("No Ringing call to hangup"); 
  23.             return false
  24.         } 
  25.     } else if ((phoneType == Phone.PHONE_TYPE_GSM) 
  26.             || (phoneType == Phone.PHONE_TYPE_SIP)) { 
  27.         // GSM:  Ringing Call and Call waiting, both are hungup by calling 
  28.         // hangup(call) function. 
  29.         if (DBG) log("hangup ringing call"); 
  30.         return hangup(ringing);                
  31.     } else
  32.         throw new IllegalStateException("Unexpected phone type: " + phoneType); 
  33.     } 


  1. /**
  2. * Trivial wrapper around Call.hangup(), except that we return a
  3. * boolean success code rather than throwing CallStateException on
  4. * failure.
  5. *
  6. * @return true if the call was successfully hung up, or false
  7. *         if the call wasn't actually active.
  8. */ 
  9. static boolean hangup(Call call) { 
  10.     try
  11.         call.hangup(); 
  12.         return true
  13.     } catch (CallStateException ex) { 
  14.         Log.e(LOG_TAG, "Call hangup: caught " + ex, ex); 
  15.     } 
  16.  
  17.     return false

然后进入 GsmCall

  1. public void 
  2. hangup() throws CallStateException { 
  3.     owner.hangup(this); 

然后进入 frameworks/base/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java

可以看到很多不同情况下挂断电话的处理,我们只看第一种情况 hangupWaitingOrBackground


  1. //***** Called from GsmCall 
  2.  
  3. /* package */ void 
  4. hangup (GsmCall call) throws CallStateException { 
  5.     if (call.getConnections().size() == 0) { 
  6.         throw new CallStateException("no connections in call"); 
  7.     } 
  8.  
  9.     if (call == ringingCall) { 
  10.         if (Phone.DEBUG_PHONE) log("(ringing) hangup waiting or background"); 
  11.         cm.hangupWaitingOrBackground(obtainCompleteMessage()); 
  12.     } else if (call == foregroundCall) { 
  13.         if (call.isDialingOrAlerting()) { 
  14.             if (Phone.DEBUG_PHONE) { 
  15.                 log("(foregnd) hangup dialing or alerting..."); 
  16.             } 
  17.             hangup((GsmConnection)(call.getConnections().get(0))); 
  18.         } else
  19.             hangupForegroundResumeBackground(); 
  20.         } 
  21.     } else if (call == backgroundCall) { 
  22.         if (ringingCall.isRinging()) { 
  23.             if (Phone.DEBUG_PHONE) { 
  24.                 log("hangup all conns in background call"); 
  25.             } 
  26.             hangupAllConnections(call); 
  27.         } else
  28.             hangupWaitingOrBackground(); 
  29.         } 
  30.     } else
  31.         throw new RuntimeException ("GsmCall " + call + 
  32.                 "does not belong to GsmCallTracker " + this); 
  33.     } 
  34.  
  35.     call.onHangupLocal(); 
  36.     phone.notifyPreciseCallStateChanged(); 


下面进入RIL java, 向rild 发请求了

  1. public void 
  2. hangupWaitingOrBackground (Message result) { 
  3.     RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, 
  4.                                     result); 
  5.  
  6.     if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); 
  7.  
  8.     send(rr); 

再往下就是  rild , 厂商refence ril工作了 ,其实就是发AT命令,这部分每个厂商可能有自己的实现,就不细说了 。


总之,android的挂断电话流程还是挺复杂的,中间要处理很多不同的情景。

 

原文地址:http://blog.csdn.net/offbye/article/details/6660693

挂断电话流程分析

4,挂断电话流程分析 4.1 InCallUI 点击通话界面的挂断按钮,就会调用CallCardFragment的如下代码, mFloatingActionButton.setOnClickLi...
  • u012439416
  • u012439416
  • 2017年08月13日 20:17
  • 314

Android 5.1 Phone 挂断电话流程分析

本文主要分析Android挂断电话的流程,研究的代码是Android 5.1的,以CDMA为例,GSM同理。 挂断电话主要分两种情况:本地主动挂断电话和远程断开通话。 这里说的本地主动挂断电话,是...
  • linyongan
  • linyongan
  • 2015年08月29日 20:36
  • 4524

Android 7.0 挂断电话流程分析

Android 7.0 挂断电话流程分析
  • qq_27061049
  • qq_27061049
  • 2017年12月13日 19:27
  • 238

Android 挂断电话流程

今天试图解决android挂断电话没有响应的一个bug,跟踪了一下Android 挂断电话流程,在此做个记录  有电话打入是RIL会通知CallNotifier, CallNotifier会...
  • offbye
  • offbye
  • 2011年08月04日 18:27
  • 4005

android 接听和挂断实现方式

转载▼ 标签:  android   接听   挂断   it 分类: android应用技巧 参考:and...
  • hanghangaidoudou
  • hanghangaidoudou
  • 2016年08月23日 13:56
  • 1527

Android挂断电话代码

监听来电这里就不贴代码了,这是监听到来电后挂断电话 /** * 通过反射的方式挂断电话 */ public void endcall() { try { //获取到S...
  • rankun1
  • rankun1
  • 2016年06月25日 18:39
  • 1481

Android通过程序接听或者挂断电话

这篇文章教你如何帮助用户自动接听或者挂断来电。当然并不是我原创的代码,我只不过是把stackoverflow上的一些代码整合了一下,做个代码的二传手。...
  • l465659833
  • l465659833
  • 2016年09月14日 21:41
  • 1539

Android之——自动挂断电话的实现

通过《Android之——AIDL小结》与《Android之——AIDL深入》两篇博文,相信大家已经对Android AIDL有了一定的了解,下面,我们就利用Android的AIDL实现自动挂断电话的...
  • l1028386804
  • l1028386804
  • 2015年07月26日 22:03
  • 2962

Android挂断电话以及Java Class Loader

Android中,要自己实现一个挂断电话方法时,很久之前可以endCall().不过现在已经不行了,要应用反射机制,获取到 "android.os.ServiceManager" 的Class,然后...
  • RuingMan
  • RuingMan
  • 2016年05月05日 17:08
  • 1894

Android黑名单挂断电话的操作

实现电话状态的监听获取电话管理器(TelephonyManager) 用管理器监听电话的状态 添加权限 TelephonyManager tm=(TelephonyManager) getSystem...
  • android_wwyy
  • android_wwyy
  • 2016年10月31日 00:27
  • 384
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android 挂断电话流程
举报原因:
原因补充:

(最多只允许输入30个字)