Я наткнулся на способ решения этой проблемы с помощью команд отражения и системного вызова и решил сообщить об этом, даже если поток старый и есть некоторые предостережения:
- Требуется рут
- Взломанный и, возможно, специфичный для ПЗУ (протестирован на титане CM 12.1)
- Вероятно, не работает на всех версиях Android (протестировано на 5.1.1)
Большая часть кода заимствована у этого ответа ChuongPham .
.
Сначала нам нужно получить правильный код транзакции, получив значение объявленного поля класса ITelephony. Поскольку я подозреваю, что имя поля может немного отличаться в зависимости от платформы (для моего имени это поле «TRANSACTION_setPreferredNetworkType_96»), я предоставляю максимально гибкое решение:
private static String get3gTransactionCode(Context context) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
final TelephonyManager mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
final Class<?> mTelephonyClass = Class.forName(mTelephonyManager.getClass().getName());
final Method mTelephonyMethod = mTelephonyClass.getDeclaredMethod("getITelephony");
mTelephonyMethod.setAccessible(true);
final Object mTelephonyStub = mTelephonyMethod.invoke(mTelephonyManager);
final Class<?> mTelephonyStubClass = Class.forName(mTelephonyStub.getClass().getName());
final Class<?> mClass = mTelephonyStubClass.getDeclaringClass();
for (Field f:mClass.getDeclaredFields()) {
if (f.getName().contains("setPreferredNetworkType")) {
final Field field = mClass.getDeclaredField(f.getName());
field.setAccessible(true);
return String.valueOf(field.getInt(null));
}
}
throw new NoSuchFieldException();
}
Далее мы можем использовать код транзакции в системном вызове через su:
private static void setPreferredNetworkType(Context context, int preferredType) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {
String transactionCode = get3gTransactionCode(context);
String command = "service call phone " + transactionCode + " i32 " + preferredType;
executeCommandViaSu(context, "-c", command);
}
В моем случае я вызываю этот метод со вторым параметром, равным 1 для 2G и 10 для предпочтения 3G. Константы для разных типов сетей можно найти здесь .
Для удобства и полноты я также скопировал и вставил метод executeCommandViaSu из Ответ ChuongPham здесь:
private static void executeCommandViaSu(Context context, String option, String command) {
boolean success = false;
String su = "su";
for (int i=0; i < 3; i++) {
// Default "su" command executed successfully, then quit.
if (success) {
break;
}
// Else, execute other "su" commands.
if (i == 1) {
su = "/system/xbin/su";
} else if (i == 2) {
su = "/system/bin/su";
}
try {
// Execute command as "su".
Runtime.getRuntime().exec(new String[]{su, option, command});
} catch (IOException e) {
success = false;
// Oops! Cannot execute `su` for some reason.
// Log error here.
} finally {
success = true;
}
}
}