如何在 Android 上检测飞行模式?

Posted

技术标签:

【中文标题】如何在 Android 上检测飞行模式?【英文标题】:How can one detect airplane mode on Android? 【发布时间】:2011-05-18 04:19:49 【问题描述】:

我的应用程序中有代码可检测 Wi-Fi 是否处于活动状态。如果启用了飞行模式,该代码将触发 RuntimeException。无论如何,我想在此模式下显示单独的错误消息。如何可靠地检测 android 设备是否处于飞行模式?

【问题讨论】:

根据您的检查方式,请注意可以同时启用飞行模式和 Wi-Fi:heresthethingblog.com/2013/08/28/… 【参考方案1】:
/**
* Gets the state of Airplane Mode.
* 
* @param context
* @return true if enabled.
*/
private static boolean isAirplaneModeOn(Context context) 

   return Settings.System.getInt(context.getContentResolver(),
           Settings.Global.AIRPLANE_MODE_ON, 0) != 0;


【讨论】:

在 Jelly Bean 4.2 中,此设置已移至 Settings.Global 当我调用它以响应意图 android.intent.action.AIRPLANE_MODE 时,这提供了不确定的结果,因为模式更改需要时间才能完成。如果你想这样做,请检查Intent.ACTION_AIRPLANE_MODE_CHANGED 提示:!= 0 返回 false(飞行模式关闭),== 0 返回 true(飞行模式打开) 和启用网络数据一样吗?如果没有 - 是否有其他设置状态可以知道用户是否启用了数据? 编译器说 AIRPLANE_MODE_ON 已弃用【参考方案2】:

通过扩展 Alex 的答案以包括 SDK 版本检查,我们有:

/**
 * Gets the state of Airplane Mode.
 * 
 * @param context
 * @return true if enabled.
 */
@SuppressWarnings("deprecation")
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
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;
           

【讨论】:

Eclipse 不会编译这个,除非你在方法前添加@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 我无法在 Intellij 中完成这项工作。我迎合 2.2,所以我有 minSdk=8,因此有“Android 2.2”作为项目 SDK”。然而,这意味着“Settings.Global”代码是红色的,不会编译。我没有不想将 4.2 设置为项目 SDK,因为我可能会错过 2.2 中没有的东西......这让我发疯,这里的最佳做法是什么?有什么想法吗? 更改你的 targetSDK【参考方案3】:

如果您不想轮询飞行模式是否处于活动状态,您可以为 SERVICE_STATE Intent 注册一个 BroadcastReceiver 并对其做出反应。

在您的 ApplicationManifest(Android 8.0 之前)中:

<receiver android:enabled="true" android:name=".ConnectivityReceiver">
    <intent-filter>
        <action android:name="android.intent.action.AIRPLANE_MODE"/>
    </intent-filter>
</receiver>

或以编程方式(所有 Android 版本):

IntentFilter intentFilter = new IntentFilter("android.intent.action.AIRPLANE_MODE");

BroadcastReceiver receiver = new BroadcastReceiver() 
      @Override
      public void onReceive(Context context, Intent intent) 
            Log.d("AirplaneMode", "Service state changed");
      
;

context.registerReceiver(receiver, intentFilter);

正如其他解决方案中所述,您可以在接收器收到通知时轮询飞行模式并抛出异常。

【讨论】:

注意:由于还有其他的SERVICE_STATE通知,所以在收到SERVICE_STATE通知之前需要检查并存储飞行模式的状态,然后在收到服务状态通知时检查它的状态,然后比较两者——以了解飞行模式是否真的改变了。 mpstx: 或使用:IntentFilter intentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); / &lt;action android:name="android.intent.action.AIRPLANE_MODE" /&gt; 对于这个解决方案,您需要以下权限: 使用 Intent.ACTION_AIRPLANE_MODE_CHANGED 同样要获取飞行模式是打开还是关闭,我们可以在我们收到的意图中使用布尔额外值。 boolean isPlaneModeOn = intent.getBooleanExtra("state", false); 布尔值 isPlaneModeOn 如果用户打开了平面模式,则为 true,如果已关闭,则为 false【参考方案4】:

注册飞行模式BroadcastReceiver(@saxos 回答)我认为立即从Intent Extras 获取飞行模式设置的状态很有意义,以避免调用Settings.Global 或@ 987654324@:

@Override
public void onReceive(Context context, Intent intent) 

    boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
    if(isAirplaneModeOn)

       // handle Airplane Mode on
     else 
       // handle Airplane Mode off
    

【讨论】:

