展訊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" />