Airplane mode in Jelly Bean
android, android-4.2-jelly-bean, android-ndk, reflection
Solution
As of 4.2.2 you cannot toggle Airplane mode as it has been Read-only.
You have two options.
- Make your application a `System` application. i.e. Root a phone, push your APK to `/system/app` and install from there. This will enable you to toggle airplane mode.
- Use `Reflection` to get hold of the Android system function call that toggles Airplane mode.
You should get code samples on how to use Reflection to get exposure API's otherwise not exposed a the developer through the SDK.
Problem
I am trying to set the airplane mode in a Nexus 4 with Android 4.2.2. I know it is not possible since AIRPLANE_MODE_ON was moved to Global system settings and it is just a read option. Is there any other way to do something similar, I mean disable the radio? I can disable Bluetooth, wifi and Internet connection, but the phone call network is still active. Could be possible to create a library with the NDK to disable completely the network? EDIT: I have tried with `java.lang.reflect` making this method: ``` @SuppressLint("NewApi") @SuppressWarnings("rawtypes") private boolean putStringAirplaneMode() throws ClassNotFoundException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { ContentResolver resolver = context.getContentResolver(); String name = Settings.Global.AIRPLANE_MODE_ON; String value = (isEnabled() ? "1" : "0"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { Log.v("AirplaneBatterySaver", "Using reflection to change airplane mode"); // For JELLY_BEAN_MR1 use reflection. TODO test if works reflection Class SystemProperties = android.provider.Settings.Global.class; Class[] parameterTypes = new Class[3]; parameterTypes[0] = ContentResolver.class; parameterTypes[1] = String.class; parameterTypes[2] = String.class; @SuppressWarnings("unchecked") Method method = SystemProperties.getMethod("putString", parameterTypes); method.setAccessible(true); return (Boolean) method.invoke(new Object(), resolver, name, value); // return Settings.Global.putString(resolver, name, value); } else { Log.v("AirplaneBatterySaver", "Using Settings.System to change airplane mode"); return Settings.System.putString(resolver, name, value); } } ``` As you can see I replace the method `Settings.System.putString(resolver, name, value);` over `JELLY_BEAN_MR1` but, of course, I am getting a `SecurityException` because my app is not a system app. This is the trace: ``` Caused by: java.lang.SecurityException: Permission denial: writing to secure settings requires android.permission.WRITE_SECURE_SETTINGS at android.os.Parcel.readException(Parcel.java:1425) at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:185) at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:137) at android.content.ContentProviderProxy.call(ContentProviderNative.java:574) at android.provider.Settings$NameValueCache.putStringForUser(Settings.java:777) at android.provider.Settings$Global.putStringForUser(Settings.java:5421) at android.provider.Settings$Global.putString(Settings.java:5411) ``` If I use `<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>` I get the error `Permission is only granted to system apps`. I was checking the SDK sources (in the files from the trace) to try to find a way to set the airplane mode without this permission but I did not get any success.