androidrootairplane-mode

How to turn on/off airplane mode, even on new Android versions (and even with root)?


Starting with Android 4.2 , turning on/off airplane mode isn't supported using normal APIs.

It should probably work when WRITE_SECURE_SETTINGS permission is granted, but that's only for system apps (as I've read).

What should be done in order to do it on devices with root?

Should a system app also require root in order to toggle airplane mode?


Solution

  • To toggle Airplane / Flight mode on and off on an Android rooted device (phone, tablet, note), you can do the following:

    private final String COMMAND_FLIGHT_MODE_1 = "settings put global airplane_mode_on";
    private final String COMMAND_FLIGHT_MODE_2 = "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state";
    
    @SuppressLint("NewApi")
    @SuppressWarnings("deprecation")
    public void setFlightMode(Context context) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
            // API 17 onwards.
            if (isRooted(context)) {            
                int enabled = isFlightModeEnabled(context) ? 0 : 1;
                // Set Airplane / Flight mode using su commands.
                String command = COMMAND_FLIGHT_MODE_1 + " " + enabled;
                executeCommandWithoutWait(context, "-c", command);
                command = COMMAND_FLIGHT_MODE_2 + " " + enabled;
                executeCommandWithoutWait(context, "-c", command);
            } else {                
                try {
                   // No root permission, just show Airplane / Flight mode setting screen.
                   Intent intent = new Intent(Settings.ACTION_AIRPLANE_MODE_SETTINGS);
                   intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                   context.startActivity(intent);
                } catch (ActivityNotFoundException e) {
                   Log.e(TAG, "Setting screen not found due to: " + e.fillInStackTrace());
                }
            }
        } else {
            // API 16 and earlier.
            boolean enabled = isFlightModeEnabled(context);
            Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, enabled ? 0 : 1);
            Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
            intent.putExtra("state", !enabled);
            context.sendBroadcast(intent);
        }
    

    To check whether Airplane / Flight mode is already on and off, do the following:

    @SuppressLint("NewApi")
    @SuppressWarnings("deprecation")
    private boolean isFlightModeEnabled(Context context) {
        boolean mode = false;
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
            // API 17 onwards 
            mode = Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
        } else {
            // API 16 and earlier.
            mode = Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) == 1;
        }
        return mode;
    }
    

    To execute su command, do the following:

    private void executeCommandWithoutWait(Context context, String option, String command) {
        boolean success = false;
        String su = "su";
        for (int i=0; i < 3; i++) {
            // "su" command executed successfully.
            if (success) {
                // Stop executing alternative su commands below. 
                break;
            }
            if (i == 1) {
                su = "/system/xbin/su";
            } else if (i == 2) {
                su = "/system/bin/su";
            }       
            try {
                // execute command
                Runtime.getRuntime().exec(new String[]{su, option, command});
            } catch (IOException e) {
                Log.e(TAG, "su command has failed due to: " + e.fillInStackTrace());
            }   
        }
    }
    

    Alternatively, if your app:

    1. Was signed with an Android framework's certificate; and
    2. Was installed to the /system/app/ directory; and
    3. Have the relevant tags declared in AndroidManifest.xml file (e.g. WRITE_SECURE_SETTINGS, etc).

    then you can just do this:

    Settings.Global.putInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, isEnabled ? 0 : 1);
    

    Since anything defined in Settings.Global can be read-write by system apps - even third-party app created as a system app.