开始看代码。

TwelveKeyDialer.java,既然要打电话,总要先输入号码才拨出,这个类就是拨号盘的界面,只是这个phone用到的类却是放在com.android.contacts包下,应该是出于代码结构的考虑吧。毕竟联系人、拨号盘、通话记录和收藏都是在一个Tab标签里的。这个界面没什么好说的,0-9数字键,P和W(也可能是*和#),P表示直接拨打带有分机号的号码(如2345-0000P1234)时会直接拨分机号,无需要再输入分机号码,而W拨号(如23450000W1234)则会有对话框提示你确认是否拨分机号,就这点区别。

按完电话号码点拨号键,接下来就开始去电流程了,离开TwelveKeyDialer.java前的代码,

voiddialButtonPressed(String ipPrefix) {

Log.d(TAG, "dialButtonPressed");

//注意这个action,只有从拨号盘拨出的才是Intent.ACTION_CALL_PRIVILEGED

//外部调用的是Intent.ACTION_CALL

Intent intent = newIntent(Intent.ACTION_CALL_PRIVILEGED);

//省略次要代码……

intent.setData(Uri.fromParts("tel", number,null));//拼一个电话的Uri,关键代码

StickyTabs.saveTab(this, getIntent());//与拨号无关

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(intent);

mDigits.getText().clear(); //清除输入

}

发出来的Intent谁来接收呢,是OutgoingCallBroadcaster.java类(其实拨打电话的方式很多,不一定是拨号盘拨号:可以从联系人拨号,可以是历史记录拨号等,无论是何种拨号,最后一定走向OutgoingCallBroadcaster.java),这是一个中间类,实际我们是看不到它的,这个类先判断号码是否为紧急号码,如果是紧急号码,启动InCallScree.java,并发送广播;如果不是,发送广播“Intent.ACTION_NEW_OUTGOING_CALL”由它的内部类OutgoingCallReceiver接收,从onReceiver()再到doReceiver(),会把action里的字符串统一替换成Intent.ACTION_CALL,启动InCallScreen.java,在这个类也可以做一些其它的业务逻辑判断(比如固定拨号,视频电话等),IncallScreen.java是电话应用的主界面,这个界面负责的东西比较多,所需要做的判断也不少,值得一提的是它重写finish()方法,当调用这个方法时它又把自己放回栈中,这样可提高下次启动的响应速度。

如果是第一次进入IncallScreen,会执行onCreate()

protectedvoidonCreate(Bundle icicle) {

Profiler.callScreenOnCreate();//获得通话界面被创建的时间。

…..省略代码...

setPhone(app.phone);  // Sets mPhone

mCM =  PhoneApp.getInstance().mCM;

mBluetoothHandsfree = app.getBluetoothHandsfree();//设置蓝牙

if(mBluetoothHandsfree !=null) {

mBluetoothHeadset = newBluetoothHeadset(this,null);

}

initInCallScreen();   //加载界面元素

…..省略代码...

registerForPhoneStates();//注册各种状态

if(icicle ==null) {

mInCallInitialStatus = internalResolveIntent(getIntent());  //这个是关键代码

} else{

mInCallInitialStatus = InCallInitStatus.SUCCESS;

}

mUseTouchLockOverlay = !app.proximitySensorModeEnabled();

Profiler.callScreenCreated();//记录通话界面创建完成后的时间

}

如果是第二次进入会执行onNewIntent()

protectedvoidonNewIntent(Intent intent) {

mInCallInitialStatus = internalResolveIntent(intent);//这个是关键代码

……去掉log代码

}

两个方法都会走到internalResolveIntent(intent),这里我们关心电话拨出的动作是怎么跑下去的,所以InCallScreen里的onResume()方法就不细看了,那里面有关于锁屏和蓝牙连接等逻辑判断。回来继续看internalResolveIntent()的代码。

InCallInitStatus internalResolveIntent(Intent intent) {

……省略很多代码…   传过来的action是Intent.ACTION_CALL,直接看重点

} elseif(action.equals(Intent.ACTION_CALL)

|| action.equals(Intent.ACTION_CALL_EMERGENCY)) {

app.setRestoreMuteOnInCallResume(false);

if(PhoneUtils.hasPhoneProviderExtras(intent)) {

InCallInitStatus status = placeCall(intent);//这是我们要找的

if(status == InCallInitStatus.SUCCESS) {

app.setBeginningCall(true);

}

returnstatus;

} }

(当我看到这篇文章的时候,也按照作者的思路看代码,发现代码不一样,本文的代码是gingerbread的代码,我看的是四核代码,版本应该是4.2的。四核的代码里internalResolveIntent()并没有执行InCallInitStatus status = placeCall(intent);//这是我们要找的    这句,看了注释,placeCall()方法在callcontroller.java里面,后续流程大致相同)

进入placeCall()方法后,会做一些关于是否紧急号码和OTA(Over-the-Air Technology空中下载技术,是通过移动通信(GSM或CDMA)的空中接口对SIM卡数据及应用进行远程管理的技术)的判断,不过我们更关心下面的代码。

if(null!= mProviderGatewayUri && !(isEmergencyNumber || isEmergencyIntent) &&

PhoneUtils.isRoutableViaGateway(number)) {

callStatus = PhoneUtils.placeCallVia(this, phone, number,

contactUri, mProviderGatewayUri);//多了个网关参数

} else{

callStatus = PhoneUtils.placeCall(phone, number, contactUri);//多数调用这里

}

后面switch分支会根据callStatus的值完成相应的功能或提示。到这里到代码就走到PhoneUtils.java里了,placeCall()是一个静态方法调用。里面最重要的代码是

Connection cn = PhoneApp.getInstance().mCM.dial(phone, number);

//也有可能看到下面的代码

Connection cn = phone.dial(number)//如果是这种,会先走到GsmCallTracker.java

顺便提下在这个方法里还会有setAudioMode(),关于音频通道和模式的设置就在这里,这里面的故事也不少,不过要先放放了。下面的代码已经在Framework层了,不管之前的代码在哪里dial,最后都会来到RIL.java。

publicvoiddial(String address,intclirMode, UUSInfo uusInfo, Message result) {

RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);

rr.mp.writeString(address);

rr.mp.writeInt(clirMode);

rr.mp.writeInt(0);// UUS information is absent

if(uusInfo ==null) {

rr.mp.writeInt(0);// UUS information is absent

} else{

rr.mp.writeInt(1);// UUS information is present

rr.mp.writeInt(uusInfo.getType());

rr.mp.writeInt(uusInfo.getDcs());

rr.mp.writeByteArray(uusInfo.getUserData());

}

send(rr);

}

跟着RIL_REQUEST_DIAL这个TAG标志向下走来到Reference-ril.c找到相应的case分支,

caseRIL_REQUEST_DIAL:

requestDial(data, datalen, t);

staticvoidrequestDial(void*data, size_t datalen, RIL_Token t){

p_dial = (RIL_Dial *)data;

switch(p_dial->clir) {

case1: clir ="I";break;/*invocation*/

case2: clir ="i";break;/*suppression*/

default:

case0: clir ="";break;/*subscription default*/

}

asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);

ret = at_send_command(cmd, NULL);

free(cmd);

RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);

}

