在InCallUI显示VoWifi到VoLTE切换提示的实现

来源:互联网 发布:js date utc gmt 编辑:程序博客网 时间:2024/05/29 09:01

需求描述:

在使用wifi网络通话的过程中,网络从Wifi切换到LTE(handover),要在通话界面上显示适当的信息提醒用户(Android L)。
期望效果图:


图1:期望效果图

需求分析

要做这个功能需要做以下两点

1.需要底层上报状态

底层会不会监听这个状态的变化并发出通知?这个问题我们并不知道答案。
两个方案同时进行去寻找答案:
1.从代码或者log中找信息;
2.提单给高通,问高通是否已经实现了对应接口。

2.上层编写代码实现显示效果

因为之前我比较详细的看过CallButton的工作流程,布局的代码,在这部分修改是不太合适的。
之前我们曾经观察到一个现象:在打紧急号码的时候,通话界面上会显示出call back number(显示条件这里不说),或许我们可以利用已经存在的控件来显示我们想要的信息。

具体实现

按照之前的需求分析,实现的地方也要分成两个部分。
底层的部分参考现有的log可以在vendor下的ims中实现。
上册的部分当然是在incallui实现了。

1.Ims 底层状态上报

然后在查阅代码的时候我发现了下面的代码块

boolean modeWifi = actSt[i].networkMode == ImsQmiIF.RADIO_TECH_WIFI ||                                actSt[i].networkMode == ImsQmiIF.RADIO_TECH_IWLAN;boolean modeLte = actSt[i].networkMode == ImsQmiIF.RADIO_TECH_ANY ||                                actSt[i].networkMode == ImsQmiIF.RADIO_TECH_LTE;

但是在实际测试中发现,这个networkMode跟通话中实际使用的网络并不是统一的,曾经在一份log中看到,modeLte总头到尾都是true,但是实际上开始是通过wifi打的电话。
另外在connectivityService.java(印象里是这个)的log中可以看到网络模式的切换,但是那里并不关心call的状态,也不好在那里修改。
之后给高通提的case得到回复,在高通释放的Android M版本中已经实现了这个功能。
在对比Android M的代码(AS内的对比工具)时发现M版本的ims下新增了一个strings.xml,这里恰好就有一行:

<string name="handover_from_wifi_to_lte">Switching to VoLTE for better Voice quality</string>

然后搜索其被使用的地方得到:

if (response.mType == ImsQmiIF.COMPLETE_SUCCESS &&        (response.mSrcTech == ImsQmiIF.RADIO_TECH_WIFI ||        response.mSrcTech == ImsQmiIF.RADIO_TECH_IWLAN) &&        response.mTargetTech == ImsQmiIF.RADIO_TECH_LTE) {    Toast.makeText(mContext, mContext.getResources().            getString(R.string.handover_from_wifi_to_lte), Toast.LENGTH_LONG).show();}

理解起来比较简单,就是在满足这种条件时弹出一个Toas提示。如果我们想要把这个状态的变化通知到上层的话,可以选择送广播的方式(貌似高通更喜欢以参数的形式逐层向上传递):

if (response.mType == ImsQmiIF.COMPLETE_SUCCESS &&        (response.mSrcTech == ImsQmiIF.RADIO_TECH_WIFI ||        response.mSrcTech == ImsQmiIF.RADIO_TECH_IWLAN) &&        response.mTargetTech == ImsQmiIF.RADIO_TECH_LTE) {    Intent intent = new Intent(VoWIFI_to_VoLTE);    Log.i(LOG_TAG, "ckt_network send broadcast VoWIFI_to_VoLTE");    mContext.sendBroadcast(intent);    Toast.makeText(mContext, mContext.getResources().            getString(R.string.handover_from_wifi_to_lte), Toast.LENGTH_LONG).show();}

到这里底层把状态上报的问题基本上是解决了。剩下的就是上层收到广播做相应的处理显示。

2.InCallUI 上层显示效果实现

查看CallCardFragment的代码,找到显示call back number的控件,mInCallMessageLabel。
现有的CallButton中有一套通话录音功能的逻辑,底层发出录音广播(也是vendor),在CallCardFragment上收到广播显示。这个跟我们想要实现的逻辑基本上是一样的。所以实现思路就很简单了,两步:接受广播->显示信息。

具体一点我们可以稍微改写一下现有的recorderStateReceiver,让它也接收网络状态变化的广播,然后去调用一个我们专门写的setIncallMessage()方法,把信息显示在inCallScreen上。

这里可能有人要问,为什么要专门写一个方法呢?直接mInCallMessageLabel.setText()不就可以了么?
确实也可以,不过考虑到之前的客户要求,很可能在之后,客户还有其他类似的需求,所以这里我们专门写一个方法方便以后扩展,也方便自定义多种显示样式。
之后考虑到信息显示后不会像Toast那样自动消失,所以还要在写点代码实现reset message,也方便下次显示其他message。
得到简易流程如下:

图2: 简易流程

关键代码:
接收广播

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {        @Override        public void onReceive(Context context, Intent intent) {            if (VoWIFI_TO_VoLTE.equals(intent.getAction())) {                Log.i(this, "ckt_network receive network change");                handler.sendEmptyMessage(SWITCH_TO_VoLTE);                handler.sendEmptyMessageDelayed(RESET_INCALL_MESSAGE, 2000);//延时2S发送重置message的消息            }        }    };

handler处理消息,调用setInCallMessage()设置消息显示或者重置

    private Handler handler = new Handler() {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case SWITCH_TO_VoLTE:                    setInCallMessage(SWITCH_TO_VoLTE);                    break;                case RESET_INCALL_MESSAGE:                    setInCallMessage(RESET_INCALL_MESSAGE);                    break;            }        }    };

实现显示效果

    /**     * set necessary message to display on in-call screen     *     * @param inCallMessage message to dislay     */    public void setInCallMessage(int inCallMessage) {        if (mInCallMessageLabel == null) {            return;        }        String text = "";        switch (inCallMessage) {            case SWITCH_TO_VoLTE:                //设置显示效果,包括内容,字体,颜色,大小等                break;            case RESET_INCALL_MESSAGE:                //恢复默认值                break;            default:                break;        }        if (!TextUtils.isEmpty(text)) {            mInCallMessageLabel.setVisibility(View.VISIBLE);        }    }

实现效果图(用mute事件模拟):


图3:实现效果图
经过在IMS网络下的测试,也是能得到上图效果的。


08/23更新
我居然忘了发这篇博客!
另,这篇博客完成的时候还是在L上实现的功能。后来我到印度新孟买出差后发现,升级到AndroidM 之后,这条信息显示的时间只有200ms左右,调查发现,代码升级后原先修改的代码需要再调整,这里就不说了。

0 0
原创粉丝点击