android去电流程,android 去电流程

开始看代码。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
安卓设备的充流程一般包括以下步骤: 1. 插入充器并连接源 当用户将充器插入安卓设备并连接源时,系统会检测到源连接事件,然后启动相应的服务和线程来处理充流程。 2. 开始充流程 系统会根据充器的类型和池的状态,选择合适的充模式,并开始充流程。在此过程中,系统会监测池的状态,包括量、温度、压等,并动态调整充流和压等参数,以保证充过程的安全和稳定。 3. 监测充状态 系统会持续监测充状态,包括量、充流、充压等,并将这些信息通知给用户和应用程序。用户可以通过系统设置界面或者充图标来查看量和充状态,应用程序可以通过BatteryManager类获取池状态信息。 4. 充完成 当池充满时,系统会停止充流程,并通知用户和应用程序。通常情况下,系统会将充流降低到一个很小的值,以防止池过充或者损坏。 5. 断开源 当用户拔出充器或者源故障时,系统会检测到源断开事件,并停止充流程。此时,系统会根据池的状态和充模式,选择合适的池管理策略,例如保持当前量、降低量等级、关闭不必要的应用程序等。 总的来说,安卓设备的充流程是一个复杂的系统过程,需要多个服务和线程协同工作,以保证充过程的安全、稳定和高效。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值