0

After reading through a bunch of stale guides and stackoverflows, I was able to usb adb to install an apk as a system app in /system/priv-app that successfully toggles AirplaneMode in Android oreo:

// method in Activity, called via click listener on a Button
private void setMobileRadioEnabled_Option1(boolean enabled) {
    android.content.Context context = this;
    int value = enabled ? 0 : 1;

    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
        Settings.System.putInt(
                context.getContentResolver(),
                Settings.System.AIRPLANE_MODE_ON, value);
    } else {
        Settings.Global.putInt(
                context.getContentResolver(),
                Settings.Global.AIRPLANE_MODE_ON, value);
    }
}

Permissions in AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>

Standard release build in AndroidStudio with custom signing keys, installed via:

adb root
adb remount
adb push app-release.apk /system/priv-app
adb shell chmod 644 /system/priv-app/app-release.apk
adb reboot

On reboot, the app is installed and I can run it without issue.

I check in the notifications drawer / status bar what things are like to start with:

Notifications Drawer screenshot - begin

I then click my Button in the app, and check what happens:

enter image description here

As you can see, airplane mode seems to be successfully enabled based on the status of the airplane mode icon. But wifi and cellular data continue to be connected, and the status bar doesn't replace the text "Android" with "Airplane mode". In this state, if I hop over to chrome, I can clearly load websites I've never visited before. So airplane mode doesn't in fact seem to be actually on.

What am I doing wrong? I expect turning on airplane mode via System.putInt() to have the same effect as tapping the airplane mode tile in the status bar. No exceptions or useful error information spitting to logcat when I execute the code.

jdowdell
  • 1,409
  • 11
  • 23

2 Answers2

0

Checking this answer it seems that you need to send a broadcast to notify that you changed the airplane mode.

The broadcast should be:

Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", < current value of the airplane mode >);
sendBroadcast(intent);
jonathanrz
  • 3,714
  • 6
  • 30
  • 49
  • 1
    I had seen comments in other stackoverflows that ACTION_AIRPLANE_MODE_CHANGED was "no longer necessary", but https://www.intertech.com/Blog/android-airplane-mode/ corroborates the claim that the intent still needs to be sent or the behaviour I was seeing ensues. – jdowdell Jan 05 '19 at 22:48
0

Alternatively to jonathanrz's additional code above, which I believe is closer to canonical, I found that the following worked in place of the Settings.System.putInt() code and did not require sending the intent (or adding the permission(s) necessary to send it), at least on Oreo. I created it by merging a few answers and offhand comments from other posts, particularly an answer sketch hidden in a comment by "Navas pk" on Toggle airplane mode in Android:

private void setMobileRadioEnabled_Option2(boolean enabled) {
    try {
        final ConnectivityManager mConnectivityManager = (ConnectivityManager) getSystemService(android.content.Context.CONNECTIVITY_SERVICE);
        final Class mClass = Class.forName(mConnectivityManager.getClass().getName());
        final Method setAirplaneMode = mClass.getDeclaredMethod("setAirplaneMode", Boolean.TYPE);
        setAirplaneMode.setAccessible(true);
        setAirplaneMode.invoke(mConnectivityManager, !enabled);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
jdowdell
  • 1,409
  • 11
  • 23