这是检索实际飞行模式状态的最有效方式。这应该得到投票并成为新的接受答案。 +1 用于阅读有关此“状态”意图的文档。我测试过,它工作正常。【参考方案5】:

来自here:

 public static boolean isAirplaneModeOn(Context context)
   return Settings.System.getInt(
               context.getContentResolver(),
               Settings.System.AIRPLANE_MODE_ON, 
               0) != 0;
 

【讨论】:

“Settings.System.AIRPLANE_MODE_ON”是否与启用网络数据相同?如果没有 - 是否有其他设置状态可以知道用户是否启用了数据? —— ***.com/questions/12806709/…@ransh【参考方案6】:

为了摆脱折旧的抱怨(针对 API17+ 并且不太关心向后兼容性时),必须与 Settings.Global.AIRPLANE_MODE_ON 进行比较:

/** 
 * @param Context context
 * @return boolean
**/
private static boolean isAirplaneModeOn(Context context) 
   return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0);

考虑较低的 API 时:

/** 
 * @param Context context
 * @return boolean
**/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@SuppressWarnings( "deprecation" )
private static boolean isAirplaneModeOn(Context context) 
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
        /* API 17 and above */
        return Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
     else 
        /* below */
        return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0;
    

【讨论】:

Settings.Global.AIRPLANE_MODE_ON 这仅适用于 API 17+,仅供参考 添加了向后兼容性 - 虽然它现在与上面的示例几乎相同。 “Settings.System.AIRPLANE_MODE_ON”是否与启用网络数据相同?如果没有 - 是否有其他设置状态可以知道用户是否启用了数据?【参考方案7】:

在奥利奥请不要使用飞行模式broadCastReceiver。这是一个隐含的意图。它已被删除。这是当前的exceptions list。它目前不在列表中,因此应该无法接收数据。认为它死了。

正如上面另一个用户所说,使用以下代码:

 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
    @SuppressWarnings( "deprecation" )
    public static boolean isAirplaneModeOn(Context context) 
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1)
        /* API 17 and above */
            return Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
         else 
        /* below */
            return Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0;
        
    

【讨论】:

【参考方案8】:

静态广播接收器

清单代码:

<receiver android:name=".airplanemodecheck" android:enabled="true"
 android:exported="true">
  <intent-filter>
     <action android:name="android.intent.action.AIRPLANE_MODE"></action>
  </intent-filter>
</receiver>

Java 代码:广播接收器 java 文件

if(Settings.System.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0)== 0)

  Toast.makeText(context, "AIRPLANE MODE Off", Toast.LENGTH_SHORT).show();

else

 Toast.makeText(context, "AIRPLANE MODE On", Toast.LENGTH_SHORT).show();

动态广播接收器

Java 代码:活动 java 文件

在应用程序打开时注册广播接收器,如果您仅在您的活动打开时执行操作,例如在您访问互联网时检查飞行模式是打开还是关闭等,则无需在清单中添加代码

airplanemodecheck reciver;

@Override
protected void onResume() 
   super.onResume();
   IntentFilter intentFilter = new IntentFilter();
   intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
   reciver = new airplanemodecheck();
   registerReceiver(reciver, intentFilter);


@Override
protected void onStop() 
  super.onStop();
  unregisterReceiver(reciver);

Java 代码:广播接收器 java 文件

if(Settings.System.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0)== 0)

  Toast.makeText(context, "AIRPLANE MODE Off", Toast.LENGTH_SHORT).show();

else

 Toast.makeText(context, "AIRPLANE MODE On", Toast.LENGTH_SHORT).show();

【讨论】:

【参考方案9】:

从 API 级别 - 17

/**
     * Gets the state of Airplane Mode.
     *
     * @param context
     * @return true if enabled.
     */
    private static boolean isAirplaneModeOn(Context context) 

        return Settings.Global.getInt(context.getContentResolver(),
                Settings.Global.AIRPLANE_MODE_ON, 0) != 0;

    

【讨论】:

【参考方案10】:

我写的这门课可能会有所帮助。它不会直接返回布尔值来告诉您飞行模式是启用还是禁用,但它会在飞行模式从一种更改为另一种时通知您。

