12f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick/*
22f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * Copyright (C) 2012 The Android Open Source Project
32f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick *
42f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
52f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * in compliance with the License. You may obtain a copy of the License at
62f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick *
72f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * http://www.apache.org/licenses/LICENSE-2.0
82f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick *
92f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * Unless required by applicable law or agreed to in writing, software distributed under the License
102f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
112f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * or implied. See the License for the specific language governing permissions and limitations under
122f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * the License.
132f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick */
142f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
152f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickpackage com.example.android.networkusage;
162f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
172f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.app.Activity;
182f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.content.BroadcastReceiver;
192f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.content.Context;
202f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.content.Intent;
212f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.content.IntentFilter;
222f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.content.SharedPreferences;
232f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.net.ConnectivityManager;
242f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.net.NetworkInfo;
252f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.os.AsyncTask;
262f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.os.Bundle;
272f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.preference.PreferenceManager;
282f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.view.Menu;
292f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.view.MenuInflater;
302f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.view.MenuItem;
312f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.webkit.WebView;
322f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport android.widget.Toast;
332f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
342f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport com.example.android.networkusage.R;
352f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport com.example.android.networkusage.StackOverflowXmlParser.Entry;
362f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
372f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport org.xmlpull.v1.XmlPullParserException;
382f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
392f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport java.io.IOException;
402f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport java.io.InputStream;
412f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport java.net.HttpURLConnection;
422f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport java.net.URL;
432f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport java.text.DateFormat;
442f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport java.text.SimpleDateFormat;
452f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport java.util.Calendar;
462f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickimport java.util.List;
472f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
482f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
492f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick/**
502f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * Main Activity for the sample application.
512f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick *
522f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * This activity does the following:
532f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick *
542f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * o Presents a WebView screen to users. This WebView has a list of HTML links to the latest
552f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick *   questions tagged 'android' on stackoverflow.com.
562f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick *
572f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * o Parses the StackOverflow XML feed using XMLPullParser.
582f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick *
592f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * o Uses AsyncTask to download and process the XML feed.
602f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick *
612f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick * o Monitors preferences and the device's network connection to determine whether
622f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick *   to refresh the WebView content.
632f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick */
642f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormickpublic class NetworkActivity extends Activity {
652f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    public static final String WIFI = "Wi-Fi";
662f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    public static final String ANY = "Any";
672f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    private static final String URL =
682f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest";
692f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
702f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Whether there is a Wi-Fi connection.
712f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    private static boolean wifiConnected = false;
722f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Whether there is a mobile connection.
732f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    private static boolean mobileConnected = false;
742f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Whether the display should be refreshed.
752f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    public static boolean refreshDisplay = true;
762f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
772f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // The user's current network preference setting.
782f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    public static String sPref = null;
792f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
802f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // The BroadcastReceiver that tracks network connectivity changes.
812f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    private NetworkReceiver receiver = new NetworkReceiver();
822f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
832f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    @Override
842f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    public void onCreate(Bundle savedInstanceState) {
852f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        super.onCreate(savedInstanceState);
862f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
872f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // Register BroadcastReceiver to track connection changes.
882f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
892f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        receiver = new NetworkReceiver();
902f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        this.registerReceiver(receiver, filter);
912f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
922f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
932f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Refreshes the display if the network connection and the
942f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // pref settings allow it.
952f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    @Override
962f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    public void onStart() {
972f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        super.onStart();
982f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
992f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // Gets the user's network preference settings
1002f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
1012f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1022f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // Retrieves a string value for the preferences. The second parameter
1032f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // is the default value to use if a preference value is not found.
1042f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        sPref = sharedPrefs.getString("listPref", "Wi-Fi");
1052f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1062f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        updateConnectedFlags();
1072f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1082f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // Only loads the page if refreshDisplay is true. Otherwise, keeps previous
1092f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // display. For example, if the user has set "Wi-Fi only" in prefs and the
1102f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // device loses its Wi-Fi connection midway through the user using the app,
1112f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // you don't want to refresh the display--this would force the display of
1122f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // an error page instead of stackoverflow.com content.
1132f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        if (refreshDisplay) {
1142f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            loadPage();
1152f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        }
1162f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
1172f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1182f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    @Override
1192f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    public void onDestroy() {
1202f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        super.onDestroy();
1212f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        if (receiver != null) {
1222f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            this.unregisterReceiver(receiver);
1232f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        }
1242f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
1252f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1262f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Checks the network connection and sets the wifiConnected and mobileConnected
1272f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // variables accordingly.
1282f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    private void updateConnectedFlags() {
1292f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        ConnectivityManager connMgr =
1302f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
1312f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1322f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
1332f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        if (activeInfo != null && activeInfo.isConnected()) {
1342f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
1352f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;
1362f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        } else {
1372f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            wifiConnected = false;
1382f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            mobileConnected = false;
1392f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        }
1402f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
1412f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1422f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Uses AsyncTask subclass to download the XML feed from stackoverflow.com.
1432f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // This avoids UI lock up. To prevent network operations from
1442f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // causing a delay that results in a poor user experience, always perform
1452f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // network operations on a separate thread from the UI.
1462f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    private void loadPage() {
1472f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        if (((sPref.equals(ANY)) && (wifiConnected || mobileConnected))
1482f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                || ((sPref.equals(WIFI)) && (wifiConnected))) {
1492f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            // AsyncTask subclass
1502f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            new DownloadXmlTask().execute(URL);
1512f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        } else {
1522f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            showErrorPage();
1532f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        }
1542f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
1552f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1562f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Displays an error if the app is unable to load content.
1572f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    private void showErrorPage() {
1582f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        setContentView(R.layout.main);
1592f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1602f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // The specified network connection is not available. Displays error message.
1612f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        WebView myWebView = (WebView) findViewById(R.id.webview);
1622f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        myWebView.loadData(getResources().getString(R.string.connection_error),
1632f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                "text/html", null);
1642f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
1652f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1662f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Populates the activity's options menu.
1672f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    @Override
1682f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    public boolean onCreateOptionsMenu(Menu menu) {
1692f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        MenuInflater inflater = getMenuInflater();
1702f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        inflater.inflate(R.menu.mainmenu, menu);
1712f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        return true;
1722f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
1732f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1742f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Handles the user's menu selection.
1752f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    @Override
1762f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    public boolean onOptionsItemSelected(MenuItem item) {
1772f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        switch (item.getItemId()) {
1782f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        case R.id.settings:
1792f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                Intent settingsActivity = new Intent(getBaseContext(), SettingsActivity.class);
1802f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                startActivity(settingsActivity);
1812f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                return true;
1822f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        case R.id.refresh:
1832f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                loadPage();
1842f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                return true;
1852f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        default:
1862f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                return super.onOptionsItemSelected(item);
1872f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        }
1882f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
1892f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1902f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Implementation of AsyncTask used to download XML feed from stackoverflow.com.
1912f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    private class DownloadXmlTask extends AsyncTask<String, Void, String> {
1922f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
1932f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        @Override
1942f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        protected String doInBackground(String... urls) {
1952f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            try {
1962f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                return loadXmlFromNetwork(urls[0]);
1972f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            } catch (IOException e) {
1982f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                return getResources().getString(R.string.connection_error);
1992f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            } catch (XmlPullParserException e) {
2002f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                return getResources().getString(R.string.xml_error);
2012f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            }
2022f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        }
2032f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
2042f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        @Override
2052f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        protected void onPostExecute(String result) {
2062f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            setContentView(R.layout.main);
2072f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            // Displays the HTML string in the UI via a WebView
2082f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            WebView myWebView = (WebView) findViewById(R.id.webview);
2092f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            myWebView.loadData(result, "text/html", null);
2102f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        }
2112f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
2122f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
2132f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Uploads XML from stackoverflow.com, parses it, and combines it with
2142f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // HTML markup. Returns HTML string.
2152f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    private String loadXmlFromNetwork(String urlString) throws XmlPullParserException, IOException {
2162f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        InputStream stream = null;
2172f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser();
2182f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        List<Entry> entries = null;
2192f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        String title = null;
2202f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        String url = null;
2212f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        String summary = null;
2222f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        Calendar rightNow = Calendar.getInstance();
2232f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        DateFormat formatter = new SimpleDateFormat("MMM dd h:mmaa");
2242f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
2252f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // Checks whether the user set the preference to include summary text
2262f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
2272f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        boolean pref = sharedPrefs.getBoolean("summaryPref", false);
2282f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
2292f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        StringBuilder htmlString = new StringBuilder();
2302f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        htmlString.append("<h3>" + getResources().getString(R.string.page_title) + "</h3>");
2312f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        htmlString.append("<em>" + getResources().getString(R.string.updated) + " " +
2322f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                formatter.format(rightNow.getTime()) + "</em>");
2332f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
2342f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        try {
2352f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            stream = downloadUrl(urlString);
2362f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            entries = stackOverflowXmlParser.parse(stream);
2372f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // Makes sure that the InputStream is closed after the app is
2382f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // finished using it.
2392f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        } finally {
2402f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            if (stream != null) {
2412f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                stream.close();
2422f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            }
2432f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        }
2442f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
2452f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // StackOverflowXmlParser returns a List (called "entries") of Entry objects.
2462f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // Each Entry object represents a single post in the XML feed.
2472f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // This section processes the entries list to combine each entry with HTML markup.
2482f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // Each entry is displayed in the UI as a link that optionally includes
2492f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // a text summary.
2502f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        for (Entry entry : entries) {
2512f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            htmlString.append("<p><a href='");
2522f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            htmlString.append(entry.link);
2532f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            htmlString.append("'>" + entry.title + "</a></p>");
2542f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            // If the user set the preference to include summary text,
2552f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            // adds it to the display.
2562f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            if (pref) {
2572f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                htmlString.append(entry.summary);
2582f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            }
2592f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        }
2602f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        return htmlString.toString();
2612f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
2622f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
2632f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // Given a string representation of a URL, sets up a connection and gets
2642f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    // an input stream.
2652f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    private InputStream downloadUrl(String urlString) throws IOException {
2662f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        URL url = new URL(urlString);
2672f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
2682f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        conn.setReadTimeout(10000 /* milliseconds */);
2692f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        conn.setConnectTimeout(15000 /* milliseconds */);
2702f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        conn.setRequestMethod("GET");
2712f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        conn.setDoInput(true);
2722f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        // Starts the query
2732f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        conn.connect();
2742f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        InputStream stream = conn.getInputStream();
2752f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        return stream;
2762f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
2772f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
2782f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    /**
2792f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick     *
2802f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick     * This BroadcastReceiver intercepts the android.net.ConnectivityManager.CONNECTIVITY_ACTION,
2812f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick     * which indicates a connection change. It checks whether the type is TYPE_WIFI.
2822f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick     * If it is, it checks whether Wi-Fi is connected and sets the wifiConnected flag in the
2832f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick     * main activity accordingly.
2842f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick     *
2852f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick     */
2862f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    public class NetworkReceiver extends BroadcastReceiver {
2872f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
2882f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        @Override
2892f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        public void onReceive(Context context, Intent intent) {
2902f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            ConnectivityManager connMgr =
2912f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                    (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
2922f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
2932f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
2942f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            // Checks the user prefs and the network connection. Based on the result, decides
2952f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            // whether
2962f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            // to refresh the display or keep the current display.
2972f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            // If the userpref is Wi-Fi only, checks to see if the device has a Wi-Fi connection.
2982f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            if (WIFI.equals(sPref) && networkInfo != null
2992f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                    && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
3002f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                // If device has its Wi-Fi connection, sets refreshDisplay
3012f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                // to true. This causes the display to be refreshed when the user
3022f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                // returns to the app.
3032f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                refreshDisplay = true;
3042f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                Toast.makeText(context, R.string.wifi_connected, Toast.LENGTH_SHORT).show();
3052f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
3062f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                // If the setting is ANY network and there is a network connection
3072f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                // (which by process of elimination would be mobile), sets refreshDisplay to true.
3082f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            } else if (ANY.equals(sPref) && networkInfo != null) {
3092f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                refreshDisplay = true;
3102f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick
3112f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                // Otherwise, the app can't download content--either because there is no network
3122f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                // connection (mobile or Wi-Fi), or because the pref setting is WIFI, and there
3132f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                // is no Wi-Fi connection.
3142f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                // Sets refreshDisplay to false.
3152f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            } else {
3162f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                refreshDisplay = false;
3172f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick                Toast.makeText(context, R.string.lost_connection, Toast.LENGTH_SHORT).show();
3182f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick            }
3192f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick        }
3202f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick    }
3212f8cc17f5fbc2e05ac0889fbbddf4e530750087bKatie McCormick}
322