来电接听InCallScreen界面源码分析

本文深入分析了Android 5.1系统中来电接听界面InCallScreen的源码,主要涉及GlowPadWrapper.java、GlowPadView.java以及布局文件的加载。通过源码解析,展示了如何从call_card_content.xml到InCallActivity.java的调用流程,探讨了来电界面在解锁前后不同处理的方式,并介绍了如何定义和操作系统全局变量。
摘要由CSDN通过智能技术生成

本篇小文对来电接听InCallScreen界面进行源码分析,该文基于android5.1进行源码分析,由于使用了厂商提供的源码版本,和google官方发布的版本会有所差异。

1. 效果图
  我们先来看样机的实际运行效果图
这里写图片描述

我们通过图片定位到:
packages/apps/InCallUI/res/values/array.xml
下面我们来看下array.xml中的代码
    <array name="incoming_call_widget_audio_with_sms_targets">
        <item>@drawable/ic_lockscreen_answer</item>
        <!--item>@drawable/ic_lockscreen_text</item-->
        <item>@null</item>
        <item>@drawable/ic_lockscreen_decline</item>
        <item>@null</item>"
    </array>
 我们看到,在这个定义了接听/拒接/短信这三个功能。
 通过“incoming_call_widget_audio_with_sms_targets”来调用这个array,继续看这个调用的地方
 packages/apps/InCallUI/res/layout/answer_fragment.xml
 我们来看下这个文件的具体调用:
<com.android.incallui.GlowPadWrapper
       ...............
        dc:targetDrawables="@array/incoming_call_widget_audio_with_sms_targets"
        dc:handleDrawable="@drawable/ic_incall_audio_handle"
        dc:outerRingDrawable="@drawable/ic_lockscreen_outerring"
        ......................

我们看到,incoming_call_widget_audio_with_sms_targets在这里进行了调用,并调用了GlowPadWrapper该函数来进行相关处理,由于对GlowPadWrapper函数不熟悉,下面我们先来介绍一下这个函数的基本情况。
最中间圆圈的按钮:  dc:handleDrawable=”@drawable/ic_incall_audio_handle”
最外面圆圈的颜色设置: dc:outerRingDrawable=”@drawable/ic_lockscreen_outerring”

2. GlowPadWrapper.java
我们看到在GlowPadWrapper.java是继承GlowPadView而来的,在这个函数里对相关的空间进行了处理,我们来看一下:

@Override
    public void onTrigger(View v, int target) {  
        Log.d(this, "onTrigger()");
        final int resId = getResourceIdForTarget(target);
        switch (resId) {
            case R.drawable.ic_lockscreen_answer:        
                mAnswerListener.onAnswer(VideoProfile.VideoState.AUDIO_ONLY, getContext());                                                                               
                mTargetTriggered = true;
                break;                  
            case R.drawable.ic_lockscreen_decline:       
                mAnswerListener.onDecline();             
                mTargetTriggered = true;
                break;
            case R.drawable.ic_lockscreen_text:          
                mAnswerListener.onText();                
                mTargetTriggered = true;
                //SPRD bug 424648 {@
                TelecomManager telecomManager = SprdUtils.getTelecommService(getContext());                                                                               
                telecomManager.silenceRinger();          
                //@}
                break;
            case R.drawable.ic_lockscreen_answer_video://SPRD: add for can't accept video call                                                                            
            case R.drawable.ic_videocam:
                mAnswerListener.onAnswer(VideoProfile.VideoState.BIDIRECTIONAL, getContext());                                                                            
                mTargetTriggered = true;
                break;
            case R.drawable.ic_toolbar_video_off:        
                InCallPresenter.getInstance().declineUpgradeRequest(getContext());                                                                                        
                mTargetTriggered = true;
                break;
            default:
                // Code should never reach here.         
                Log.e(this, "Trigger detected on unhandled resource. Skipping.");                                                                                         
        }
    } 

在这里对
ic_lockscreen_answer 、
ic_lockscreen_decline
ic_lockscreen_text
对接听,拒接,短信进行了处理,这里我们先放一下,我们看下GlowPadView.java这个函数的情况。
public class GlowPadView extends View {}
我们看到,其实也是extends了view,所以在这里我们看到很熟悉的一些函数
protected void onDraw(Canvas canvas){};
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {};

相信大家对view的常用的函数都已经比较熟悉了,我们就不在这里更进一步的分析,
到这里我们知道:
GlowPadView.java进行布局;
GlowPadWrapper.java对按钮进行监测;

