zoukankan      html  css  js  c++  java
  • Andriod通话处理流程

      Andriod通话处理流程

    一、总览

    1、从java端发送at命令的处理流程。

    2、unsolicited 消息从modem上报到java的流程。

    3、猫相关的各种状态的监听和通知机制。

    4、通话相关的图标变换的工作原理。

    5、gprs拨号上网的通路原理。

    6、通话相关的语音通路切换原理、震动接口。

    7、通话相关的notification服务。

    8、通话相关的各种server。

    第一部分:从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.digits,执行

    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()

      //如果为紧急号码马上启动intent.setClass(this, InCallScreen.class); startActivity(intent);

      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());

            if (LOGV) Log.v(TAG, "Broadcasting intent " + broadcastIntent + ".");

            sendOrderedBroadcast(broadcastIntent, PERMISSION, null, 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消息。找到OutgoingCallReceiver,执行

    onReceive()函数

      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部分流程

    onCreate(第一次)/onNewIntent(非第一次)

      internalResolveIntent

        placeCall(intent);

          PhoneUtils.placeCall(mPhone, number, intent.getData());

            phone.dial(number);

              mCT.dial(newDialString);

                dial(dialString, CommandsInterface.CLIR_DEFAULT);

                  cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());//obtainCompleteMessage(EVENT_OPERATION_COMPLETE);

                    send(rr);

                      msg = mSender.obtainMessage(EVENT_SEND, rr);

                      acquireWakeLock();

                      msg.sendToTarget();

                    RILSender.handleMessage()

                      case EVENT_SEND:

                        ...

                        s.getOutputStream().write(dataLength);                   

                        s.getOutputStream().write(data);//从这里流程跑到下面ril.cpp中监听部份

    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));

                  ...

              }

    第三部分、第四部分:猫相关的各种状态的监听和通知机制/通话相关的图标变换的工作原理。

    网络状态,edge,gprs图标的处理
    a、注册监听部分
    ==>SystemServer.java
      init2()
        Thread thr = new ServerThread();
        thr.setName("android.server.ServerThread");
        thr.start();
          ServerThread.run()
            com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
              sInstance = new StatusBarPolicy(context, service);
                // phone_signal
                mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
                mPhoneData = IconData.makeIcon("phone_signal",
                   null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0);
                mPhoneIcon = service.addIcon(mPhoneData, null);
                 // register for phone state notifications.
                ((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE))
                    .listen(mPhoneStateListener,
                              PhoneStateListener.LISTEN_SERVICE_STATE
                            | PhoneStateListener.LISTEN_SIGNAL_STRENGTH
                            | PhoneStateListener.LISTEN_CALL_STATE
                            | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
                            | PhoneStateListener.LISTEN_DATA_ACTIVITY);
                 //实际是调用的是TelephonyRegistry.listen,此listen函数会将Iphonestatelistener添加到对应的的handler数组中,到时来了事件会轮询回调。

                // data_connection
                mDataData = IconData.makeIcon("data_connection",
                    null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0);
                mDataIcon = service.addIcon(mDataData, null);
                service.setIconVisibility(mDataIcon, false);

    b、事件通知部分
    ==>PhoneFactory.java
    makeDefaultPhones()
      sPhoneNotifier = new DefaultPhoneNotifier();
      useNewRIL(context);
        phone = new GSMPhone(context, new RIL(context), sPhoneNotifier);

    for example
    ==>DataConnectionTracker.java
    notifyDefaultData(String reason)
      phone.notifyDataConnection(reason);
        mNotifier.notifyDataConnection(this, reason);
        ==>DefaultPhoneNotifier.java
          mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                        "telephony.registry"));
          mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()),
                        sender.isDataConnectivityPossible(), reason, sender.getActiveApn(),
                        sender.getInterfaceName(null));

    第五部分:gprs拨号上网的通路原理。

    上层java程序调用gprs流程:
    =>PhoneApp.java
      onCreate()
        PhoneFactory.makeDefaultPhones(this);
          phone = new GSMPhone(context, new SimulatedCommands(), sPhoneNotifier);
            mDataConnection = new DataConnectionTracker (this);
              createAllPdpList();//建立缺省pdpconnection
                 pdp = new PdpConnection(phone);
                   dataLink = new PppLink(phone.mDataConnection);
                   dataLink.setOnLinkChange(this, EVENT_LINK_STATE_CHANGED, null);
            
              //某个条件触发执行
              trySetupData(String reason)
               setupData(reason);
                 pdp = findFreePdp();
                 Message msg = obtainMessage();
                 msg.what = EVENT_DATA_SETUP_COMPLETE;
                 msg.obj = reason;
                 pdp.connect(apn, msg);
                             phone.mCM.setupDefaultPDP(apn.apn, apn.user, apn.password,
                                obtainMessage(EVENT_SETUP_PDP_DONE));
             
               //收到EVENT_SETUP_PDP_DONE消息
               =>pdpconnection.java
               handleMessage()
                 case EVENT_SETUP_PDP_DONE:
                   dataLink.connect();//dataLink是pppLink.java
                      SystemService.start(SERVICE_PPPD_GPRS);//启动pppd_grps服务
                      poll.what = EVENT_POLL_DATA_CONNECTION;
                      sendMessageDelayed(poll, POLL_SYSFS_MILLIS);//启动轮询,看是否成功连接gprs
                        checkPPP()//每隔5秒轮询,看是否连接成功,或断开
                          //如果已经连接
                          mLinkChangeRegistrant.notifyResult(LinkState.LINK_UP);

                      //执行到pdpconnection.handleMessage()
                      case EVENT_LINK_STATE_CHANGED
                        onLinkStateChanged(ls);
                          case LINK_UP:
                            notifySuccess(onConnectCompleted);
                              onCompleted.sendToTarget();
                   
                      //执行dataConnectionTracker.java的handleMessage()
                      case EVENT_DATA_SETUP_COMPLETE
                        notifyDefaultData(reason);
                          setupDnsProperties();
                          setState(State.CONNECTED);
                          phone.notifyDataConnection(reason);
                          startNetStatPoll();
                            resetPollStats();
                            1、读取发送出去的包数和接受到的包数
                            2、如果发送的数据包且没有收到应答包数n大于等于看门狗追踪的限定包数。
                            2.1、开始轮询pdp context list,尝试恢复网络连接
                            2.2、如果轮询24次后还没有联通网络则停止网络状态轮询,进行一次ping实验。
                            2.2.1、如果ping成功则,重新进行网络状态轮询,否则发送EVENT_START_RECOVERY事件。

                          // reset reconnect timer
                          nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;

    着重c++部分代码的角度分析

    =>DataConnectionTracker.java
    trySetupData(String reason)
      setupData(reason);
        =>PdpConnection.java
        pdp.connect(apn, msg);
          =>RIL.JAVA
          phone.mCM.setupDefaultPDP(apn.apn, apn.user, apn.password,
                    obtainMessage(EVENT_SETUP_PDP_DONE));
            send(rr);
            //send socket to RIL
           
            //enter c++ layer
            =>ril.cpp
            processCommandsCallback (int fd, short flags, void *param)
              processCommandBuffer(p_record, recordlen);
                status = p.readInt32(&request);
                pRI->pCI = &(s_commands[request]);
                pRI->pCI->dispatchFunction(p, pRI);
                 dispatchStrings();
                   s_callbacks.onRequest(pRI->pCI->requestNumber, pStrings, datalen, pRI);
                   =>reference-ril.c
                     onRequest();
                       requestSetupDefaultPDP(data, datalen, t);
                         err = write_at_to_data_channel("ATD*99***1#",1);
                        
                         //after a while.get "connect" from data channel,so need to send socket message to java layer.
                         p.writeInt32 (RESPONSE_SOLICITED);
                         p.writeInt32 (pRI->token);//the serial No  in the request list.
                         errorOffset = p.dataPosition();
                         p.writeInt32 (e);
                         if (e == RIL_E_SUCCESS) {
                            /* process response on success */
                            ret = pRI->pCI->responseFunction(p, response, responselen);

                            /* if an error occurred, rewind and mark it */
                            if (ret != 0) {
                              p.setDataPosition(errorOffset);
                              p.writeInt32 (ret);
                            }
                         }
                         sendResponse(p);
                         sendResponseRaw(p.data(), p.dataSize());
                           ret = blockingWrite(fd, (void *)&header, sizeof(header));
                           blockingWrite(fd, data, dataSize);
                          
                           =>RIL.JAVA
                           RILReceiver.run();
                             length = readRilMessage(is, buffer);
                             p = Parcel.obtain();
                             p.unmarshall(buffer, 0, length);
                             p.setDataPosition(0);
                             processResponse(p);
                               processSolicited (p);
                                 serial = p.readInt();
                                 error = p.readInt();
                                 rr = findAndRemoveRequestFromList(serial);
                                 ret =  responseStrings(p);
                                 if (rr.mResult != null) {
                                   AsyncResult.forMessage(rr.mResult, ret, null);
                                   rr.mResult.sendToTarget();
                                 }
             
           =>pdpConnection.java
           handleMessage()
             case EVENT_SETUP_PDP_DONE:
                ...
                dataLink.connect();
                =>pppLink.java
                  SystemProperties.set(PROPERTY_PPPD_EXIT_CODE, "");
                  SystemService.start(SERVICE_PPPD_GPRS);//启动pppd_grps服务

                  poll.what = EVENT_POLL_DATA_CONNECTION;
                  sendMessageDelayed(poll, POLL_SYSFS_MILLIS);
                  dataConnection.state = State.CONNECTING;
                  handleMessage()
                    case EVENT_POLL_DATA_CONNECTION
                      checkPPP();
                        if (ArrayUtils.equals(mCheckPPPBuffer, UP_ASCII_STRING, UP_ASCII_STRING.length)
                        || ArrayUtils.equals(mCheckPPPBuffer, UNKNOWN_ASCII_STRING,
                                UNKNOWN_ASCII_STRING.length)
                                && dataConnection.state == State.CONNECTING)
                        if (mLinkChangeRegistrant != null) {
                          mLinkChangeRegistrant.notifyResult(LinkState.LINK_UP);
                      =>pdpConnection.java
                      handleMessage()
                        case EVENT_LINK_STATE_CHANGED:
                          DataLink.LinkState ls  = (DataLink.LinkState) ar.result;
                          onLinkStateChanged(ls);
                            case LINK_UP:
                               notifySuccess(onConnectCompleted);
                                 AsyncResult.forMessage(onCompleted);
                                 onCompleted.sendToTarget();
                                
                                 =>DataConnectionTracker.java
                                 handleMessage()
                                   case EVENT_DATA_SETUP_COMPLETE:
                                   ...
                                     SystemProperties.set("gsm.defaultpdpcontext.active", "true");
                                     notifyDefaultData(reason);
                                       setupDnsProperties();//设置dns,gw,我们的实现方式是在pppd中设置的,不用pppd拨号的适用。
                                       setState(State.CONNECTED);
                                       phone.notifyDataConnection(reason);
                                           mNotifier.notifyDataConnection(this, reason);
                                           =>DefaultPhoneNotifier.java
                                              //mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
                        "telephony.registry"));构造函数中初始化了mRegistry
                                              mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()),
                                                  sender.isDataConnectivityPossible(), reason, sender.getActiveApn(),
                                                  sender.getInterfaceName(null));
                                      startNetStatPoll();    

                    }

    第六部分:通话相关的语音通路切换原理、震动接口

    6、语音通路

    6.1、设置语音通路的路由

    目前我们有两处处理:

    a、CallTracker.java中的

    handlePollCalls()

      检测到+clcc返回的电话列表中有状态为DriverCall.State.ALERTING(表示拨打电话后,对方已经振铃),此时需要设置语音通路为MODE_IN_CALL

    b、PhoneUtils.java中setAudioMode()函数

    c、调用通路分析

     AudioManager audioManager = (AudioManager) context.getSystemService

       (Context.AUDIO_SERVICE);

     audioManager.setMode(mode);

       AudioManager.setMode(mode);

         AudioService.setMode(mode);

           AudioSystem.setMode(mode);(native function)

             android_media_AudioSystem.cpp==>android_media_AudioSystem_setMode()

             AudioSystem.cpp==>setMode()

               const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();

                 binder = sm->getService(String16("media.audio_flinger"));

                 ...

                 gAudioFlinger = interface_cast<IAudioFlinger>(binder);

                 ...

                 return gAudioFlinger;

                              通过查找“media.audio_flinger”发现AudioFlinger.cpp==>instantiate()//Main_mediaserver.cpp中被实例化。

                    defaultServiceManager()->addService(String16("media.audio_flinger"), new AudioFlinger());

                      mAudioHardware = AudioHardwareInterface::create();

                        LOGV("Creating Vendor Specific AudioHardware");

                        hw = createAudioHardware();

                          return new AudioHardwareMarvell();

               return af->setMode(mode);

                 AudioHardwareLittle.cpp==>setMode(mode)

                   doRouting();

                     enable_incall_headphone()//or others...

                       system("alsactl -f /etc/alsactl/asound.state_none restore");

                       system("alsactl -f /etc/alsactl/asound.state_headset_r_s restore");

    6.2、来电播放振铃,挂断或接听停止振铃。

     ==>Phone.app

     onCreate()

        ringer = new Ringer(phone);

          Vibrator mVibrator = new Vibrator();

            mService = IHardwareService.Stub.asInterface(ServiceManager.getService("hardware"));

        notifier = new CallNotifier(this, phone, ringer, mBtHandsfree);

          mPhone.registerForIncomingRing(this, PHONE_INCOMING_RING, null);

          mPhone.registerForPhoneStateChanged(this, PHONE_STATE_CHANGED, null);

          mPhone.registerForDisconnect(this, PHONE_DISCONNECT, null);

          ...

          case PHONE_INCOMING_RING:

            mRinger.ring();

              mHardwareService.setAttentionLight(true);

              mVibratorThread.start();

                while (mContinueVibrating) {

                mVibrator.vibrate(VIBRATE_LENGTH);

                    SystemClock.sleep(VIBRATE_LENGTH + PAUSE_LENGTH);

                }

              ...

              makeLooper();

              mRingHandler.sendEmptyMessage(PLAY_RING_ONCE);

              ...

              case PLAY_RING_ONCE:

                PhoneUtils.setAudioMode(mContext, AudioManager.MODE_RINGTONE);

                r.play();

          ...

          case PHONE_DISCONNECT:

          case PHONE_STATE_CHANGED:

            ...

            mRinger.stopRing();

              Message msg = mRingHandler.obtainMessage(STOP_RING);

              msg.obj = mRingtone;

              mRingHandler.sendMessage(msg);

              case STOP_RING:

                 r.stop();

                 getLooper().quit();

              ...

              mVibrator.cancel();

    第七部分:通话相关的notification服务

    7、通话相关的notification服务。

    7.1、NotificationMgr

    ==>PhoneApp.java

    onCreate()

       NotificationMgr.init(this)//NotificationMgr.java//此类主要负责电话通知的具体表现(通知和取消通知),未接图标、通话中、蓝牙激活中、保持中,静音、免提等。封装了简单的瞬间显示文本消息的功能。提供漫游数据连接禁止的通知封装和漫游数据连接允许时取消通知

         sMe = new NotificationMgr(context);

           mNotificationMgr = (NotificationManager)

                context.getSystemService(Context.NOTIFICATION_SERVICE);

           mStatusBar = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); //主要用于显示静音和speaker状态的图表(在状态条右边显示)

         sMe.updateNotifications();//主要功能是:

                1、查询是否有未读的未接听电话,并显示到状态栏图标,和通知列表

                2、根据是否是电话状态,更新状态栏图表和通知列表(可能是激活,蓝牙,保持等)

    7.2、CallNotifier

    ==>PhoneApp.java

      onCreate()

        notifier = new CallNotifier(this, phone, ringer, mBtHandsfree);//此类主要是监听通话相关的事件,然后进行例如来电播放铃声,震动。挂断、接听停止振铃等(调用Ringer类实现此功能),根据不同的状态调用调用NotificationMgr进行具体的通知和取消通知。

    第八部分: 通话相关的各种server

    电话通信相关的服务:
    (1)、从ServiceManager得到的:
    a、wifiService
    b、PhoneInterfaceManager
    c、PhoneSubInfo
    d、SimPhoneBookInterfaceManager
    e、SimSmsInterfaceManager
    f、TelephonyRegistry
    g、NetStatService
    h、ConnectivityService

    (2)、从ApplicationContext得到的:
    a、TelephonyManager

  • 相关阅读:
    FreeBSD 里面用 ADSL 来上网的设置
    功能齐全的DataGrid
    jsp中动态生成图像
    配置Struts应用解读Struts应用的两大配置文件
    spring 事务配置
    文件上传原理简单实现
    html中position两属性relative和absolute区别
    html 窗口参数详解
    hibernate联合主键的使用
    自动投票的一个脚本
  • 原文地址:https://www.cnblogs.com/pandans/p/1882948.html
Copyright © 2011-2022 走看看