Android VoLTE 视频通话是否可用状态读取与监听

  • 初始化状态读取

    TelephonyManager.isImsRegistered()
    

    在远程服务端中对应的接口实际上为:

    frameworks\opt\telephony\src\java\com\android\internal\telephony\PhoneBase.java
    
     /**
         * Get IMS Registration Status
         */
        @Override
        public boolean isImsRegistered() {
            ImsPhone imsPhone = mImsPhone;
            boolean isImsRegistered = false;
            if (imsPhone != null) {
                isImsRegistered = imsPhone.isImsRegistered();
            } else {
                ServiceStateTracker sst = getServiceStateTracker();
                if (sst != null) {
                    isImsRegistered = sst.isImsRegistered();
                }
            }
            Rlog.d(LOG_TAG, "isImsRegistered =" + isImsRegistered);
            return isImsRegistered;
        }
    

    在ImsPhone中

    frameworks\opt\telephony\src\java\com\android\internal\telephony\imsphone
    
    public boolean isImsRegistered() {
        return mImsRegistered;
    }
    
    public void setImsRegistered(boolean value) {
        mImsRegistered = value;
    }
    
    /* SPRD: Add for VoLTE. @{ */
    public boolean isVideoEnabled(){
        return isVideoCallEnabled();
    }
    

该接口存在一定问题,在某些时候,会始终返回false状态

目前可依照展讯6.0平台系统拨号应用方案实现

  • 展讯6.0实现

    //使用TelephonyManager.listen(mPhoneStateListener,PhoneStateListener.LISTEN_VOLTE_STATE)注册一个PhoneState的监听器
    //当注册监听器时,接口会理解回调onVoLteServiceStateChanged方法,返回当前volte状态
    
    class DialVoLteStateListener extends PhoneStateListener {
    
        @Override
        public void onVoLteServiceStateChanged(VoLteServiceState stateInfo) {
    
            if (stateInfo.getSrvccState() == VoLteServiceState.IMS_REG_STATE_REGISTERED) {
                LogUtil.d("VOLTE_SERVICE_STATE_IMS_REGISTERED");
            } else if (stateInfo.getSrvccState() == VoLteServiceState.IMS_REG_STATE_NOT_EGISTERED) {
                LogUtil.d("VOLTE_SERVICE_STATE_IMS_UNREGISTERED");
            }
    }
    

    }

    • 当注册监听器时,立即回调,返回当前volte状态
    • 当volte状态变化时回调,对变化之后的状态给出通知

需注意,该监听方案不稳定,可能存在延迟、丢失等情况,只在进程启动时注册监听,会出现遗漏volte状态变化通知的情况,所以按照底版本方案,依靠该接口注册后立即返回状态的特点,在界面进入前台时注册,读取当前volte状态,当界面离开前台时反注册掉,依此反复。

  • 展讯7.0实现

    private class DialVoLteStateListener extends IImsRegisterListener.Stub {
    
        @Override
        public void imsRegisterStateChange(boolean isRegistered) {
            LogUtil.d("imsRegisterStateChange: "+isRegistered);
        }
    }
    

与展讯6.0实现思想相同,只是接口变化了

展讯7.0平台上,特别增加了一个aidl接口IImsRegisterListener,其中只定义了一个回调函数,imsRegisterStateChange。该接口相比6.0更加稳定可靠,只是注册和反注册该监听需要反射调用。 
接口:

  IImsServiceEx imsService = ImsManagerEx.getIImsServiceEx();
  imsService.registerforImsRegisterStateChanged(mPhoneStateListener);