public abstract class AirplaneModeReceiver extends BroadcastReceiver 

    private Context context;

    /**
     * Initialize tihe reciever with a Context object.
     * @param context
     */
    public AirplaneModeReceiver(Context context) 
        this.context = context;
    

    /**
     * Receiver for airplane mode status updates.
     *
     * @param context
     * @param intent
     */
    @Override
    public void onReceive(Context context, Intent intent) 
        if(Settings.System.getInt(
                context.getContentResolver(),
                Settings.Global.AIRPLANE_MODE_ON, 0
        ) == 0) 
            airplaneModeChanged(false);
         else 
            airplaneModeChanged(true);
        
    

    /**
     * Used to register the airplane mode reciever.
     */
    public void register() 
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        context.registerReceiver(this, intentFilter);
    

    /**
     * Used to unregister the airplane mode reciever.
     */
    public void unregister() 
        context.unregisterReceiver(this);
    

    /**
     * Called when airplane mode is changed.
     *
     * @param enabled
     */
    public abstract void airplaneModeChanged(boolean enabled);


用法

// Create an AirplaneModeReceiver
AirplaneModeReceiver airplaneModeReceiver;

@Override
protected void onResume()

    super.onResume();

    // Initialize the AirplaneModeReceiver in your onResume function
    // passing it a context and overriding the callback function
    airplaneModeReceiver = new AirplaneModeReceiver(this) 
        @Override
        public void airplaneModeChanged(boolean enabled) 
            Log.i(
                "AirplaneModeReceiver",
                "Airplane mode changed to: " + 
                ((active) ? "ACTIVE" : "NOT ACTIVE")
            );
        
    ;

    // Register the AirplaneModeReceiver
    airplaneModeReceiver.register();


@Override
protected void onStop()

    super.onStop();

    // Unregister the AirplaneModeReceiver
    if (airplaneModeReceiver != null)
        airplaneModeReceiver.unregister();

【讨论】:

【参考方案11】:

这是唯一对我有用的东西(API 27):

IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
this.registerReceiver(br, filter);

br 是您的广播接收器。我相信随着最近权限的变化,现在需要ConnectivityManager.CONNECTIVITY_ACTIONIntent.ACTION_AIRPLANE_MODE_CHANGED

【讨论】:

【参考方案12】:

自 Jelly Bean(内部版本代码 17)以来,此字段已移至全局设置。 因此,为了获得最佳的兼容性和稳健性,我们必须同时处理这两种情况。 以下示例是用 Kotlin 编写的。

fun isInAirplane(context: Context): Boolean 
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) 
        Settings.Global.getInt(
            context.contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0
        )
     else 
        Settings.System.getInt(
            context.contentResolver, Settings.System.AIRPLANE_MODE_ON, 0
        )
     != 0

注意:如果您不支持 Jelly Bean 之前的版本,您可以省略 if 子句。您在引用 Settings.System.AIRPLANE_MODE_ON 时获得的值与您在 Global 下找到的值相同。*

    /**
     * @deprecated Use @link android.provider.Settings.Global#AIRPLANE_MODE_ON instead
     */
    @Deprecated
    public static final String AIRPLANE_MODE_ON = Global.AIRPLANE_MODE_ON;

这是之前代码的上面的果冻豆版本。

fun isInAirplane(context: Context): Boolean 
    return Settings.Global.getInt(
        context.contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0
    ) != 0

【讨论】:

【参考方案13】:

您可以检查互联网是否已打开

public class ConnectionDetector 

private Context _context;

public ConnectionDetector(Context context)
    this._context = context;


public boolean isConnectingToInternet()
    ConnectivityManager connectivity = (ConnectivityManager) _context.getSystemService(Context.CONNECTIVITY_SERVICE);
      if (connectivity != null)
      
          NetworkInfo[] info = connectivity.getAllNetworkInfo();
          if (info != null)
              for (int i = 0; i < info.length; i++)
                  if (info[i].getState() == NetworkInfo.State.CONNECTED)
                  
                      return true;
                  

      
      return false;

【讨论】:

上述方法的问题是没有考虑到其他应用修改连接的情况。例如,如果用户打开了飞行模式,但另一个具有适当权限的应用程序启用了收音机。此外,让我们假设收音机打开但没有连接......无论如何,上面的答案并没有告诉我们飞行模式是打开还是关闭,只要设备有连接。两种不同的东西。

以上是关于如何在 Android 上检测飞行模式?的主要内容,如果未能解决你的问题,请参考以下文章

手机处于飞行模式时如何检测 iCloud 用户?

如何知道广播接收器中飞行模式是打开还是关闭?

android 4.2 系统以后的飞行模式

关闭飞行模式后,为啥 Android 应用程序会通过 Activity 和 Fragment 生命周期方法

android 代码控制飞行模式开关 支持4.2以上 root

android 代码控制飞行模式开关 支持4.2以上 root