什么是VoLTE?
文笔不好,看官多担待.度娘介绍的很清楚了,不多说了,只是在5.1Lollipop开始系统就应经有关于VoLte的开关了,中文叫:增强型4G LTE模式.
How to enable HD Voice Calling on Android 5.1 Lollipop
Google has recently rolled out the highly-anticipated Android 5.1 Lollipop update with stability and performance fixes for a slew of Android devices, which also introduces a bunch of new features including native support for multiple SIM cards, device protection and High Definition Voice Calling on compatible phones and carriers.
HD Voice Calling is a useful addition to 4G LTE capable devices such as Nexus 6, wherein users can benefit with superior call quality via Enhanced 4G LTE Mode on carriers that support the service.
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0NXYFhGd192UvwVe0lmdhJ3ZvwFM38CXlZHbvN3cpR2Lc1TPB10QGtWUCpEMJ9CXsxWam9CXwADNvwVZ6l2c052bm9CXUJDT1wkNhVzLcRnbvZ2LcBTSU90dnR0Tqh2MkZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39DNxETNygDMyEDMyEDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
获取VoLTE开关状态
之前没关注过,也没注意早在Android 5.1版本就已经有了VoLte开关了。有很多介绍VoLte开关原理的,我这里的也是就不啰嗦了。
获取VoLte开关,在6.0上比较容易,6.0之后有一个类TelephonyManager,通过源码发现TelephonyManager.isVolteEnabled(),有关于VoLTE的开关状态,太好了,比较嗨皮,做版本过滤就好了,直接获取。
/**
* Returns the Status of Volte
*@hide
*/
public boolean isVolteEnabled() {
try {
return getITelephony().isVolteEnabled();
} catch (RemoteException ex) {
return false;
} catch (NullPointerException ex) {
return false;
}
}
6.0以上获取VoLte开关状态
if(Build.VERSION.SDK_INT >= ){
TelephonyManager telephonyManager = TheApp.GetTelephonyManager();
Class<? extends TelephonyManager> teleclass = telephonyManager.getClass();
Method method = teleclass.getDeclaredMethod("isVolteEnabled");
method.setAccessible(true);
isvoLte = (boolean) method.invoke(telephonyManager);
}
最近 发现5.1系统也有,SO… 那么看看怎么获取呢?
我在翻阅资料,查看源码时发现一个类
android.provider.Settings.Global
Global.java
/**
* Whether the Volte/VT is enable
* Type: int (0 for false, 1 for true)
* @hide
*/
public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled";
ENHANCED_4G_MODE_ENABLED 只是存储VoLTE开关状态的对应NAME而已,我们通过它可以读取手机当前VoLTE的开关状态,反射Global。
Class<?> GlobalClass = Global.getClass();
try {
Field field = GlobalClass.getDeclaredField("ENHANCED_4G_MODE_ENABLED");
field.setAccessible(true);
String volteStr = (String) field.get(Global);
}catch(Exception e){
}
那么如何获取呢? 根据ENHANCED_4G_MODE_ENABLED Type: int ( for false, for true)我们知道它的返回是 或 。
int VoLteState = android.provider.Settings.Global.getInt(getContentResolver(), volteStr);
VoLteState 则就是手机当前返回的VoLTE开关,在我测试手机Coolpad Y803-9 ,Android 5.1 它的名字叫做增强型4G LTE模式,当打开时手机状态栏或显示HD字样的图标。
要想设置VoLTE开关状态,除了你需要你的应用是系统APP(system App)之外,别忘了,在AndroidManifest.xml中添加相应的权限,才能修改。这里的修改是指,开发者自定义手机的VoLTE开关(只要手机支持)。我没有试过,不过一些代码可以验证一下,代码如下:
设置VoLTE开关 (未验证)
/**
* Whether the Volte/VT is enabled
* <p>
* Type: int (0 for false, 1 for true)
* "volte_vt_enabled"
*/
public static void SetVolteEnable(boolean enable){
int value = enable ? : ;
String volteStr = null ;
Global Global = new Global();
Class<?> GlobalClass = Global.getClass();
try {
Field field =GlobalClass.getDeclaredField("ENHANCED_4G_MODE_ENABLED");
field.setAccessible(true);
volteStr = (String) field.get(Global);
} catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException e) {
e.printStackTrace();
}
//如果是你的App是预制为系统App的,那么直接改变即可
if(checkSystemApp()){
android.provider.Settings.Global.putInt( TheApp.getContext().getContentResolver(),volteStr, value);
}
if (isNonTtyOrTtyOnVolteEnabled(TheApp.getContext())) {
try {
SubscriptionManager subManager (SubscriptionManager)TheApp.getContext()
.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
Class<? extends SubscriptionManager> sunClass = subManager.getClass();
Method method1 = sunClass.getDeclaredMethod("getDefaultVoicePhoneId");
method1.setAccessible(true);
int phoneid = (Integer) method1.invoke(subManager);
Class<?> clazz = (Class<?>)Class.forName("com.android.ims.ImsManager");
Constructor ct = clazz.getDeclaredConstructor(new Class[{Context.class,int.class});
ct.setAccessible(true);
Object obj = ct.newInstance(new Object[{TheApp.getContext(),phoneid});
//setAdvanced4GMode
Method method = clazz.getDeclaredMethod("setAdvanced4GMode", new Class[]{boolean.class});
method.setAccessible(true);
method.invoke(obj, enable);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
/**
* Indicates whether the call is non-TTY or if TTY - whether TTY on VoLTE is
* supported.
*/
public static boolean isNonTtyOrTtyOnVolteEnabled(Context context) {
if (getBooleanCarrierConfig(context, CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL)) {
return true;
}
String preferred = null ;
int mode = ;
try {
Secure secure = new Secure();
Class<?> secureClass = secure.getClass();
Field field = secureClass.getDeclaredField("PREFERRED_TTY_MODE");
field.setAccessible(true);
preferred = (String) field.get(secure);
TelecomManager telcom = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
Class telcomClass = telcom.getClass();
Field field1 = telcomClass.getDeclaredField("TTY_MODE_OFF");
field1.setAccessible(true);
mode = (Integer) field1.get(telcom);
} catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException e) {
e.printStackTrace();
}
// public static final String PREFERRED_TTY_MODE =
// "preferred_tty_mode";
return Settings.Secure.getInt(context.getContentResolver(),preferred, mode) == mode;
}
private static boolean getBooleanCarrierConfig(Context context, String key) {
CarrierConfigManager configManager = (CarrierConfigManager) context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
Class configManagerClass = configManager.getClass();
PersistableBundle b = null;
if (configManager != null) {
b = configManager.getConfig();
}
if (b != null) {
return b.getBoolean(key);
} else {
try {
Method method = configManagerClass.getDeclaredMethod("getDefaultConfig");
method.setAccessible(true);
PersistableBundle persistableBundle = (PersistableBundle) method.invoke(configManager);
return persistableBundle.getBoolean(key);
} catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return false;
}
好,先到这了,祝大家新年快乐!