Handling Airplane Mode with HTTP Requests

1.5k views Asked by At

My app has quite a few occasions where it makes HTTP post requests. I discovered during testing that if the user is in airplane mode when this request is made, the app crashes. So, in an effort to handle this situation elegantly, I call a function that tests whether the phone is in airplane mode immediately prior to making the AsyncTask call. If the function returns true, I don't make the AsyncTask call.

The test itself works correctly. The user is notified that they must turn off airplane mode and them come back and try again. The problem is that after airplane mode is turned off, and the AsyncTask proceeds, my HTTP post crashes the app. If airplane mode was never on in the first place, everything runs smoothly.

I can't figure out what to do. Is there a better way to test for airplane mode in the first place? Or is there something else that I need to do after blocking the AsyncTask to restore the system state such that the http request will succeed.

Any advice is appreciated. Here is some code to hopefully make this more clear. If there is additional code that will help, please let me know. Thanks!

public class LoginActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);

            context = this;

            btnLogin.setOnClickListener(new View.OnClickListener() {
                public void onClick(View view) {
                UserFunctions userFunction = new UserFunctions(context);
                if (userFunction.isAirplaneModeOn(context)) {
                    userFunction.warnAboutAirplaneMode(context);
                    return;
                }

                new Login().execute();  

            });
    }

    class Login extends AsyncTask<String, String, String> {

        private JSONParser jsonParser = new JSONParser();
        private JSONObject json;

        @Override
        protected String doInBackground(String... args) {

            String URL = context.getResources().getString(R.string.dbURL) + context.getResources().getString(R.string.attemptLogin_php);

                    //this next line is the one that crashes - iff the user was
                    // previously in airplane mode. If there weren't ever in airplane
                    // mode, this runs just fine
            json = jsonParser.makeHttpRequest(URL, params);

                    ...

    }
}

Here is the UserFunctions class:

    public class UserFunctions {

            @SuppressLint( "NewApi" )
            @SuppressWarnings("deprecation")
            public boolean isAirplaneModeOn(Context context) {

                if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
                    return Settings.Global.getInt(context.getContentResolver(),
                       Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
                } else {
                    return Settings.System.getInt(context.getContentResolver(),
                           Settings.System.AIRPLANE_MODE_ON, 0) != 0;
                }

            }

            public void warnAboutAirplaneMode(Context context) {

                AlertDialog.Builder builder = new AlertDialog.Builder(context)
                    .setTitle("Airplane Mode Is On")
                    .setIcon(R.raw.airplane_mode)
                    .setCancelable(false)
                    .setMessage("Your phone is in airplane mode. Please turn this off then try again.")

                    .setNeutralButton("OK", new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int id) {
                            dialog.cancel();
                        }

                    });

                AlertDialog alert = builder.create();
                alert.show();   
            }

        }
1

There are 1 answers

4
tyczj On BEST ANSWER

Checking for Airplane mode alone is probably not a good idea because you can have wifi on in airplane mode. But there are probably a few possible answers to this but what I do is register a BroadcastReceiver that listens for network state changes with the following permission

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

my receiver looks like this in the manifest

<receiver android:name="com.example.NetworkReceiver" >
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
    </receiver>

when that gets fired I check to see if there is network connection or not and keep an app wide boolean in SharedPreferences and I check that boolean every time right before I make a HTTP call.

I have found instances where this could still not completely solve your problem such as SocketTimeOutExceptions where the user has bad reception and the connection times out.