private void reflect(String methodName,DialVoLteStateListener listener) {     
    Class clazz = null;
    Object result = null;
    try {
        clazz = Class.forName("com.android.ims.internal.ImsManagerEx");
        if(clazz != null){
            Method method = clazz.getMethod("getIImsServiceEx", null);
            if(method != null){
                result = method.invoke(obj, null);
            }
        }
    } catch (ClassNotFoundException e) {
        printError(e);
    }

    if (result != null) {
        Class clazz = result.getClass();
        try {
            Method method = clazz.getMethod(methodName, new Class[]{IImsRegisterListener.class});
            if (null != method) {
                method.invoke(obj, new Object[]{listener});
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

//注册监听器
reflect("registerforImsRegisterStateChanged",mPhoneStateListener);

//反注册监听器
reflect("unregisterforImsRegisterStateChanged",mPhoneStateListener);

MTK平台volte视频通话

MTK平台6.0和7.0的方案可通用

  • 主动读取当前volte状态

    TelephonyManager.isImsRegistered()
    

与展讯相同,该方法依然存在问题,目前可有两种解决方案

1.修改Phone代码

    packages\services\Telephony\src\com\android\phone\PhoneInterfaceManager.java

    public boolean isImsRegistered() {
        //Solve inserted on Sim2 and reg ims always return false  >>>start
        int phoneId = TelephonyUtilsEx.getMainPhoneId();
        if(SubscriptionManager.isValidPhoneId(phoneId)) {
            Phone phone = PhoneFactory.getPhone(phoneId);
            if(null != phone) {
                return phone.isImsRegistered();
            }
        }
        //>>>end  此间为增加代码
        return mPhone.isImsRegistered();
    }

2.反射MTK平台特有接口读取

调用ITelephonyEx的isImsRegistered(int subId)

boolean isImsRegistered() {
    boolean flags = false;
    //获取主数据sim卡的 subId
    int subId = SubscriptionManager.getDefaultDataSubId();
    //注:7.0 接口变化为SubscriptionManager.getDefaultDataSubscriptionId()

    IBinder phoneEx = ServiceManager.getService("phoneEx");
    if (phoneEx != null) {
        Object telephonyEx = ReflectUtil.invokeStatic("com.mediatek.internal.telephony.ITelephonyEx$Stub", "asInterface",
                new Class[] { IBinder.class }, new Object[] { phoneEx });
        if (telephonyEx != null) {
            Object r = ReflectUtil.invoke(telephonyEx,"isImsRegistered",new Class[]{int.class},new Object[]{subId});
            if (r instanceof Boolean) {
                flags = (Boolean) r;
                LogUtil.d("ITelephonyEx isImsRegistered :" + flags);
            }
        }
    }
    return flags;
}
  • 动态监听volte状态变化

可以通过广播获取volte状态变化的通知,但是该广播不是StickyBroadcast,注册时无法获取当前状态,需上述接口辅助

//注册广播
IntentFilter filter = new IntentFilter();
filter.addAction("com.android.ims.IMS_STATE_CHANGED");
mContext.registerReceiver(mVoLTEStateBroadcast, filter);

class VoLTEStateBroadcast extends BroadcastReceiver{
    private static final String REG_STATE = "android:regState";
    private static final String REG_PHONE_ID = "android:phone_id";

    @Override
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();
        LogUtil.d("VoLTEStateBroadcast action:"+action);
        if ("com.android.ims.IMS_STATE_CHANGED".equals(action)) {
            int regState = intent.getIntExtra(REG_STATE, -1);
            int phoneId = intent.getIntExtra(REG_PHONE_ID, -1 );

            boolean enabled = (regState == ServiceState.STATE_IN_SERVICE);
        }            
    }
}

高通平台volte视频通话

高通平台6.0和7.0的实现方案亦可通用

高通平台也通过注册广播实现,并且该广播是StickyBroadcast,注册立即返回当前volte状态

//注册粘性广播
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.SERVICE_STATE");
mContext.registerReceiver(mServiceStateListener, intentFilter);

class ServiceStateListener extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if ("android.intent.action.SERVICE_STATE".equals(action)){
            int state = intent.getIntExtra("imsRadioTechnology",-1);
            boolean register = (state == ServiceState.RIL_RADIO_TECHNOLOGY_LTE) 
            //最终结果
            boolean result = isVideoRegister() && register;
        }
    }
}

//需要判断当前卡是否有视频通话的能力
public boolean isVideoRegister(Context context) {
    TelecomManager telecommMgr = (TelecomManager)context.getSystemService(Context.TELECOM_SERVICE);

    if (telecommMgr == null) {
        return false;
    }

    List accountHandles = telecommMgr.getCallCapablePhoneAccounts();
    for (PhoneAccountHandle accountHandle : accountHandles) {
        PhoneAccount account = telecommMgr.getPhoneAccount(accountHandle);
        if (account != null) {
            if(account.hasCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING)) {
                return true;
            }
        }
    }
    LogUtil.d("isVideoRegister : false");
    return false;
}

在读取volte状态之前,首先要判断当前手机系统版本是否支持volte视频通话,这是一个属性配置:

  ImsManager.isVtEnabledByPlatform(mContext)

另,以上API的调用,需注意请求相关权限:

  
  

你可能感兴趣的:(android)