android呼叫流程分析--整体介绍

android4.2 /MTK6572 Phone call分析

 

目 录

1. 概述 4

1.1 Phone Call 4

1.1.1 框架介绍 4

1.1.2 功能说明 5

2. 4.2呼叫相关类分析 6

2.1 基本知识 6

2.1.1 文件说明 6

2.2 DialtactsActivity 7

2.2.1 onCreate 7

2.2.2 其他 10

2.3 CallManager 11

2.3.1 说明 11

2.3.2 初始注册 12

2.3.3 业务注册 13

2.4 CallNotifier 15

2.4.1 说明 15

2.5 PhoneInterfaceManager 17

2.5.1 说明 17

2.6 NotificationMgr 17

2.6.1 说明 17

2.7 InCallScreen 18

2.7.1 说明 18

3. ICS Android 4.2 呼叫流程 21

3.1 呼叫请求 21

3.1.1 拨号请求(Contact 21

3.1.2 拨号请求(Phone 26

3.1.3 进入通话界面 30

3.2 呼叫建立 34

3.2.1 ECPI 34

3.2.2 ECPI消息处理 37

3.2.3 界面更新 40

3.3 呼叫结束 40

3.3.1 ECPI消息处理 40

3.3.2 界面更新 42

3.4 MO呼叫流程图 42

3.5 MT呼叫 43

3.5.1 接听 43

3.5.2 拒接 43

3.6 挂断呼叫 43

 

1. 
概述

1.1 Phone Call 

(本文在文字描述和图片引用方面,使用了其他同学的部分内容,在此感谢!本人侧重代码分析,在此将分析过程分享给大家。)

1.1.1 框架介绍

...

 

Telephony层的相关类关系如下:

 

1.1.1 功能说明

 

        GsmCallTracker对象中还提供有三个GsmCall对象(派生自抽象类Call):ringingCall(用来管理处于INCOMINGWAITING状态的通话)、foregroundCall(用来管理处于DAILINGALERTINGACTIVE状态的通话)、backgroundCall(用来管理HOLD的通话)。

GsmCallTrackerCall应用中的通话管理层,它维护了一个最多MAX_CONNECTIONS=7GsmConnections通话链路的同时,还维护了三种通话状态(ringingCallforegroundCallbackgroundCall,GsmCall以及GsmConnectionGsmCallTracker维护的对象,同时GsmConnection又依附于GsmCall的存在,MAX_CONNECTIONS_PER_CALL=5表明最多可以有5路通话处于某一个通话状态(foregroundCall,background,ringing)GsmConnection继承自Connection类,该类主要是用来维护某一路的通话状态。当它们状态均为DISCONNECTED时意味着该GSMCallIDLE状态。

 

在GSMCallTracker中维护着通话列表:connections。顺序记录了正连接上的通话,这些通话包括:ACTIVEDIALINGALERTINGHOLDINGINCOMINGWAITING等状态的连接。GSMCallTracker将这些连接分为了三类别进行管理:RingingCall: INCOMING ,WAITING  ForegourndCall: ACTIVE, DIALING ,ALERTING BackgroundCall: HOLDING

 

另外GSMCallTracker还包含一个GsmConnection类型(派生自抽象类Connection)的数组对象Connections,用来维护所有的现行的通话的列表,GSMCallTracker对象最大可维护7路通话。

         GsmConnection对象中有个成员变量:GsmCall parent,这个成员变量是用来表示该connection是属于哪个Call的,一个Call可以有多个Connection,但一个Connection只能属于一个Call

 

1. 4.2呼叫相关类分析

1.1 基本知识

1.1.1 文件说明

CallDetailActivity.java 联系人详情

DialtactsActivity.java  通话记录

VoicemailContract.java 存放VM相关的一些常量、URI等,子类Status会经常被引用。

在calllogfragment.java  通话记录列表里添加了vvm的记录。

在CallDetailActivity.java 联系人详情里添加了详细信息显示。

在CallDetailHistoryAdapter.java里做详细信息数据适配器

DialpadFragment.java 拨号盘界面

 

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

 

1.2 DialtactsActivity

DialtactsActivity.java  Dialer程序在packages/apps/Contacts中,见DialtactsActivity,它继承自TabActivity类是通话界面入口activity,包含3个功能项,由3tab呈现, 通过实现接口 TabHost.OnTabChangeListener在各个tab之间切换。界面如下,

 

 

1.1.1 onCreate

onCreate主要完成了如下注释的几个工作,

 

         protected void onCreate(Bundle icicle) {

        …       

        final Intent intent = getIntent();

        fixIntent(intent);

        setContentView(R.layout.dialtacts_activity); //载入layout,该layout修改后只有一个view pager

 

        mContactListFilterController = ContactListFilterController.getInstance(this);

        mContactListFilterController.addListener(mContactListFilterListener);

 

        findViewById(R.id.dialtacts_frame).addOnLayoutChangeListener(mFirstLayoutListener);

 

        mViewPager = (ViewPager) findViewById(R.id.pager);//获取view的控件引用,并进行相关设置

        mViewPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));//getFragmentManager在activity里面,该句详细分析见后

        mViewPager.setOnPageChangeListener(mPageChangeListener); // 监听器设置当前文件只改变了索引

        mViewPager.setOffscreenPageLimit(2);

        addDialpadScrollingThreshold(true);

        …

        

        // Setup the ActionBar tabs (the order matches the tab-index contants TAB_INDEX_*)

        setupDialer();// 设置各功能项,当前只是添加了tab,实现在其他地方

        setupCallLog();

        setupFavorites();

        getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        getActionBar().setDisplayShowTitleEnabled(false);

        getActionBar().setDisplayShowHomeEnabled(false);

 

      …

        setCurrentTab(intent);

    }   

 

1)布局文件

