在安卓手机上切换飞行模式

32

我犯了什么错误?它没法工作。

public void airplane() {
    boolean isEnabled = Settings.System.getInt(this.getApplicationContext().getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) == 1;
    Settings.System.putInt(context.getContentResolver(),Settings.System.AIRPLANE_MODE_ON,isEnabled ? 0 : 1);
    //Settings.System.putInt(this.getApplicationContext().getContentResolver(),Settings.System.AIRPLANE_MODE_ON,isEnabled ? 0 : 1);
    Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
}

1
可能是重复的问题,参考如何将AIRPLANE_MODE_ON设置为“True”或ON? - Peter Mortensen
这个回答解决了你的问题吗?如何将AIRPLANE_MODE_ON设置为“True”或ON? - miken32
10个回答

47

这个答案包含必要的代码实现。同时确保你拥有WRITE_SETTINGS权限。

这段代码源自控制飞行模式

// read the airplane mode setting
boolean isEnabled = Settings.System.getInt(
      getContentResolver(), 
      Settings.System.AIRPLANE_MODE_ON, 0) == 1;

// toggle airplane mode
Settings.System.putInt(
      getContentResolver(),
      Settings.System.AIRPLANE_MODE_ON, isEnabled ? 0 : 1);

// Post an intent to reload
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", !isEnabled);
sendBroadcast(intent);

21
从Android 4.2及以上版本开始,这已不再可能。 - Tommie
32
是的,它无法在4.2.x版本上运行,因为现在需要一个WRITE_SECURE_SETTINGS权限,该权限仅供系统应用程序使用。谷歌越来越让我们这些小家伙感到疏远了。 - jmroyalty
3
请注意,自Android 4.2(Jelly Bean主要版本1)起,切换飞行模式已不再可行。这是因为谷歌采用了一种简单/方便的解决方案(对他们自己而言)来解决Android中的缺陷,而不是重新审视其安全模型。有办法绕过此问题 - 例如拥有Root设备和/或将应用程序安装为系统应用程序 - 以允许飞行模式正常工作。不幸的是,这不是“家庭用户”知道如何做或想做的事情... - ChuongPham
5
在API 17中,Settings.System.AIRPLANE_MODE_ON已经不建议使用。请改用Settings.Global.AIRPLANE_MODE_ON。 - Nguyen Minh Binh
1
在Android 5.0中,我尝试发送广播(ACTION_AIRPLANE_MODE_CHANGED),但是遇到了安全异常。我已经添加了所有必需的权限并且我的应用程序是系统应用程序。 - yasinkafadar
显示剩余6条评论

16

适用于所有API版本。

  • API < 17上自动切换
  • API >= 17的用户操作打开Airplane模式的默认活动

无需Root权限,无需系统级权限!


AndroidManifest.xml中添加权限:

<!--airplane mode-->
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>

那么:

@SuppressWarnings("deprecation")
    private void initAirplanemodeBtn() {
        airplanemodeButton = (ToggleButton) findViewById(R.id.airplanemode_btn);
        airplanemodeButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

                if (android.os.Build.VERSION.SDK_INT < 17) {
                    try {
                        // read the airplane mode setting
                        boolean isEnabled = Settings.System.getInt(
                                getContentResolver(),
                                Settings.System.AIRPLANE_MODE_ON, 0) == 1;

                        // toggle airplane mode
                        Settings.System.putInt(
                                getContentResolver(),
                                Settings.System.AIRPLANE_MODE_ON, isEnabled ? 0 : 1);

                        // Post an intent to reload
                        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
                        intent.putExtra("state", !isEnabled);
                        sendBroadcast(intent);
                    } catch (ActivityNotFoundException e) {
                        Log.e(TAG, e.getMessage());
                    }
                } else {
                    try {
                        Intent intent = new Intent(android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS);
                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(intent);
                    } catch (ActivityNotFoundException e) {
                        try {
                            Intent intent = new Intent("android.settings.WIRELESS_SETTINGS");
                            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                        } catch (ActivityNotFoundException ex) {
                            Toast.makeText(buttonView.getContext(), R.string.not_able_set_airplane, Toast.LENGTH_SHORT).show();
                        }
                    }
                }

            }
        });
    }

