To expand Muzikant Solution # 2, try solving the solution below on a shortened Android 5.0 device (since I don’t have one at the moment) and let me know if it works or doesn’t work.
To enable or disable mobile data, try:
Note. The variable mobile_data can be found in the Android API 21 source code in /android-sdk/sources/android-21/android/provider/Settings.java and is declared as:
public static final String MOBILE_DATA = "mobile_data";
So far, android.intent.action.ANY_DATA_STATE Intent can be found in the Android API 21 source code in /android-sdk/sources/android-21/com/android/internal/telephony/TelephonyIntents.java and is declared as:
public static final String ACTION_ANY_DATA_CONNECTION_STATE_CHANGED = "android.intent.action.ANY_DATA_STATE";
UPDATE 1 . If you do not want to implement the above Java codes in your Android application, you can run su commands using the shell (Linux) or the command line (Windows) as follows:
adb shell "su -c 'settings put global mobile_data 1; am broadcast -a android.intent.action.ANY_DATA_STATE --ez state 1'"
Note. adb is located in the /android-sdk/platform-tools/ directory. The settings command is only supported on Android 4.2 or later. The old version of Android will report a "sh: settings: not found" error.
UPDATE 2 . Another way to switch your mobile network to the Android 5+ root device is to use the undocumented shell service command. The following command can be executed via ADB to switch the mobile network:
// 1: Enable; 0: Disable adb shell "su -c 'service call phone 83 i32 1'"
Or simply:
Note 1 Transaction code 83 used in the service call phone command may change between versions of Android. Please check the com.android.internal.telephony.ITelephony field value TRANSACTION_setDataEnabled for your version of Android. Also, instead of hardcoding 83, you'd better use Reflection to get the value of the TRANSACTION_setDataEnabled field. Thus, it will work in all mobile brands running Android 5+ (if you do not know how to use Reflection to get the value of the TRANSACTION_setDataEnabled field, see the Solution from PhongLe below - save me from duplication here). It is important . Please note that transaction code TRANSACTION_setDataEnabled was only introduced in Android 5.0 and later. Running this transaction code in earlier versions of Android will do nothing, since the transaction code TRANSACTION_setDataEnabled does not exist.
Note 2 : adb is located in the /android-sdk/platform-tools/ directory. If you do not want to use ADB, execute the method using su in your application.
Note 3 See UPDATE 3 below.
UPDATE 3 . Many Android developers emailed me questions about turning on / off the mobile network for Android 5+, but instead of answering individual emails, I will send my answer here so that everyone can use it and adapt it for their Android applications.
First of all, let me clarify some misconceptions and misunderstandings regarding:
svc data enable svc data disable
The above methods will turn on / off background data input, not a subscription service, so the battery discharges a fair bit, because the subscription service - the Android system service - will still work in the background. For Android devices that support multiple SIM cards, this scenario is worse, since the subscription service constantly checks for available mobile networks (networks) for use with active SIM cards available on the Android device. Use this method at your own risk.
Now the correct way to disable the mobile network, including the corresponding subscription service, is using the SubscriptionManager class, introduced in API 22:
public static void setMobileNetworkfromLollipop(Context context) throws Exception { String command = null; int state = 0; try { // Get the current state of the mobile network. state = isMobileDataEnabledFromLollipop(context) ? 0 : 1; // Get the value of the "TRANSACTION_setDataEnabled" field. String transactionCode = getTransactionCode(context); // Android 5.1+ (API 22) and later. if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { SubscriptionManager mSubscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); // Loop through the subscription list ie SIM list. for (int i = 0; i < mSubscriptionManager.getActiveSubscriptionInfoCountMax(); i++) { if (transactionCode != null && transactionCode.length() > 0) { // Get the active subscription ID for a given SIM card. int subscriptionId = mSubscriptionManager.getActiveSubscriptionInfoList().get(i).getSubscriptionId(); // Execute the command via `su` to turn off // mobile network for a subscription service. command = "service call phone " + transactionCode + " i32 " + subscriptionId + " i32 " + state; executeCommandViaSu(context, "-c", command); } } } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) { // Android 5.0 (API 21) only. if (transactionCode != null && transactionCode.length() > 0) { // Execute the command via `su` to turn off mobile network. command = "service call phone " + transactionCode + " i32 " + state; executeCommandViaSu(context, "-c", command); } } } catch(Exception e) { // Oops! Something went wrong, so we throw the exception here. throw e; } }
To check if the mobile network is on or not:
private static boolean isMobileDataEnabledFromLollipop(Context context) { boolean state = false; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { state = Settings.Global.getInt(context.getContentResolver(), "mobile_data", 0) == 1; } return state; }
To get the value of the TRANSACTION_setDataEnabled field (borrowed from the PhongLe solution below):
private static String getTransactionCode(Context context) throws Exception { try { 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(); final Field field = mClass.getDeclaredField("TRANSACTION_setDataEnabled"); field.setAccessible(true); return String.valueOf(field.getInt(null)); } catch (Exception e) {
To execute a command via su :
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; } } }
We hope that this update will clear up any misconception, misunderstanding or question that you may have about enabling / disabling the mobile network on Android 5+ root devices.