dialtacts_activity.xml

    <android.support.v4.view.ViewPager

        android:id="@+id/pager"

        android:layout_width="match_parent"

        android:layout_height="match_parent" />      

 

2ViewPager

根据onCreate以及后面的start等方法,我们并没有明显发现各tab项对应的界面布局和相关数据处理,而且我们的layout也仅仅是一个ViewPager类,我们需要找到tab的实现过程。

通过代码分析我们可以看出mDialpadFragment、mCallLogFragment、mPhoneFavoriteFragment是各tab对应的类的引用,他们通过onAttachFragment被赋值,通过子类ViewPagerAdapter的方法getItem来new出各自的实例。

public void onAttachFragment(Fragment fragment) {

        if (fragment instanceof DialpadFragment) {

            mDialpadFragment = (DialpadFragment) fragment;

        } else if (fragment instanceof CallLogFragment) {

            mCallLogFragment = (CallLogFragment) fragment;

        } else if (fragment instanceof PhoneFavoriteFragment) {

            mPhoneFavoriteFragment = (PhoneFavoriteFragment) fragment;

}

 

ViewPagerAdapter:

        public Fragment getItem(int position) {

            switch (position) {

                case TAB_INDEX_DIALER:

                    return new DialpadFragment();

                case TAB_INDEX_CALL_LOG:

                    return new CallLogFragment();

                case TAB_INDEX_FAVORITES:

                    return new PhoneFavoriteFragment();

            }

 

这些方法是如何关联上的,各类之间的关系是怎样的,我们可以进一步来分析。

 

根据上面onCreate的代码可以看出,通过layout,我们得到了一个ViewPager的引用,然后设置adapter,在setAdapter里调用populate,populate调用addNewItem,addNewItem调用mAdapter.instantiateItem,而getItem则是被instantiateItem调用的,所以我们能知道通过getItem最终将new出来的实例传递给了ViewPager。

 

对于其中的mAdapter,则是onCreate新建的子类ViewPagerAdapter的实例,通过它的继承关系,可以看到getItem是被父类FragmentPagerAdapter的instantiateItem调用的。

          public Object instantiateItem(ViewGroup container, int position) {

            fragment = getItem(position);

 

onAttachFragment是在new Fragment的时候被调用的,它是在Fragment.onAttach()后并在Fragment.onCreate()前被调用的。

 

这样,mDialpadFragment等对象实例就初始化好了,并通过一些粘合的方法关联到tab上了。

 

3setupDialer

添加tab项。以setupDialer为例,说明tab是如何添加的,这里需要注意的是对mTabListener的设置,关联了ViewPagertab

   private void setupDialer() {

         final Tab tab = getActionBar().newTab();

        tab.setContentDescription(R.string.dialerIconLabel);

        tab.setTabListener(mTabListener);

        tab.setIcon(R.drawable.ic_tab_dialer);

        getActionBar().addTab(tab);

}

 

4

如果启动了contact进程,从launcher里面进入到dailtactsactivity,不会再走onCreate,而是先走onNewIntent,再走start

 

进程如何启动,为何不走onCreate

1.1.2 其他

onNewIntent

 

在其他应用使用拨号,调用onNewIntent,调用栈如下,

DialtactsActivity.onNewIntent(Intent) line: 1135

Instrumentation.callActivityOnNewIntent(Activity, Intent) line: 1156

ActivityThread.deliverNewIntents(ActivityThread$ActivityClientRecord, List) line: 2493

ActivityThread.performNewIntents(IBinder, List) line: 2506

ActivityThread.handleNewIntent(ActivityThread$NewIntentData) line: 2515

ActivityThread.access$1400(ActivityThread, ActivityThread$NewIntentData) line: 162

ActivityThread$H.handleMessage(Message) line: 1435

ActivityThread$H(Handler).dispatchMessage(Message) line: 107

Looper.loop() line: 194

ActivityThread.main(String[]) line: 5400

Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]

Method.invoke(Object, Object...) line: 525

ZygoteInit$MethodAndArgsCaller.run() line: 837

ZygoteInit.main(String[]) line: 604

NativeStart.main(String[]) line: not available [native method]

 

 

setCurrentTab

设置当前tab关联的viewPage对象。这个方法是tabview的粘合方法。

 

 

mainmenu进入DialpadFragment的调用栈,

DialpadFragment.onStart() line: 1043

DialpadFragment(Fragment).performStart() line: 1719

FragmentManagerImpl.moveToState(Fragment, int, int, int, boolean) line: 913

FragmentManagerImpl.moveToState(int, int, int, boolean) line: 1057

FragmentManagerImpl.moveToState(int, boolean) line: 1039

FragmentManagerImpl.dispatchStart() line: 1845

DialtactsActivity(Activity).performStart() line: 5138

DialtactsActivity(Activity).performRestart() line: 5187

DialtactsActivity(Activity).performResume() line: 5192

 

 

1.1 CallManager

1.1.1 说明

 

* CallManager class provides an abstract layer for PhoneApp to access

 * and control calls. It implements Phone interface.

 *

 * CallManager provides call and connection control as well as

 * channel capability.

 *

 * There are three categories of APIs CallManager provided

 *

 *  1. Call control and operation, such as dial() and hangup()

 *  2. Channel capabilities, such as CanConference()

 *  3. Register notification

如上描述,CallManager提供Phone应用的抽象层处理,主要提供3类接口API:呼叫控制、信道信息、注册通知。

1.1.2 初始注册

CallManager提供registerPhone来进行相关实例的初始注册。

 

PhoneGlobals.java在onCreate里面调用自身方法registerPhone,间接调用CallManager.registerPhone来注册相关实例。

    private void registerPhone() {

        mCM = CallManager.getInstance();

        if (GeminiUtils.isGeminiSupport()) {

            mCMGemini = MTKCallManager.getInstance();

            mCMGemini.registerPhoneGemini(phone);

        } else {

            mCM.registerPhone(phone);

        }

    }      

 

PhoneProxy.java里在重建phone对象时也会进行registerPhone注册。   

deleteAndCreatePhone()

{

if(mActivePhone != null) 

CallManager.getInstance().registerPhone(mActivePhone);

}

                    

 

对于CallManager registerPhone的实现,如下,为每个卡槽实例提供呼叫相关的注册,

    public boolean registerPhone(Phone phone) {

       if ((FeatureOption.MTK_BSP_PACKAGE == true) && 

       (FeatureOption.MTK_GEMINI_SUPPORT == true) && 

       (!(phone instanceof SipPhone))) {

           int count = (MAXIMUM_SIM_COUNT < PhoneConstants.GEMINI_SIM_NUM) ? MAXIMUM_SIM_COUNT : PhoneConstants.GEMINI_SIM_NUM;

        /* registerPhone is called by Google default PhoneAPP */

           for (int i = 0; i < count; i++) {

               Phone p = ((GeminiPhone)phone).getPhonebyId(PhoneConstants.GEMINI_SIM_1 + i);

               registerOnePhone(p);

           }

           

           int default_sim = SystemProperties.getInt(PhoneConstants.GEMINI_DEFAULT_SIM_PROP, PhoneConstants.GEMINI_SIM_1);

           mDefaultPhone = getPhoneBase(((GeminiPhone)phone).getPhonebyId(default_sim));

           Log.d(LOG_TAG, "[BSPPackage]default_sim = " + default_sim);

           Log.d(LOG_TAG, "[BSPPackage]mDefaultPhone = " + mDefaultPhone);

           registerForPhoneStates(getPhoneBase(phone));

           return true;

 

每个卡槽实例都注册mPhones、mRingingCalls、mBackgroundCalls、mForegroundCalls。

       private boolean registerOnePhone(Phone phone) {

       boolean result = false;

        Phone basePhone = getPhoneBase(phone);

        if (basePhone != null && !mPhones.contains(basePhone)) {

            mPhones.add(basePhone);

            mRingingCalls.add(basePhone.getRingingCall());

            mBackgroundCalls.add(basePhone.getBackgroundCall());

            mForegroundCalls.add(basePhone.getForegroundCall()); 

            result = true;   

        }

        return result;

    }   

 

1.1.3 业务注册

1)向上提供注册服务

CallManager通过向应用的上层提供注册服务的方法,将呼叫信息和网络状态上报。

 

常规的注册方法是GeminiRegister做中转,向上层提供注册方法,GeminiRegister再调用CallManager的注册方法,将客户端的信息封装到RegistrantList里面,使用时再调用RegistrantList的方法notifyRegistrants通知到其客户端。

InCallScreen里面注册呼叫事件改变,

      GeminiRegister.registerForPreciseCallStateChanged(callManager, mHandler, PHONE_STATE_CHANGED);

 

CallManager里,mPreciseCallStateRegistrants是对应的RegistrantList,handler和事件被封装存放起来,

    public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){

        mPreciseCallStateRegistrants.addUnique(h, what, obj);

    }      

 

CallManager只是一个中间层,它不会自己产生状态信息,它的信息要来源于它的下层。所以它本身也会向下注册(后面会讲到)。如果他收到下层上报的EVENT_PRECISE_CALL_STATE_CHANGED事件,则在handler里面调用它的上层已经注册的RegistrantList,将状态改变通知到其客户端InCallScreen

                case EVENT_PRECISE_CALL_STATE_CHANGED:

                case EVENT_PRECISE_CALL_STATE_CHANGED + NOTIFICATION_ID_OFFSET:

                case EVENT_PRECISE_CALL_STATE_CHANGED + (NOTIFICATION_ID_OFFSET * 2):

                case EVENT_PRECISE_CALL_STATE_CHANGED + (NOTIFICATION_ID_OFFSET * 3):

                    if (VDBG) Log.d(LOG_TAG, " handleMessage (EVENT_PRECISE_CALL_STATE_CHANGED)");

                    index = (msg.what - EVENT_PRECISE_CALL_STATE_CHANGED) / NOTIFICATION_ID_OFFSET;

                    mPreciseCallStateRegistrantsGemini[index].notifyRegistrants((AsyncResult) msg.obj);

                    mPreciseCallStateRegistrants.notifyRegistrants((AsyncResult) msg.obj);

                    handle3GSwitchLock();

 

                    try {

                          checkIfExistsFollowingAction();

                    } catch (Exception e) {

                          //Do nothing.

                    }

                    break;      

 

InCallScreen类主要负责通话界面的绘制和通话过程的控制,它也有一个handler,当CallManager通知呼叫状态改变时,它会处理自己注册的事件

                case PHONE_STATE_CHANGED:

                     onPhoneStateChanged((AsyncResult) msg.obj);      

 

 

2)向下注册获取服务

在registerPhone里,提供初始注册服务时,也调用了registerSinglePhoneStates向下注册服务,方法是调用phone提供的注册方法。例如        phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED + eventDifference*simId, null);就是用来向phone注册呼叫状态改变的。phoneGSMPhone的实例引用,registerForPreciseCallStateChanged是Phonebase的方法,GSMPhone继承自PhonebaseregisterForPreciseCallStateChanged的实现是将CallManagerhandlerEVENT_PRECISE_CALL_STATE_CHANGED封装起来,存放在在PhonebasemPreciseCallStateRegistrants这个RegistrantList里面。

    public void registerForPreciseCallStateChanged(Handler h, int what, Object obj) {

        checkCorrectThread(h);

 

        mPreciseCallStateRegistrants.addUnique(h, what, obj);

    }    

当呼叫状态改变时,需要将这个信息通知到上层应用,GSMPhonenotifyPreciseCallStateChanged会被GsmCallTracker.java调用,

phone.notifyPreciseCallStateChanged();      

GSMPhone是继承自Phonebase的,所以最终是PhonebasenotifyPreciseCallStateChangedP被调用,由于之前注册过RegistrantList,所以使用RegistrantList的方法notifyRegistrants通知到其客户端CallManager

    protected void notifyPreciseCallStateChangedP() {

        AsyncResult ar = new AsyncResult(null, this, null);

        mPreciseCallStateRegistrants.notifyRegistrants(ar);

    }      

CallManagerhandler会进行事件的处理。

 

1.2 CallNotifier

1.2.1 说明

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清理、若有未接电话须在状态栏显示等。

1.3 PhoneInterfaceManager

1.3.1 说明

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

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

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

 

1.4 NotificationMgr

1.4.1 说明

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对象并调用其初始化函数时检查提示的。

 

1.5 InCallScreen

1.5.1 说明

它是手机正在通话时的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来响应处理。

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值