InCallScreen是什么
本文来自http://blog.youkuaiyun.com/yihongyuelan 转载请务必注明出处
本文以MTK平台Android 4.2为分析对象,MTK在原生的基础之上添加了许多自己的东西,因此个别地方跟原生代码以及QCOM的代码不同,请读者知悉。
在电话的呼出流程中,我们最后需要按下拨号键,才能将电话拨打出去,那么在按下拨号键之后,我们可以看到会弹出一个界面,显示拨号信息以及一些其他信息,这个界面就是我们的InCallScreen界面。当然,在来电的时候,弹出的界面依然是InCallScreen,在我们接通电话之后显示的那个界面仍然是InCallScreen。也就是说在通话过程中,我们一直可见并操作的那个界面就是InCallScreen。
图 1 InCallScreen界面
图1中所示就是InCallScreen不同情况下所展示的界面,分别是拨号、接通、来电三种情况下InCallScreen的现实情况。
InCallScreen结构分析
经过对比后可以发现,InCallScreen的拨号以及接通时,界面表现基本一致,而来电界面主要由于多了一个滑动接听的控件,从而导致界面不太一样。这里我们队InCallScreen的结构分析,采用接通之后的界面。如图2:
图 2 来电/去电接通后InCallScreen
InCallScreen布局分析
在InCallScreen.java中,我们可以在onCreate方法中找到InCallScreen加载的布局文件,即incall_screen.xml。在incall_screen.java文件中,我们可以看到有以下几个控件:
- call_card:显示当前通话的信息,比如来电号码,通话时间,移动运营商等等;
- incall_touch_ui:包括挂断按钮,显示DTMF拨号盘按钮,扬声器,静音,暂停,加入通话等几个按钮,就是通话界面下方的控制按钮;
- otaCallCardStub:CDMA模式下跟OTA相关的控件;
- manageConferencePanelStub:多方通话管理界面;
- vtInCallScreenStub:视屏通话控件;
- dtmf_twelve_key_dialer_stub:这个控件为DTMF控件,也就是我们点击
按钮之后,会弹出一个0~9以及*和#的拨号盘。
因为我们这里主要分析一般模式下的通话界面,因此暂不涉及到视屏通话。
总的来讲,在图2显示的界面中,我们直观能够看到的控件主要是:call_card以及incall_touch_ui这两块。当我们点击DTMF弹出按钮之后,会显示DTMF控件。当然在我们接入多方通话之后,就会看到多方通话的界面了。call_card通话信息展示
call_card控件,实际上显示的信息主要为通话联系人的相关信息,布局如下:
<?xml version="1.0" encoding="utf-8"?>
<com.android.phone.CallCard xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/call_info_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include android:id="@+id/primary_call_info"
layout="@layout/primary_call_info" />
<RelativeLayout android:id="@+id/largeAreaForSharing"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"/>
</com.android.phone.CallCard>
整个布局情况如下图:
图 3 CallCard界面
详细信息请参看primary_call_info.xml。
incall_touch_ui通话控制界面
这里所谓的控制主要包括了在通话界面底部的一些操作按钮,比如:挂断、显示/取消显示DTMF拨号界面、开启/关闭扬声器、启动/停止静音、开启/取消来电保持、添加多路通话等一些操作按钮。当然这里并没有将所有的控制按钮或者控制控件全部显示出来,比如当来电时,我们需要滑动接听电话,这里的滑动控件即MultiWaveView也属于incall_touch_ui.xml布局。布局如图4:
图 4 InCallTouchUi
InCallScreen初始化流程
通过查看Phone.apk的AndroidManifest.xml文件可以看到:
<activity android:name="InCallScreen"
android:theme="@style/Theme.InCallScreen" <!-- InCallScreen的Theme -->
android:label="@string/phoneIconLabel"
android:excludeFromRecents="true" <!-- 该Activity不会显示在最近使用列表中 -->
android:launchMode="singleInstance" <!-- 该Activity为单例模式 -->
android:screenOrientation="nosensor" <!-- 该Activity不会横竖屏切换,默认竖屏 -->
android:configChanges="keyboardHidden" <!-- 该Activity显示时隐藏keyboard -->
android:exported="false"> <!-- 该Activity不能被其它调用 -->
</activity>
查看@style/Theme.InCallScreen可以看到:
<style name="Theme.InCallScreen" parent="@android:style/Theme.Holo.NoActionBar">
<item name="android:windowBackground">@android:color/black</item>
<item name="*android:windowAnimationStyle">@style/InCallAnimationStyle</item>
</style>
可以看到InCallScreen的Theme中没有ActionBar,窗口背景为黑色,有过场动画。
因为InCallScreen为单例模式,第一次启动时调用onCreate而后面则会调用其onNewIntent方法。我们知道在onCreate方法中,一般都是对一些对象进行创建并初始化,以及设置布局文件等等。在InCallScreen的onCreate方法中,完成了PhoneApp对象的获取,以及Window参数的设置等等,在这些过程中我们需要关注以下三个方法:- initInCallScreen:初始化CallCard以及InCallTouchUi等截面;
- registerForPhoneStates:注册关于Phone状态改变的监听事件,这也就是为什么Phone状态改变之后InCallScreen能够收到变化消息的原因,这一点我们在来电流程中也有提及;
-
internalResolveIntent:该方法用于处理InCallScreen收到的Intent信息;
同样,在onNewIntent方法中主要调用了internalResolveIntent方法,因此下面我们着重分析以下几个方法在InCallScreen初始化的过程中作用。
initInCallScreen
该方法在InCallScreen的onCreate方法中调用,仅执行一次,代码如下:
private void initInCallScreen() {
... ...省略
// Initialize CallTime 通话时间初始化
mCallTime = new CallTime(this);
// Initialize the CallCard. 通话信息初始化
mCallCard = (CallCard) findViewById(R.id.callCard);
... ...省略
//第二路通话界面初始化
mSecCallInfo = (ViewStub) findViewById(R.id.secondary_call_info);
mCallCard.setInCallScreenInstance(this);
//通话录音按钮初始化
mVoiceRecorderIcon = (ImageView) findViewById(R.id.voiceRecorderIcon);
mVoiceRecorderIcon.setBackgroundResource(R.drawable.voice_record);
mVoiceRecorderIcon.setVisibility(View.INVISIBLE);
// Initialize the onscreen UI elements. 通话控制布局初始化
initInCallTouchUi();
... ...省略
// The DTMF Dialpad. DTMF拨号盘初始化
ViewStub stub = (ViewStub) findViewById(R.id.dtmf_twelve_key_dialer_stub);
mDialer = new DTMFTwelveKeyDialer(this, stub);
mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
// Initialize VTInCallScreen 视屏电话初始化
mVTInCallScreen = new VTInCallScreenProxy(this, mDialer);
}
可以看到这里全都是对InCallScreen上布局的一些初始化过程,我们继续看到其中对于InCallTouchUi初始化的代码:
private void initInCallTouchUi() {
... ...省略
mInCallTouchUi = (InCallTouchUi) findViewById(R.id.inCallTouchUi);
mInCallTouchUi.setInCallScreenInstance(this);
// 挂断并通话短信回复
mRespondViaSmsManager = new RespondViaSmsManager();
mRespondViaSmsManager.setInCallScreenInstance(this);
}
通过代码可以知道InCallScreen上的布局显示几乎都是在initInCallScreen方法中做的,如果我们修改了InCallScreen的布局那么我们应该在这里对修改后的布局进行初始化。
registerForPhoneStates
该方法在initInCallScreen方法之后,我们在来电流程中也有分析过该方法,代码如下:
private void registerForPhoneStates() {
if (!mRegisteredForPhoneStates) {
if (FeatureOption.MTK_GEMINI_SUPPORT) {
... ...省略
mCMGemini.registerForIncomingRingGemini(mHandler, PHONE_INCOMING_RING, null, PhoneConstants.GEMINI_SIM_1);
mCMGemini.registerForIncomingRingGemini(mHandler, PHONE_INCOMING_RING2, null, PhoneConstants.GEMINI_SIM_2);
... ...省略
} else {
... ...省略
mCM.registerForIncomingRing(mHandler, PHONE_INCOMING_RING, null);
... ...省略
}
这里所用的mHandler就是InCallScreen的mHandler,这里通过register****方法注册监听实际上为观察者模式的运用。
internalResolveIntent
该方法是InCallScreen用于处理Intent的方法,代码如下:
private void internalResolveIntent(Intent intent) {
... ...省略
if (action.equals(intent.ACTION_MAIN)) {
//是否显示Dialpad
if (intent.hasExtra(SHOW_DIALPAD_EXTRA)) {
boolean showDialpad = intent.getBooleanExtra(SHOW_DIALPAD_EXTRA, false);
if (VDBG) log("- internalResolveIntent: SHOW_DIALPAD_EXTRA: " + showDialpad);
mApp.inCallUiState.showDialpad = showDialpad;
final boolean hasActiveCall = mCM.hasActiveFgCall();

本文详细剖析了Android 4.2的InCallScreen界面,包括其结构、布局、初始化流程及控制流程。InCallScreen在接通、拨号和来电时有不同的展示,主要由call_card、incall_touch_ui等组件构成。文章深入探讨了各个组件的控制流程,如滑动接听、拨号盘显示/隐藏、扬声器、静音、呼叫保持和挂断等功能,并分析了CallCard如何显示通话信息。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



