I have code in my application that detects if Wi-Fi is actively connected. That code triggers a RuntimeException if airplane mode is enabled. I would like to display a separate error message when i开发者_高级运维n this mode anyway. How can I reliably detect if an Android device is in airplane mode?
/**
* 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;
}
By extending Alex's answer to include SDK version checking we have:
/**
* 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;
}
}
And if you don't want to poll if the Airplane Mode is active or not, you can register a BroadcastReceiver for the SERVICE_STATE Intent and react on it.
Either in your ApplicationManifest (pre-Android 8.0):
<receiver android:enabled="true" android:name=".ConnectivityReceiver">
<intent-filter>
<action android:name="android.intent.action.AIRPLANE_MODE"/>
</intent-filter>
</receiver>
or programmatically (all Android versions):
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);
And as described in the other solutions, you can poll the airplane mode when your receiver was notified and throw your exception.
When registering the Airplane Mode BroadcastReceiver
(@saxos answer) I think it makes a lot of sense to get the state of the Airplane Mode setting right away from the Intent Extras
in order to avoid calling Settings.Global
or Settings.System
:
@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
}
}
From here :
public static boolean isAirplaneModeOn(Context context){
return Settings.System.getInt(
context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON,
0) != 0;
}
in order to get rid of the the depreciation complaint (when targeting API17+ and not caring too much about the backward compatibility), one has to compare with 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);
}
when considering lower 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;
}
}
In Oreo please do not use the airplane mode broadCastReceiver. it is an implicit intent. it has been removed. Here is the current exceptions list. its not currently on the list so should fail to receive data. Consider it dead.
as stated by another user above use the following code:
@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;
}
}
Static Broadcast Receiver
Manifest code:
<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 code: Broadcast Receiver java file
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();
}
OR
Dynamic Broadcast Receiver
Java code: Activity java file
Register broadcast receiver on application open no need to add code in manifest if you take an action only when your activity open like check airplane mode is on or off when you access the internet etc
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 code: Broadcast Receiver java file
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();
}
From API Level - 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;
}
Since Jelly Bean (Build Code 17), this field has been moved to Global settings. Thus, to achieve the best compatibility and robustness we have to take care of both cases. The following example is written in 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
}
Note: If you do not keep support for versions before Jelly Bean, you can omit the if clause.
The value that you get while referencingSettings.System.AIRPLANE_MODE_ON
, is the same as the one you find under Global.*
/**
* @deprecated Use {@link android.provider.Settings.Global#AIRPLANE_MODE_ON} instead
*/
@Deprecated
public static final String AIRPLANE_MODE_ON = Global.AIRPLANE_MODE_ON;
This is the above-jelly bean version of the previous code.
fun isInAirplane(context: Context): Boolean {
return Settings.Global.getInt(
context.contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0
) != 0
}
I wrote this class that might be helpful. It doesn't directly return a boolean to tell you if Airplane Mode is enabled or disabled, but it will notify you when Airplane Mode is changed from one to the other.
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);
}
Usage
// 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();
}
Here's the only thing what worked for me (API 27):
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
this.registerReceiver(br, filter);
Where br
is your BroadcastReceiver. I believe that with the recent changes in permission now both ConnectivityManager.CONNECTIVITY_ACTION
and Intent.ACTION_AIRPLANE_MODE_CHANGED
are needed.
You could check if the internet is on
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;
}
}
精彩评论