1
+1 我认为这是谷歌希望我们采取的方式:将用户发送到正确的设置页面,让他们自己进行设置 - 如果他们不是太无知的话 ;)不过最好还是提供一个提示(比如一个对话框,其中包含解释该怎么做的文本以及“确定”和“暂不”按钮)。 - FrankKrumnow
@FrankKrumnow 给定的权限适用于非系统应用程序吗?我收到了警告。 - Vivek Pratap Singh
从 Android 8 开始,写入设置的权限本身是一个(可撤销的)运行时权限。这意味着你不能立即获得它,但用户可以进行设置。如何检查和将用户发送到哪里的答案在此处:stackoverflow - FrankKrumnow

13
以下内容适用于已经进行了root的设备。
您可以使用以下命令在命令行中切换飞行模式的开/关状态:
ON:
settings put global airplane_mode_on 1
am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true

OFF:
settings put global airplane_mode_on 0
am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false

此功能适用于 Android 4.4.2 及以上版本。


在这里使用4.2.2版本。非常有帮助! - D. Gibbs
@siesta 正在处理4.3版本。 - CelinHC
在 Android 5 上工作。@Michal,你是以 root 用户身份执行吗?从 Android 4.2 开始,它需要以 root 用户身份执行。 - A.J.

12

注意:有用户 NarendraR 指出此方法在最新版本中已不再适用。

我认为“Settings.System.AIRPLANE_MODE_ON”已经过时,我正在使用:

public class AirplaneModeService {
    public boolean run(Context context) {
        boolean isEnabled = isAirplaneModeOn(context);
        // Toggle airplane mode.
        setSettings(context, isEnabled?1:0);
        // Post an intent to reload.
        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        intent.putExtra("state", !isEnabled);
        context.sendBroadcast(intent);
        return true;
    }
    public static boolean isAirplaneModeOn(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            return Settings.System.getInt(context.getContentResolver(), 
                    Settings.System.AIRPLANE_MODE_ON, 0) != 0;          
        } else {
            return Settings.Global.getInt(context.getContentResolver(), 
                    Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
        }       
    }
    public static void setSettings(Context context, int value) {
        if (Build.VERSION.SDK_INT < 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);
        }       
    }
}

我希望这能帮助到某人。


4
“setSettings”函数在Jelly Bean系统无法使用:因为“Settings.Global”是只读的。 - eggyal
1
这需要android.permission.WRITE_SECURE_SETTINGS权限,这个权限不可用于第三方应用程序。请参阅此[链接](https://dev59.com/L2cs5IYBdhLWcg3wMxNF) - Marky0
谢谢@NarendraR,我刚刚更新了帖子并加入了你的评论。 - cesaregb

5
如@eggyal所提到的,从4.2版本开始,无法切换飞行模式。
但是我们可以使用以下方法控制每个无线服务:
Wifi可以使用WifiService 〜 getSystemService(Context.WIFI_SERVICE)来控制。 Bluetooth可以使用BluetoothAdapter-getSystemService(Context.BLUETOOTH_SERVICE)来控制。
经过一些研究,我发现使用Java Reflection仍然可以控制Android收音机(Wifi,Network,Bluetooth),因为飞行模式基本上会切换蓝牙,Wifi和网络的状态。
因此,通过控制收音机,您实际上可以创建自己的飞行模式。
警告:使用Reflection可能会在某些设备上失败(取决于类的制造商实现)。
以下示例代码切换移动网络:
private void setMobileRadioEnabled(boolean enabled) {
    try {
        final ConnectivityManager conman = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        final Class conmanClass = Class.forName(conman.getClass().getName());
        final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
        iConnectivityManagerField.setAccessible(true);
        final Object iConnectivityManager = iConnectivityManagerField.get(conman);
        final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
        final Method setRadio = iConnectivityManagerClass.getDeclaredMethod("setRadio", Integer.TYPE ,  Boolean.TYPE);
        setRadio.setAccessible(true);
        for (NetworkInfo networkInfo : conman.getAllNetworkInfo()) {
            if(isNetworkTypeMobile(networkInfo.getType())) {
                setRadio.invoke(iConnectivityManager, networkInfo.getType(), enabled);
            }
        }
    } catch (Exception e) {
        Log.e(TAG, "Opss...", e);
    }
}

public static boolean isNetworkTypeMobile(int networkType) {
    switch (networkType) {
        case ConnectivityManager.TYPE_MOBILE:
        case ConnectivityManager.TYPE_MOBILE_MMS:
        case ConnectivityManager.TYPE_MOBILE_SUPL:
        case ConnectivityManager.TYPE_MOBILE_DUN:
        case ConnectivityManager.TYPE_MOBILE_HIPRI:
        case 10:
        case 11:
        case 12:
        case 14:
            return true;
        default:
            return false;
    }
}

2
无法在Naugat上工作。抛出异常NoSuchMethodException setRadio。 - Ramapati Maurya

4
在每个设置之前,请使用android.provider,如下所示:
public class MainActivity extends Activity implements OnClickListener {

    Button air;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        air = (Button) findViewById(R.id.button1);
        air.setOnClickListener(this);
    }

    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub
        // read the airplane mode setting
        boolean isEnabled = android.provider.Settings.System.getInt(
              getContentResolver(), 
              android.provider.Settings.System.AIRPLANE_MODE_ON, 0) == 1;

        // toggle airplane mode
        android.provider.Settings.System.putInt(
              getContentResolver(),
              android.provider.Settings.System.AIRPLANE_MODE_ON, isEnabled ? 0 : 1);

        // Post an intent to reload
        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        intent.putExtra("state", !isEnabled);
        sendBroadcast(intent);

    }

}

