`

Android Phone拨出电话流程

阅读更多
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);
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    Android_phone流程图

    拨出电话的流程相对复杂,涉及到多个组件和类的交互: 1. 用户在任何界面发起拨号请求(如拨号盘、通话记录或联系人),都会触发outgoingCallBroadcast的onCreate()函数。在这里,获取Action和Number,并进行判断,...

    Android phone 框架介绍

    - **InCallScreen.java**:负责处理来电和拨出电话的主界面显示逻辑。 - **PhoneInterfaceManager.java**:实现 ITelephony.Stub 接口,提供给后台服务使用的 Java 层服务。这些服务可以通过调用 PhoneUtils 的方法...

    Android 通话模块来电和去电流程分析

    #### 二、拨出电话(语音电话)流程详解 拨出电话的过程涉及多个层次的交互,从用户界面到系统核心层,每个环节都紧密相连。下面将详细介绍这一过程中的主要步骤。 ##### 第一部分:主动下发命令消息 1. **...

    android 打电话程序

    系统会检查权限,如果权限已获取,就会显示拨号界面或直接拨出电话,否则会提示用户授权。 6. **安全考虑**:在实际开发中,为了防止恶意使用,应该在拨打电话前检查用户是否真的愿意执行这个操作,通常会通过...

    Android 4.4 Kitkat Phone工作流程浅析(十)__"通话显示"查询流程 图片资源

    7. **UI展示**:最后,获取到的`displayName`会呈现在手机的来电或拨号界面上,供用户识别来电者或确认拨出的号码。 通过以上分析,我们可以看到Android 4.4 KitKat中的“通话显示”查询流程是一个复杂但高效的过程...

    Android4.4InCallUI源码(Phone)

    在`Phone`应用中,`InCallUI`通过`PhoneStateListener`监听电话状态的变化,如来电、拨出、通话结束等。当有新的电话状态发生时,`InCallUI`会根据`PhoneStateListener`的回调方法,更新UI展示。此外,`InCallUI`还...

    Android应用源码之电话、短信黑白名单拦截、电话录音-IT计算机-毕业设计.zip

    - **BroadcastReceiver**:注册一个广播接收器,监听系统的电话事件,如`ACTION_NEW_OUTGOING_CALL`用于拦截拨出电话,`ACTION_PHONE_STATE_CHANGED`用于拦截打入电话。 - **拦截逻辑**:根据设定的黑白名单,对比...

    安卓开发-android打电话源码.zip

    除了拨打电话,Android还提供了`ACTION_DIAL`动作,用于打开拨号盘并预填电话号码,但不会直接拨出电话。这通常用于让用户确认是否真的要拨打电话: ```java // 创建Intent Intent dialIntent = new Intent(Intent....

    应用源码之Phone.zip

    1. 通话管理:处理拨出和接收到的电话,包括电话状态的监听、通话录音、通话计费等。 2. 联系人管理:存储、检索和编辑联系人信息,与系统联系人数据库交互。 3. 电话簿:展示联系人列表,支持搜索、添加和删除联系...

    无限拨号器

    这样的特性对于需要频繁拨打电话的业务流程特别有用,比如火车或飞机票的电话预订系统,用户只需要设置好电话号码和拨打次数,应用就能自动完成整个过程,无需人工持续干预。这样既节省了时间,也减少了错误的可能性...

    mobileandroid双模手机的开发流程及框架.docx

    未优化的RIL可能导致电话漏接、无法拨出、短信异常等问题。 - 漏接电话可能由于GSM射频通讯基带部分或WinCE系统响应机制故障。 - 硬件问题,如GSM信号质量不佳,可能影响电话拨出。 - 软件问题,WinCE系统未能...

    InCallActivity启动Performance浅析图片资源

    在Android系统中,InCallActivity是电话应用中的一个重要组件,主要负责处理来电、拨出电话以及通话中的各种交互。在Android 5.1 Lollipop版本中,对InCallActivity的性能进行了优化,以提供更好的用户体验。本文将...

Global site tag (gtag.js) - Google Analytics