Android VoLTE 視頻通話是否可用狀態讀取與監聽

展訊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" />
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章