Android 4.2 InCallScreen UI浅析

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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参数的设置等等,在这些过程中我们需要关注以下三个方法:
  1. initInCallScreen:初始化CallCard以及InCallTouchUi等截面;
  2. registerForPhoneStates:注册关于Phone状态改变的监听事件,这也就是为什么Phone状态改变之后InCallScreen能够收到变化消息的原因,这一点我们在来电流程中也有提及;
  3. 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();
 
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值