3.0 LayoutInflater.inflate
在往下看之前我们先来看一下inflate这个是起什么作用的,在
sw/frameworks/base/core/java/android/view/LayoutInflater.java
—->
public View inflate(int resource, ViewGroup root) {}
public View inflate(XmlPullParser parser, ViewGroup root){}
public View inflate(int resource, ViewGroup root, boolean attachToRoot) {}
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {}
在这几个定义的注释开头,我们都能看到这样一句话,
Inflate a new view hierarchy from the specified XML node.
实例化一个xml到制定的layout里和setContent有一些区别:
setContentView()一旦调用, layout就会立刻显示UI;而inflate只会把Layout形成一个以view类实现成的对象,有需要时再用setContentView(view)显示出来。一般在activity中通过setContentView()将界面显示出来,但是如果在非activity中如何对控件布局设置操作了,这就需要LayoutInflater动态加载。
public View inflate(int Resourece,ViewGroup root)
作用:填充一个新的视图层次结构从指定的XML资源文件中
reSource:View的layout的ID
root: 生成的层次结构的根视图
return 填充的层次结构的根视图。如果参数root提供了,那么root就是根视图;否则填充的XML文件的根就是根视图。

public View inflate(int resource, ViewGroup root, boolean attachToRoot)方法三个参数的含义
resource:需要加载布局文件的id,意思是需要将这个布局文件中加载到Activity中来操作。
root:需要附加到resource资源文件的根控件,什么意思呢,就是inflate()会返回一个View对象,如果第三个 参
数attachToRoot为true,就将这个root作为根对象返回,否则仅仅将这个root对象的LayoutParams属性附
加到resource对象的根布局对象上,也就是布局文件resource的最外层的View上,比如是一个
LinearLayout或者其它的Layout对象。
attachToRoot:是否将root附加到布局文件的根视图上.

4.0 packages/apps/InCallUI/res/layout/call_card_content.xml

来电界面的布局xml文件是在call_card_content.xml进行,在这里没有
绿色的来电信心,号码/归属地/等等 ….: primary_call_info_container
下方4个按键的接听/拒接/短信 : @+id/answerFragment

我们知道,在布局过程中,有静态布局和动态布局这两种方式,
setContentView()
LayoutInflater.inflate()
这两种方式,这两种方式的主要特点在上面已经介绍过。
既然我们知道,那么我们就看看这是是怎么进行调用的,通过全局搜索我们可以看到
packages/apps/InCallUI/src/com/android/incallui/CallCardFragment.java
中对call_card_content进行了引用,

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        mDensity = getResources().getDisplayMetrics().density;
        mTranslationOffset =
            getResources().getDimensionPixelSize(R.dimen.call_card_anim_translate_y_offset);
        **return inflater.inflate(R.layout.**call_card_content**, container, false)**;
    }

在这里我们看到,onCreateView动态加载了call_card_content.xml这个文件,在这里进行了初始化。
那么我们如果往上再看的话,又是哪里来调用这个CallCardFragment.java的呢,
我们来搜下“CallCardFragment”这个字串,我们可以看到,
比较有价值的地方是这个:
packages/apps/InCallUI/res/layout/incall_screen.xml:

我们这里采用的是从下往上逆向查找的方法来进行源码分析,这样的方法更直接直观的去寻找我们需要的东西,如果我们顺着源码的执行顺序来查找,那么我们一个个的去看每个文件,这样浪费的时间就比较多了。
到了这里,我们就对哪里调用的incall_screen.xml这个文件比较熟悉了,我们回到了
InCallActivity.java

5.0 当前界面来电的不同处理
我们知道,5.1的来电界面解锁前是直接进入到来电界面的,但是如果是在解锁后的某一个界面中,这个时候来电,就会现在状态栏提示有来电,点击之后才进入到来电界面。那么我们怎么来查找这个判断是否在解锁前或者后的界面在哪里呢?我们应该从哪里入手比较合理呢?

5.1 查找incallactivity的调用
我们知道,启动一个activity的方法,一般会在AndroidManifest.XML里面有相关的属性能进行查找,比如
Intent / resevice …..
还有一个就是我们在代码中动态的启动,那么既然是这样,启动一个intent我们知道,必须对包名和类型进行定义。那么我们先来看下incallactivity.java在AndroidManifest.xml中的定义是怎样的

<activity android:name="com.android.incallui.InCallActivity"
                  android:theme="@style/Theme.InCallScreen"
                  android:label="@string/phoneAppLabel"
                  android:excludeFromRecents="true"
                  android:launchMode="singleInstance"
                  android:configChanges="keyboardHidden"
                  android:exported="false"
                  android:screenOrientation="nosensor" >
        </activity>

在这里,我们能很清楚的看到,这里没有intent/action/receiver/service……..
等等这下关键得词,既然在这里我们得不到启动该activity的有用信息,那么我们就换个思路去找找看,我们从动态启动该activity去想想看到底这个是怎么启动的。我们知道5.1之后一个intent的启动必须要同时对包名和类名进行注册,但是,包名不是唯一的,但是类名一定是唯一的,所以,我们先从类名入手,我们在InCallUi这个模块下去搜索用到“InCallActivity”这个类名的地方,我们来看搜索的结果
**xxxxx@build-server-C:xxxxx greprInCallActivity.classpackages/app

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值