Android Dial处理过程
第一部分:从java端发送at命令的处理流程。
拨出电话流程:
1、Contacts的AndroidManifest.xml 中android:process="android.process.acore" 说明此应用程序运行在acore进程中。
DialtactsActivity的intent-filter的action属性设置为main,catelog属性设置为launcher,所以此 activity能出现在主菜单中,并且是点击此应用程序的第一个界面。dialtactsactivity包含四个tab,分别由 TwelveKeyDialer、RecentCallsListActivity,两个activity-alias DialtactsContactsEntryActivity和DialtactsFavoritesEntryActivity分别表示联系人和收藏 tab,但是正真的联系人列表和收藏是由ContactsListActivity负责。
2、进入TwelveKeyDialer 中OnClick方法,按住的按钮id为:R.id.dialButton,执行placecall()方法:
Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,Uri.fromParts("tel", number, null));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
3、intert.ACTION_CALL_PRIVILEGED实际字符串为 android.intent.action.CALL_PRIVILEGED,通过查找知道了packegs/phone下面的 AndroidManifest.xml中PrivilegedOutgoingCallBroadcaster activity-alias设置了intent-filter,所以需要找到其targetactivity为 OutgoingCallBroadcaster。所以进入OutgoingCallBroadcaster的onCreate()中:
String action = intent.getAction();
String number = PhoneNumberUtils.getNumberFromIntent(intent, this);
if (number != null) {
number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
number = PhoneNumberUtils.stripSeparators(number);
}
final boolean emergencyNumber =
(number != null) && PhoneNumberUtils.isEmergencyNumber(number);
获取过来的Action以及Number,并对Action以及Number类型进行判断。
//如果为callNow = true;则启动InCall界面:
intent.setClass(this, InCallScreen.class);
startActivity(intent);
并发送广播给OutgoingCallReceiver:
Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
if (number != null) broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);
broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, intent.getData().toString() );
sendOrderedBroadcast(broadcastIntent, PERMISSION,
new OutgoingCallReceiver(), null, Activity.RESULT_OK, number, null);
4、Intent.ACTION_NEW_OUTGOING_CALL实际字符串 android.intent.action.NEW_OUTGOING_CALL,通过查找知道了packegs/phone下面的 androidmanifest.xml中OutgoingCallReceiver Receiver接收此intent消息。找到OutgoingCallBroadcaster类中的内部类OutgoingCallReceiver, 执行onReceive()函数:
执行doReceive(context, intent);方法:
获取传给来的号码,根据PhoneApp的实例获取PhoneType等。最后启动InCall界面:
Intent newIntent = new Intent(Intent.ACTION_CALL, uri);
newIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);
newIntent.setClass(context, InCallScreen.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
5、请求拨号的java部分流程
6、请求拨号的c/c++部分流程
6.1、初始化事件循环,启动串口监听,注册socket监听。
rild.c->main()
(1)、RIL_startEventLoop
//建立事件循环线程
ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);
//注册进程唤醒事件回调
ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,
processWakeupCallback, NULL);
rilEventAddWakeup (&s_wakeupfd_event);
//建立事件循环
ril_event_loop
for (;;) {
...
n = select(nfds, &rfds, NULL, NULL, ptv);
// Check for timeouts
processTimeouts();
// Check for read-ready
processReadReadies(&rfds, n);
// Fire away
firePending();
}
(2)、funcs = rilInit(&s_rilEnv, argc, rilArgv);//实际是通过动态加载动态库的方式执行reference-ril.c中的RIL_Init
//单独启动一个线程读取串口数据
ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);
fd = open (s_device_path, O_RDWR);
ret = at_open(fd, onUnsolicited);
ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);
RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);
在initializeCallback中执行的程序:
setRadioState (RADIO_STATE_OFF);
at_handshake();
/* note: we don't check errors here. Everything important will
be handled in onATTimeout and onATReaderClosed */
/* atchannel is tolerant of echo but it must */
/* have verbose result codes */
at_send_command("ATE0Q0V1", NULL);
/* No auto-answer */
at_send_command("ATS0=0", NULL);
...
//注册rild socket端口事件监听到事件循环中
(3)、RIL_register(funcs);
s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);
ret = listen(s_fdListen, 4);
ril_event_set (&s_listen_event, s_fdListen, false,
listenCallback, NULL);//将此端口加入事件select队列
rilEventAddWakeup (&s_listen_event);
如果rild socket端口有数据来了将执行listencallback函数
listencallback
//为此客户端连接创建新的监听句柄,s_fdListen继续监听其他客户端的连接。
s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);
ril_event_set (&s_commands_event, s_fdCommand, 1,
processCommandsCallback, p_rs);//将此端口加入事件select队列
rilEventAddWakeup (&s_commands_event);
6.2、socket监听,收到dial的socket请求
processCommandsCallback
//读数据到p_record中
ret = record_stream_get_next(p_rs, &p_record, &recordlen);
processCommandBuffer(p_record, recordlen);
p.setData((uint8_t *) buffer, buflen);
// status checked at end
status = p.readInt32(&request);
status = p.readInt32 (&token);//请求队列中的序号
pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));
pRI->token = token;
/*
包含#include "ril_commands.h"语句,结构体如下:
typedef struct {
int requestNumber;
void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);
int(*responseFunction) (Parcel &p, void *response, size_t responselen);
} CommandInfo;
*/
pRI->pCI = &(s_commands[request]);
pRI->p_next = s_pendingRequests;
s_pendingRequests = pRI;
pRI->pCI->dispatchFunction(p, pRI);
//假设是接收了dial指令,pRI->PCI->dispatchFunction(p,pRI),调用dispatchDial (p,pRI)
dispatchDial (p,pRI)
s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeof(dial), pRI);
in reference-ril.c onRequest()
...
switch (request) {
case RIL_REQUEST_DIAL:
requestDial(data, datalen, t);
asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);
ret = at_send_command(cmd, NULL);
err = at_send_command_full (command, NO_RESULT, NULL, NULL, 0, pp_outResponse);
err = at_send_command_full_nolock(command, type, responsePrefix, smspdu,timeoutMsec, sponse);
err = writeline (command);
//此处等待,直到收到成功应答或失败的应答,如:ok,connect,error cme等
err = pthread_cond_wait(&s_commandcond, &s_commandmutex);
waiting....
waiting....
/* success or failure is ignored by the upper layer here.
it will call GET_CURRENT_CALLS and determine success that way */
RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
p.writeInt32 (RESPONSE_SOLICITED);
p.writeInt32 (pRI->token);
errorOffset = p.dataPosition();
p.writeInt32 (e);
if (e == RIL_E_SUCCESS) {
/* process response on success */
ret = pRI->pCI->responseFunction(p, response, responselen);
if (ret != 0) {
p.setDataPosition(errorOffset);
p.writeInt32 (ret);
}
}
sendResponse(p);
sendResponseRaw(p.data(), p.dataSize());
blockingWrite(fd, (void *)&header, sizeof(header));
blockingWrite(fd, data, dataSize);
6.4、串口监听收到atd命令的应答"OK"或"no carrier"等
readerLoop()
line = readline();
processLine(line);
handleFinalResponse(line);
pthread_cond_signal(&s_commandcond);//至此,前面的等待结束,接着执行RIL_onRequestComplete函数
6.5、java层收到应答后的处理,以dial为例子.
ril.java->RILReceiver.run()
for(;;)
{
...
length = readRilMessage(is, buffer);
p = Parcel.obtain();
p.unmarshall(buffer, 0, length);
p.setDataPosition(0);
processResponse(p);
type = p.readInt();
if (type == RESPONSE_SOLICITED) {
processSolicited (p);
serial = p.readInt();
rr = findAndRemoveRequestFromList(serial);
rr.mResult.sendToTarget();
......
}
CallTracker.java->handleMessage (Message msg)
switch (msg.what) {
case EVENT_OPERATION_COMPLETE:
ar = (AsyncResult)msg.obj;
operationComplete();
cm.getCurrentCalls(lastRelevantPoll);
第二部分:unsolicited 消息从modem上报到java的流程。
C++部分:
readerLoop()
line = readline();
processLine(line);
handleUnsolicited(line);
if (s_unsolHandler != NULL) {
s_unsolHandler (line1, line2);//实际执行的是void onUnsolicited (const char *s, const char *sms_pdu)
if (strStartsWith(s,"+CRING:")|| strStartsWith(s,"RING")
|| strStartsWith(s,"NO CARRIER") || strStartsWith(s,"+CCWA") )
RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
p.writeInt32 (RESPONSE_UNSOLICITED);
p.writeInt32 (unsolResponse);
ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen);
ret = sendResponse(p);
sendResponseRaw(p.data(), p.dataSize());
ret = blockingWrite(fd, (void *)&header, sizeof(header));
blockingWrite(fd, data, dataSize);
Java部分:
ril.java->RILReceiver.run()
for(;;)
{
...
length = readRilMessage(is, buffer);
p = Parcel.obtain();
p.unmarshall(buffer, 0, length);
p.setDataPosition(0);
processResponse(p);
processUnsolicited (p);
response = p.readInt();
switch(response) {
...
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret = responseVoid(p); break;
...
}
switch(response) {
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
if (RILJ_LOGD) unsljLog(response);
mCallStateRegistrants
.notifyRegistrants(new AsyncResult(null, null, null));
...
}
第三部分:猫相关的各种状态的监听和通知机制
第四部分:通话相关的图标变换的工作原理。
A. 注册监听部分
B.事件通知部分
Android Dial处理过程相关推荐
- Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)
本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 上篇文章<<Android中measure过程.WRAP_CONTENT详解以及xml布局文 ...
- android Android项目构建过程
今天,简单讲讲android studio如何把写好的工程打包成apk的. 平时开发过程中我们通过android studio编写完成android项目之后直接点击 Run 'app'就可以在buil ...
- android view绘制过程
应用程序窗口内部所包含的视图对象的实际类型为DecorView.DecorView类继承了View类,是作为容器(ViewGroup)来使用的,它的实现如图1所示: 每一个应用程序窗口的视图对象都有一 ...
- Android的启动过程
Passion注:本篇文章描述的是Android的启动过程,不包括Linux的启动过程 分别来自 http://dingpwen.spaces.live.com/blog/cns!4CADD02D22 ...
- Android studio安装过程中入的坑的记录与记录
Android studio安装过程中入的坑的记录与记录 * 由于最近项目的需求,所以最近一直在配置安卓的开发环境,之前用的是Eclipse + ADT的模式开发的,配置环境也花了一些时间,但是由于谷 ...
- Android 系统(216)---Android坐标分析过程
Android坐标分析过程 Android中有两种坐标系,分别是Android坐标系和视图坐标系. 首先看一下屏幕区域划分 //获取状态栏高度 Rect rect= new Rect(); get ...
- Framework学习(二)Android的启动过程
Android设备的启动过程 上一张介绍了Android的系统的整体架构,认识了体系的构造,今天就讲一下,Android的系统的启动过程. 看了架构图,我们知道架构的设计是至上而下的,但是,Andro ...
- 解决Android Studio安装过程中“SDK tools directory is missing”的问题
解决Android Studio安装过程中"SDK tools directory is missing"的问题 参考文章: (1)解决Android Studio安装过程中&qu ...
- android 按键用户点击事件,Android按键事件处理过程详解
Android按键事件处理过程详解 (2013-09-26 14:05:19) 标签: it 在Android系统中,存在多种界面事件,如点击事件.触摸事件.焦点事件和菜单事件等,在这些界面事件发生时 ...
最新文章
- pwn入门-PLT表与GOT表、libc入门
- TLS--线程局部存储
- Dotnet洋葱架构实践
- 《SAS编程与数据挖掘商业案例》学习笔记之十九
- angular依赖注入_Angular依赖注入简介
- servlet下根据相对路径找资源
- dsp呼吸灯C语言编程,DSP28335 呼吸灯程序
- 牛顿(Newton)插值及其MATLAB程序
- html5离线缓存使用
- unity打开摄像头
- 【Web理论篇】Web应用程序安全与风险
- 传说中的世界500强面试题-数学能力(2)
- ps随机排列_[PS]圆点随机不重叠排列脚本
- 网页播放rtsp视频流最终方案
- 聊天室应用开发实践(二):实现基于 Web 的聊天室
- AM中使用PML语言标注船体结构
- 格式为[区号-座机号-分机号]的座机号校验正则
- Mina中的Snark Worker
- 台式电脑win10系统怎么开启无线服务器,台式电脑win10怎么连wifi_window10台式如何连接wifi...
- vue html模板递归,vue使用递归组件实现多级列表
热门文章
- 谈判技巧之奇怪的压力
- abp vnext安装模块
- 前端开发过程中,经常遇到复制粘贴后自动空白一行,该如何解决这个问题哪?
- Mac 解决github 下载慢问题
- java中instr函数,Oracle中instr函数使用方法
- List中addAll()方法简介
- Mysql无法启动报错19884 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
- Surfacebook误删显卡恢复办法/无法打开nVidia控制面板解决办法/找不到显卡恢复方法
- IT业务运维可观测技术的发展浅析
- Vue 父组件如何触发子组件中的方法