zoukankan      html  css  js  c++  java
  • Android源码分析:Telephony部分–phone进程

    com.android.phone进程

    它就象个后台进程一样,开机即运行并一直存在。它的代码位于:packages/apps/Phone/src/com/android/phone

    当有来电时,它会作出反应,如显示UI和铃声提示;当在通话过程中,它显示InCallScreen; 当要拨号时ITeleohony的接口调用最终到Phone进程,然后由它去与PhoneFactory创建的GSMPhone或CDMAPhone进行交互;通话记录也是由Phone添加到数据库里的。

    最重要的一个类是PhoneAPP,继承自Application,是顶层Phone应用程序类,包含了:

    Phone phone;
    CallNotifier notifier;
    Ringer ringer;
    BluetoothHandsfree mBtHandsfree;
    PhoneInterfaceManager phoneMgr;

    //此处省略了部分成员变量代码

    private InCallScreen mInCallScreen;

    //此处省略了部分成员变量代码

    private Activity mPUKEntryActivity;
    private ProgressDialog mPUKEntryProgressDialog;

    //此处省略了部分成员变量代码

    private KeyguardManager mKeyguardManager;
    private StatusBarManager mStatusBarManager;
    private int mStatusBarDisableCount;
    private AccelerometerListener mAccelerometerListener;

    在froyo版本中, PhoneApp实现了检测人脸对打电话时的干扰,它使用了距离传感器来判断脸部皮肤与屏幕的距离。

    CallNotifier

    CallNotifier是一个Handler,它为PhoneApp处理各个主动上报来的一些消息。它监听来自Telephony层phone状态变化和其它各种事件,从而作出反应 如各种UI行为:启动铃音播放和来电显示UI、播放正在通话时的来电提示、更新状态栏提示(通过NotificationMgr)、通话记录添加等。

    在PhoneBase中提供了一些RegistrantList,CallNotifier可以将自己作为一个感兴趣者注册进去,这样,当状态变化时,CallNotifier将得到通知,然后在线程中对其处理,作出UI方面的响应。在其构造函数中可以看出它处理的消息事件类别,下面的代码列出了部分要处理的消息种类(没有列出针对CDMA或GSM特定类型的消息):

    mPhone.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null);

    mPhone.registerForPreciseCallStateChanged(this, PHONE_STATE_CHANGED, null);

    mPhone.registerForDisconnect(this, PHONE_DISCONNECT, null);

    mPhone.registerForUnknownConnection(this, PHONE_UNKNOWN_CONNECTION_APPEARED, null);

    mPhone.registerForIncomingRing(this, PHONE_INCOMING_RING, null);

    当有PHONE_NEW_RINGING_CONNECTION类型消息到来时,意味着一个RINGING或WAITING的连接(connection)出现,此时handleMessage函数调用onNewRingingConnection来处理。后者先检查Settings里的设置是否可以接听电话;然后进行响铃(见InCallTonePlayer)和显示InCallScreen的UI,见PhoneUtils.showIncomingCallUi()和PhoneApp.displayCallScreen()两个函数。

    通话过程中的铃音提示由线程类InCallTonePlayer完成。

    当有PHONE_INCOMING_RING类型的消息到来时,意味着RIL层受到Ring,此处播放铃音。它使用的是Ringer.ring()函数,它会创建一个线程去播放铃音(见Ringer.makeLooper函数)。

    当收到PHONE_STATE_CHANGED消息时,表明Phone的状态发生了改变,比如响铃后接通了电话,此时处理函数是onPhoneStateChanged,比如再次确认停止铃音、更新状态栏列的状态通知等。

    当收到PHONE_DISCONNECT消息时,表明电话连接已挂断或RingCall断掉。其处理函数是onDisconnect。它清理现场诸如音频通道恢复、来电响铃的停止确认、对InCallScreen的UI清理、若有未接电话须在状态栏显示等。

    PhoneInterfaceManager

    它继承自 Itelephony.Stub,实现了服务器侧的 ITelephony接口,其接口定义见文件:

    frameworks/base/telephony/java/com/android/internal/telephony/ITelephony.aidl

    TelephonyManager作为客户端通过Binder与其交互。

    NotificationMgr

    NotificationMgr以静态成员函数的方式为PhoneApp用于Phone进程在状态栏中通知用户消息的功能,诸如:有未接电话、正在通话、是否静音等信息。它使用系统提供的API类NotificationManager和StatusBarManager完成通知功能。每项通知对应着通知、更新通知和取消通知的函数。当收到Message时,PhoneApp的Handler的handleMessage会使用NotificationMgr更新状态栏信息。下面的代码片段用于更新状态栏的的提示信息:

    case EVENT_UPDATE_INCALL_NOTIFICATION:
    NotificationMgr.getDefault().updateInCallNotification();//通话提示
    break;
    case EVENT_DATA_ROAMING_DISCONNECTED:
    NotificationMgr.getDefault().showDataDisconnectedRoaming();//因漫游数据连接断开提示
    break;
    case EVENT_DATA_ROAMING_OK:
    NotificationMgr.getDefault().hideDataDisconnectedRoaming();//隐藏漫游断开提示
    break;

    是否有未接电话的提示则是在PhoneApp创建NotificationMgr对象并调用其初始化函数时检查提示的。

    InCallScreen

    它是手机正在通话时的Activity。当有来电、开始拨号或正在通话时,运行的是该Activity,UI界面是其对应的View:

    // Inflate everything in incall_screen.xml and add it to the screen.
    setContentView(R.layout.incall_screen);

    在其OnCreate函数中将自己指定为PhoneApp的InCallScreen:

    app.setInCallScreenInstance(this);

    InCallScreen需要处理来电时跳过键盘锁直接可以接听电话、是否有耳机插入的情况、是否用蓝牙接听电话、需要监听并维护更新通话状态并显示给用户、需要支持通话过程中的某些功能(如发送DTMF、电话会议、分离一路通话)操作、OTA Call等。

    CallCard是InCallScreen中的一个call(可能是当前的Call或保持的Call或来电Call)。

    当需要接听电话或拨打电话时,上层发来intent,然后InCallScreen收到intent时它的InCallScreen.onNewIntent函数被调用,解析intent,要么调用placeCall拨打电话,要么调用internalAnswerCall接听电话。

    应用程序可发出Intent进行电话呼叫,如在TwelveKeyDialer.java中进行呼叫时,去创建一个Intent:

    void placeCall() {

    final String number = mDigits.getText().toString();

    boolean sendEmptyFlash = false;

    Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,

    Uri.fromParts(“tel”, number, null));

    if (number == null || !TextUtils.isGraphic(number)) {

    // There is no number entered.

    if (phoneIsCdma() && phoneIsOffhook()) {

    // We only want to send this empty flash extra if we’re CDMA and the

    // phone is offhook (don’t want to send if ringing or dialing)

    intent.putExtra(EXTRA_SEND_EMPTY_FLASH, true);

    sendEmptyFlash = true;

    } else {

    playTone(ToneGenerator.TONE_PROP_NACK);

    return;

    }

    }

    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    startActivity(intent);

    在phone程序中OutgoingCallBroadcaster(文件OutgoingCallBroadcaster.java)的包含一个内部类OutgoingCallReceiver,由它接收电话呼叫Intent,然后经过转换后再发送出去,由上述的InCallScreen接收处理,显示拨号界面并进行呼叫等。

    如OutgoingCallBroadcaster所说,它接收 CALL 和CALL_PRIVILEGED 两种Intents,然后广播出ACTION_NEW_OUTGOING_CALL intent,让别的应用程序有机会去监视这些intent,最后这些呼叫intent又被自己收到转换,启动InCallScreen.

    下面的代码是Intent转换,然后Intent被InCallScreen接收:

    Intent newIntent = new Intent(Intent.ACTION_CALL, uri);

    newIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);

    PhoneUtils.checkAndCopyPhoneProviderExtras(intent, newIntent);

    newIntent.setClass(context, InCallScreen.class);

    newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    if (DBG) Log.v(TAG, “doReceive(): calling startActivity: ” + newIntent);

    context.startActivity(newIntent);

    }

    这样做的目的是

    InCallTouchUi:

    通话过程中的按钮功能以及来电接听时的滑动接听功能。

    ManageConferenceUtils:管理多方通话的工具,包括部分UI元素。借助PhoneUtils实现其功能。

    DTMFTwelveKeyDialer:通话状态时的拨号盘,用于发送DTMF。

    DTMFTwelveKeyDialerView:DTMF拨号视图布局类。

    InCallControlState维护着一些状态信息,诸如是否Enable了Speaker声音免提、是否可以添加新的一路通话等等。它是MVC模式的数据部分。

    InCallMenu是通话状态菜单,里面包含各个菜单项:

    InCallMenuItemView mManageConference;
    InCallMenuItemView mShowDialpad;
    InCallMenuItemView mEndCall;
    InCallMenuItemView mAddCall;
    InCallMenuItemView mSwapCalls;
    InCallMenuItemView mMergeCalls;
    InCallMenuItemView mBluetooth;
    InCallMenuItemView mSpeaker;
    InCallMenuItemView mMute;
    InCallMenuItemView mHold;
    InCallMenuItemView mAnswerAndHold;
    InCallMenuItemView mAnswerAndEnd;
    InCallMenuItemView mAnswer;
    InCallMenuItemView mIgnore;

    InCallMenuItemView继承自TextView,代表着手机处在通话状态时的菜单项。每个菜单项保护一个文本,一个可选的“绿灯”,代表着打开/关闭;在文本上面的可以有可选的图标。其成员函数可以给它们赋值。当它们被点击后,在函数InCallScreen.handleOnscreenButtonClick或InCallScreen.onClick中得到调用。前者用于InCallTouchUi上的点击事件。

    InCallScreen的成员函数

    registerForPhoneStates:用于注册InCallScreen对哪些状态感兴趣。对于GSM手机,则注册了这些:

    mPhone.registerForPreciseCallStateChanged(mHandler, PHONE_STATE_CHANGED, null);
    mPhone.registerForDisconnect(mHandler, PHONE_DISCONNECT, null);
    mPhone.registerForMmiInitiate(mHandler, PhoneApp.MMI_INITIATE, null); mPhone.registerForMmiComplete(mHandler, PhoneApp.MMI_COMPLETE, null);
    mPhone.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null);

    当状态变化收到Message后,由mHandler来响应处理。

    应用程序Dialer/Contacts

    Dialer程序在packages/apps/Contacts中,见DialtactsActivity,它继承自TabActivity类,拥有四个Tab:Dialer、Call log、 Contacts和Favorites四个tab。通过实现接口 TabHost.OnTabChangeListener在各个tab之间切换。

  • 相关阅读:
    js编码中常用的知识点
    oracle函数的使用
    oracle 临时表的使用
    oracle11G归档日志管理
    oracle中 高水位线详解
    oracle并行模式(Parallel)
    oracle常用函数详解(详细)
    oracle系统表的查询
    15000 字的 SQL 语句大全
    oracle_单引号问题和execute immediate 赋值问题
  • 原文地址:https://www.cnblogs.com/kevincode/p/3837908.html
Copyright © 2011-2022 走看看