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