###展讯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<PhoneAccountHandle> 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的调用,需注意请求相关权限:

<uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />