初始化状态读取
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状态,当界面离开前台时反注册掉,依此反复。
展讯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平台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状态变化的通知,但是该广播不是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);
}
}
}
高通平台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的调用,需注意请求相关权限: