什么是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.
获取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 >= 23){
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 (0 for false, 1 for true)我们知道它的返回是1 或 0。
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 ? 1 : 0;
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 = 0;
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;
}
好,先到这了,祝大家新年快乐!