你已经在新版本的Android上测试过了吗?需要哪个权限才能实现这个功能? - Vivek Pratap Singh

4
在安卓5.0(棒棒糖)之后,您可以使用下面的方法。但是这是隐藏的API,您的应用程序需要系统级权限。
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL"/>

ConnectivityManager mgr =  (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
        mgr.setAirplaneMode(true); 

仅适用于KitKat+版本。 - sean loyola
在Android Studio中显示错误:“mgr.setAirplaneMode(true);”,表示不存在这样的方法。 - Sanjeev
这个方法只能被系统应用程序使用,如果您的应用程序已安装,则必须通过反射实现。ConnectivityManager mgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); try { if (mgr != null) { Method airPlane = ConnMgr.getClass().getDeclaredMethod("setAirplaneMode", boolean.class); if (null != aiPlane) { airPlane.invoke(mgr, !isEnabled); } } } catch - Navas pk

3
注意,在Android 4.2 APIs中记录的(强调添加):
新全局设置
通过添加Settings.Global,系统设置已更新以支持多个用户。这些设置类似于Settings.Secure设置,因为它们是只读的,但应用于设备上所有用户空间。
一些现有的设置从Settings.SystemSettings.Secure移至此处。如果您的应用程序当前正在更改先前在Settings.System中定义的设置(例如AIRPLANE_MODE_ON),则如果那些设置被移至Settings.Global,则您应该预期这样做将不再适用于运行Android 4.2或更高版本的设备。您可以继续读取Settings.Global中的设置,但是因为这些设置不再被认为是应用程序可安全更改的内容,尝试更改这些设置将会失败并且在运行Android 4.2或更高版本的设备上运行您的应用程序时,系统将向系统日志中写入警告

1
这个对我有效。
public static boolean isAirplaneModeOn() {
    return Settings.System.getInt(mContext.getContentResolver(),
            Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
}

public static void setAirPlaneMode(boolean airplaneMode) {
    Logger.d(LOG_TAG + "setAirPlaneMode airplaneMode: " + airplaneMode) ;
    int state = airplaneMode ? 1 : 0;
    Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
                             state);
    Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
    intent.putExtra("state", state);
    mContext.sendBroadcast(intent);
}

但是你需要系统权限

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

你是如何让它工作的?你是如何将你的应用变成系统应用的? - Codes12
我曾经为一家OEM工作,那是系统镜像中预装的应用程序。 - Deepu

-1
我发现了一个针对17+的解决方法,如果你想关闭互联网,这个方法可以起作用。
权限
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />

方法

@SuppressWarnings({ "unchecked", "rawtypes" })
private void setMobileDataEnabled(boolean state) {
    try {
        final ConnectivityManager conman = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        final Class conmanClass = Class.forName(conman.getClass().getName());
        final Field iConnectivityManagerField = conmanClass.getDeclaredField("mService");
        iConnectivityManagerField.setAccessible(true);
        final Object iConnectivityManager = iConnectivityManagerField.get(conman);
        final Class iConnectivityManagerClass = Class.forName(iConnectivityManager.getClass().getName());
        final Method setMobileDataEnabledMethod = iConnectivityManagerClass.getDeclaredMethod("setMobileDataEnabled", Boolean.TYPE);
        setMobileDataEnabledMethod.setAccessible(true);
        setMobileDataEnabledMethod.invoke(iConnectivityManager, state);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接