到这里我们的电话基本上算是拨出去了,至于是否成功还要看返回结果,通常形式上的流程是这样的(下面只是很多可能中的一种,也是比较常见的一种),

===>>[SendAT] ATD15812345678//拨号,看到atd是不是会想到贝尔实验室和AT&T呢?

<<====[RecvAT] OK

<<====[RecvAT] +CLCC: 1,0,2,0,0,"15812345678",129,//主动上报clcc

===>>[SendAT] AT+CMUT=0, time=//设置话简静音关

<<====[RecvAT] OK, time=

===>>[SendAT] AT+CLCC           //主动查询,

<<====[RecvAT] +CLCC: 1,0,2,0,0,"15812345678",129,//以这一次的clcc为准

这段代码描述这样一个事实,不管模块报上来CLCC数据如何,我们都会重新查询后再上报给应用层,上层收到消息后更新界面和维护Connection里每一路电话的状态。到这一步,去电的流程也算是基本走完了,后面还有些界面状态刷新的代码省略了,对于AT命令那一部分,具体实现要看芯片厂商,表现上不完全一致。

转自 http://blog.csdn.net/baimy1985/article/details/7853268

android去电流程,android 去电流程相关推荐

  1. Android监听来去电通话录音真正可实行方案,可获取电话接通时状态

    最近 经过一段时间研究了Android来去电并且录音的研究,特此作为记录 首先监听来去电并且可以录音得有以下权限: //录音权限 <uses-permission android:name=&q ...

  2. Android 10.0 PackageManagerService(一)工作原理及启动流程-[Android取经之路]

    摘要:PackageManagerService是Android系统核心服务之一,在Android中的非常重要,主要负责APK.jar包等的管理. 阅读本文大约需要花费50分钟. 文章的内容主要还是从 ...

  3. Android10.0应用进程创建过程以及Zygote的fork流程-[Android取经之路]

    摘要:点击手机桌面图标,例如微信,它是如何启动的呢,让我们从系统源码级来一起分析. 阅读本文大约需要花费1小时. 文章的内容主要还是从源码进行分析,虽然又臭又长,但是如果想要学习Android系统源码 ...

  4. Android10.0系统启动之Launcher(桌面)启动流程-[Android取经之路]

    摘要:上一节我们讲完了Android10.0的ActivityManagerService的启动流程,在AMS的最后启动了Launcher进程,今天我们就来看看Launcher的真正启动流程. 阅读本 ...

  5. Android 10.0 系统服务之ActivityMnagerService-AMS启动流程-[Android取经之路]

    摘要:上一节我们讲完了SystemServer的启动过程,这一节接着上一节的步骤,来讲解ActivityManagerService的启动过程. ActivityManagerService简称AMS ...

  6. 【Android 逆向】Android 进程简介 ( Android 应用启动流程 )

    文章目录 前言 一.Android 进程 二.Android 应用启动流程 前言 参考 [Android 逆向]Android 系统文件分析 ( /proc/pid 进程号对应进程目录 | oom_a ...

  7. 【字节码插桩】Android 打包流程 | Android 中的字节码操作方式 | AOP 面向切面编程 | APT 编译时技术

    文章目录 一.Android 中的 Java 源码打包流程 1.Java 源码打包流程 2.字符串常量池 二.Android 中的字节码操作方式 一.Android 中的 Java 源码打包流程 Ja ...

  8. 【Android 启动过程】Android 应用启动流程 | Activity 启动流程

    文章目录 一.Android 系统启动流程 二.Activity 启动流程 一.Android 系统启动流程 打开 Android 手机电源键后 , 先运行 BootLoader , 然后使用 Boo ...

  9. 【Android 安装包优化】APK 打包流程 ( 文件结构 | 打包流程 | 安装流程 | 安卓虚拟机 )

    文章目录 一.APK 文件结构 二.APK 打包流程 三.APK 安装流程 四.安卓虚拟机 一.APK 文件结构 Android 应用的安装包时 以 " .apk " 为后缀的 A ...

  10. 【Android 应用开发】Android 工程修改包名流程 ( 修改 applicationId | 修改 package | 修改 R 资源引用 | 修改 BuildConfig 引用 )

    文章目录 一. Android 工程修改包名流程 二. 修改 applicationId 三. 修改 package 包名 四. AndroidManifest.xml 清单文件组件 五. 修改 R ...

最新文章

  1. SQL*Plus 系统变量之15 - DESC[RIBE]
  2. MathType公式行距设置的方法
  3. htmlparser解析网页内容代码
  4. Linux驱动修炼之道-内存映射
  5. NN如何在表格数据中战胜GBDT类模型
  6. [Protobuf] Mac系统下安装配置及简单使用
  7. 我的20132014
  8. 1535C. Unstable String
  9. first network error, wait for 15 seconds
  10. java8 streamlist转化
  11. Java MD5加密工具类
  12. 判断对错html,js制作单选题,能判断对错
  13. 蔡勒(Zeller)公式及其推导:快速将任意日期转换为星期数
  14. 股票预测和股票分析就用FineBI!
  15. Python将npy文件转换为mat文件
  16. png怎么转换成jpg格式?如何转换照片格式为jpg?
  17. git获取ssh密钥
  18. 琴生不等式(Jensen Inequality)
  19. 必须了解的待人处事小技巧
  20. c语言数组子集,C语言实现数组所有子集

热门文章

  1. Oracle FAST_START_MTTR_TARGET参数的理解
  2. Flink CEP结合案例详解
  3. 行业寒冬:我们究竟还要学习哪些Android知识?赶紧收藏!
  4. android 应用程序入口,小米系统 应用入口之争的另一种思路
  5. 两个.c文件访问同一个全局变量的用法
  6. echarts format tooltip
  7. selenium的弹出框处理
  8. GoodSync文件同步工具,亲测可用。
  9. 山东大学类脑实验 五 HMAX 模型实现
  10. lol显示客户端无法与服务器通讯,lol客户端无法与登录队列怎么办 lol客户端无法与登录队列进行通讯解决办法...