summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKatie McCormick <kmccormick@google.com>2012-03-16 17:47:55 -0700
committerKatie McCormick <kmccormick@google.com>2012-08-08 11:27:09 -0700
commit2f8cc17f5fbc2e05ac0889fbbddf4e530750087b (patch)
treec33a8b7880f4cc821e2067c487badf69d98ea21f
parent0d3a127742b56a9aae9c9c018b7042f49902db8a (diff)
downloadframeworks_base-2f8cc17f5fbc2e05ac0889fbbddf4e530750087b.zip
frameworks_base-2f8cc17f5fbc2e05ac0889fbbddf4e530750087b.tar.gz
frameworks_base-2f8cc17f5fbc2e05ac0889fbbddf4e530750087b.tar.bz2
cherrypick from ics-mr1 docs: source for nw app Change-Id: If50f407a0e56fa802fe9beedaa650e3a131872b2
Change-Id: I55d8668f4065129c844ada239f268a6621df4780
-rw-r--r--samples/training/network-usage/AndroidManifest.xml48
-rw-r--r--samples/training/network-usage/README.txt14
-rw-r--r--samples/training/network-usage/res/drawable-hdpi/ic_launcher.pngbin0 -> 4147 bytes
-rw-r--r--samples/training/network-usage/res/drawable-ldpi/ic_launcher.pngbin0 -> 1723 bytes
-rw-r--r--samples/training/network-usage/res/drawable-mdpi/ic_launcher.pngbin0 -> 2574 bytes
-rw-r--r--samples/training/network-usage/res/layout/main.xml12
-rw-r--r--samples/training/network-usage/res/menu/mainmenu.xml24
-rw-r--r--samples/training/network-usage/res/values/arrays.xml28
-rw-r--r--samples/training/network-usage/res/values/strings.xml35
-rw-r--r--samples/training/network-usage/res/xml/preferences.xml33
-rw-r--r--samples/training/network-usage/src/com/example/android/networkusage/NetworkActivity.java321
-rw-r--r--samples/training/network-usage/src/com/example/android/networkusage/SettingsActivity.java66
-rw-r--r--samples/training/network-usage/src/com/example/android/networkusage/StackOverflowXmlParser.java169
13 files changed, 750 insertions, 0 deletions
diff --git a/samples/training/network-usage/AndroidManifest.xml b/samples/training/network-usage/AndroidManifest.xml
new file mode 100644
index 0000000..4b96d14
--- /dev/null
+++ b/samples/training/network-usage/AndroidManifest.xml
@@ -0,0 +1,48 @@
+<!--
+ Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.networkusage"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk android:minSdkVersion="4"
+ android:targetSdkVersion="14" />
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+
+ <activity
+ android:name="com.example.networkusage.NetworkActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:label="SettingsActivity" android:name=".SettingsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MANAGE_NETWORK_USAGE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/samples/training/network-usage/README.txt b/samples/training/network-usage/README.txt
new file mode 100644
index 0000000..cc9a7a0
--- /dev/null
+++ b/samples/training/network-usage/README.txt
@@ -0,0 +1,14 @@
+README
+======
+
+This Network Usage sample app does the following:
+
+-- Downloads an XML feed from StackOverflow.com for the most recent posts tagged "android".
+
+-- Parses the XML feed, combines feed elements with HTML markup, and displays the resulting HTML in the UI.
+
+-- Lets users control their network data usage through a settings UI. Users can choose to fetch the feed
+ when any network connection is available, or only when a Wi-Fi connection is available.
+
+-- Detects when there is a change in the device's connection status and responds accordingly. For example, if
+ the device loses its network connection, the app will not attempt to download the feed.
diff --git a/samples/training/network-usage/res/drawable-hdpi/ic_launcher.png b/samples/training/network-usage/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/samples/training/network-usage/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/network-usage/res/drawable-ldpi/ic_launcher.png b/samples/training/network-usage/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000..1095584
--- /dev/null
+++ b/samples/training/network-usage/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/network-usage/res/drawable-mdpi/ic_launcher.png b/samples/training/network-usage/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/samples/training/network-usage/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/training/network-usage/res/layout/main.xml b/samples/training/network-usage/res/layout/main.xml
new file mode 100644
index 0000000..8498934
--- /dev/null
+++ b/samples/training/network-usage/res/layout/main.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+
+<WebView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/webview"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+/>
+</LinearLayout>
diff --git a/samples/training/network-usage/res/menu/mainmenu.xml b/samples/training/network-usage/res/menu/mainmenu.xml
new file mode 100644
index 0000000..17d44db
--- /dev/null
+++ b/samples/training/network-usage/res/menu/mainmenu.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/settings"
+ android:title="@string/settings" />
+ <item android:id="@+id/refresh"
+ android:title="@string/refresh" />
+</menu>
diff --git a/samples/training/network-usage/res/values/arrays.xml b/samples/training/network-usage/res/values/arrays.xml
new file mode 100644
index 0000000..2e8b8a7
--- /dev/null
+++ b/samples/training/network-usage/res/values/arrays.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <string-array name="listArray">
+ <item>Only when on Wi-Fi</item>
+ <item>On any network</item>
+ </string-array>
+ <string-array name="listValues">
+ <item>Wi-Fi</item>
+ <item>Any</item>
+ </string-array>
+</resources>
diff --git a/samples/training/network-usage/res/values/strings.xml b/samples/training/network-usage/res/values/strings.xml
new file mode 100644
index 0000000..d7c702f
--- /dev/null
+++ b/samples/training/network-usage/res/values/strings.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+
+ <string name="app_name">NetworkUsage</string>
+
+ <!-- Menu items -->
+ <string name="settings">Settings</string>
+ <string name="refresh">Refresh</string>
+
+ <!-- NetworkActivity -->
+ <string name="page_title">Newest StackOverflow questions tagged \'android\'</string>
+ <string name="updated">Last updated:</string>
+ <string name="lost_connection">Lost connection.</string>
+ <string name="wifi_connected">Wi-Fi reconnected.</string>
+ <string name="connection_error">Unable to load content. Check your network connection.</string>
+ <string name="xml_error">Error parsing XML.</string>
+
+</resources>
diff --git a/samples/training/network-usage/res/xml/preferences.xml b/samples/training/network-usage/res/xml/preferences.xml
new file mode 100644
index 0000000..801ba79
--- /dev/null
+++ b/samples/training/network-usage/res/xml/preferences.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2012 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ <ListPreference
+ android:title="Download Feed"
+ android:summary="Network connectivity required to download the feed."
+ android:key="listPref"
+ android:defaultValue="Wi-Fi"
+ android:entries="@array/listArray"
+ android:entryValues="@array/listValues"
+ />
+ <CheckBoxPreference
+ android:title="Show Summaries"
+ android:defaultValue="false"
+ android:summary="Show a summary for each link."
+ android:key="summaryPref" />
+</PreferenceScreen>
diff --git a/samples/training/network-usage/src/com/example/android/networkusage/NetworkActivity.java b/samples/training/network-usage/src/com/example/android/networkusage/NetworkActivity.java
new file mode 100644
index 0000000..b7ed331
--- /dev/null
+++ b/samples/training/network-usage/src/com/example/android/networkusage/NetworkActivity.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.example.android.networkusage;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.webkit.WebView;
+import android.widget.Toast;
+
+import com.example.android.networkusage.R;
+import com.example.android.networkusage.StackOverflowXmlParser.Entry;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.List;
+
+
+/**
+ * Main Activity for the sample application.
+ *
+ * This activity does the following:
+ *
+ * o Presents a WebView screen to users. This WebView has a list of HTML links to the latest
+ * questions tagged 'android' on stackoverflow.com.
+ *
+ * o Parses the StackOverflow XML feed using XMLPullParser.
+ *
+ * o Uses AsyncTask to download and process the XML feed.
+ *
+ * o Monitors preferences and the device's network connection to determine whether
+ * to refresh the WebView content.
+ */
+public class NetworkActivity extends Activity {
+ public static final String WIFI = "Wi-Fi";
+ public static final String ANY = "Any";
+ private static final String URL =
+ "http://stackoverflow.com/feeds/tag?tagnames=android&sort=newest";
+
+ // Whether there is a Wi-Fi connection.
+ private static boolean wifiConnected = false;
+ // Whether there is a mobile connection.
+ private static boolean mobileConnected = false;
+ // Whether the display should be refreshed.
+ public static boolean refreshDisplay = true;
+
+ // The user's current network preference setting.
+ public static String sPref = null;
+
+ // The BroadcastReceiver that tracks network connectivity changes.
+ private NetworkReceiver receiver = new NetworkReceiver();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Register BroadcastReceiver to track connection changes.
+ IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
+ receiver = new NetworkReceiver();
+ this.registerReceiver(receiver, filter);
+ }
+
+ // Refreshes the display if the network connection and the
+ // pref settings allow it.
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ // Gets the user's network preference settings
+ SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+
+ // Retrieves a string value for the preferences. The second parameter
+ // is the default value to use if a preference value is not found.
+ sPref = sharedPrefs.getString("listPref", "Wi-Fi");
+
+ updateConnectedFlags();
+
+ // Only loads the page if refreshDisplay is true. Otherwise, keeps previous
+ // display. For example, if the user has set "Wi-Fi only" in prefs and the
+ // device loses its Wi-Fi connection midway through the user using the app,
+ // you don't want to refresh the display--this would force the display of
+ // an error page instead of stackoverflow.com content.
+ if (refreshDisplay) {
+ loadPage();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (receiver != null) {
+ this.unregisterReceiver(receiver);
+ }
+ }
+
+ // Checks the network connection and sets the wifiConnected and mobileConnected
+ // variables accordingly.
+ private void updateConnectedFlags() {
+ ConnectivityManager connMgr =
+ (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
+ if (activeInfo != null && activeInfo.isConnected()) {
+ wifiConnected = activeInfo.getType() == ConnectivityManager.TYPE_WIFI;
+ mobileConnected = activeInfo.getType() == ConnectivityManager.TYPE_MOBILE;
+ } else {
+ wifiConnected = false;
+ mobileConnected = false;
+ }
+ }
+
+ // Uses AsyncTask subclass to download the XML feed from stackoverflow.com.
+ // This avoids UI lock up. To prevent network operations from
+ // causing a delay that results in a poor user experience, always perform
+ // network operations on a separate thread from the UI.
+ private void loadPage() {
+ if (((sPref.equals(ANY)) && (wifiConnected || mobileConnected))
+ || ((sPref.equals(WIFI)) && (wifiConnected))) {
+ // AsyncTask subclass
+ new DownloadXmlTask().execute(URL);
+ } else {
+ showErrorPage();
+ }
+ }
+
+ // Displays an error if the app is unable to load content.
+ private void showErrorPage() {
+ setContentView(R.layout.main);
+
+ // The specified network connection is not available. Displays error message.
+ WebView myWebView = (WebView) findViewById(R.id.webview);
+ myWebView.loadData(getResources().getString(R.string.connection_error),
+ "text/html", null);
+ }
+
+ // Populates the activity's options menu.
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.mainmenu, menu);
+ return true;
+ }
+
+ // Handles the user's menu selection.
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.settings:
+ Intent settingsActivity = new Intent(getBaseContext(), SettingsActivity.class);
+ startActivity(settingsActivity);
+ return true;
+ case R.id.refresh:
+ loadPage();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ // Implementation of AsyncTask used to download XML feed from stackoverflow.com.
+ private class DownloadXmlTask extends AsyncTask<String, Void, String> {
+
+ @Override
+ protected String doInBackground(String... urls) {
+ try {
+ return loadXmlFromNetwork(urls[0]);
+ } catch (IOException e) {
+ return getResources().getString(R.string.connection_error);
+ } catch (XmlPullParserException e) {
+ return getResources().getString(R.string.xml_error);
+ }
+ }
+
+ @Override
+ protected void onPostExecute(String result) {
+ setContentView(R.layout.main);
+ // Displays the HTML string in the UI via a WebView
+ WebView myWebView = (WebView) findViewById(R.id.webview);
+ myWebView.loadData(result, "text/html", null);
+ }
+ }
+
+ // Uploads XML from stackoverflow.com, parses it, and combines it with
+ // HTML markup. Returns HTML string.
+ private String loadXmlFromNetwork(String urlString) throws XmlPullParserException, IOException {
+ InputStream stream = null;
+ StackOverflowXmlParser stackOverflowXmlParser = new StackOverflowXmlParser();
+ List<Entry> entries = null;
+ String title = null;
+ String url = null;
+ String summary = null;
+ Calendar rightNow = Calendar.getInstance();
+ DateFormat formatter = new SimpleDateFormat("MMM dd h:mmaa");
+
+ // Checks whether the user set the preference to include summary text
+ SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ boolean pref = sharedPrefs.getBoolean("summaryPref", false);
+
+ StringBuilder htmlString = new StringBuilder();
+ htmlString.append("<h3>" + getResources().getString(R.string.page_title) + "</h3>");
+ htmlString.append("<em>" + getResources().getString(R.string.updated) + " " +
+ formatter.format(rightNow.getTime()) + "</em>");
+
+ try {
+ stream = downloadUrl(urlString);
+ entries = stackOverflowXmlParser.parse(stream);
+ // Makes sure that the InputStream is closed after the app is
+ // finished using it.
+ } finally {
+ if (stream != null) {
+ stream.close();
+ }
+ }
+
+ // StackOverflowXmlParser returns a List (called "entries") of Entry objects.
+ // Each Entry object represents a single post in the XML feed.
+ // This section processes the entries list to combine each entry with HTML markup.
+ // Each entry is displayed in the UI as a link that optionally includes
+ // a text summary.
+ for (Entry entry : entries) {
+ htmlString.append("<p><a href='");
+ htmlString.append(entry.link);
+ htmlString.append("'>" + entry.title + "</a></p>");
+ // If the user set the preference to include summary text,
+ // adds it to the display.
+ if (pref) {
+ htmlString.append(entry.summary);
+ }
+ }
+ return htmlString.toString();
+ }
+
+ // Given a string representation of a URL, sets up a connection and gets
+ // an input stream.
+ private InputStream downloadUrl(String urlString) throws IOException {
+ URL url = new URL(urlString);
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setReadTimeout(10000 /* milliseconds */);
+ conn.setConnectTimeout(15000 /* milliseconds */);
+ conn.setRequestMethod("GET");
+ conn.setDoInput(true);
+ // Starts the query
+ conn.connect();
+ InputStream stream = conn.getInputStream();
+ return stream;
+ }
+
+ /**
+ *
+ * This BroadcastReceiver intercepts the android.net.ConnectivityManager.CONNECTIVITY_ACTION,
+ * which indicates a connection change. It checks whether the type is TYPE_WIFI.
+ * If it is, it checks whether Wi-Fi is connected and sets the wifiConnected flag in the
+ * main activity accordingly.
+ *
+ */
+ public class NetworkReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ ConnectivityManager connMgr =
+ (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
+
+ // Checks the user prefs and the network connection. Based on the result, decides
+ // whether
+ // to refresh the display or keep the current display.
+ // If the userpref is Wi-Fi only, checks to see if the device has a Wi-Fi connection.
+ if (WIFI.equals(sPref) && networkInfo != null
+ && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
+ // If device has its Wi-Fi connection, sets refreshDisplay
+ // to true. This causes the display to be refreshed when the user
+ // returns to the app.
+ refreshDisplay = true;
+ Toast.makeText(context, R.string.wifi_connected, Toast.LENGTH_SHORT).show();
+
+ // If the setting is ANY network and there is a network connection
+ // (which by process of elimination would be mobile), sets refreshDisplay to true.
+ } else if (ANY.equals(sPref) && networkInfo != null) {
+ refreshDisplay = true;
+
+ // Otherwise, the app can't download content--either because there is no network
+ // connection (mobile or Wi-Fi), or because the pref setting is WIFI, and there
+ // is no Wi-Fi connection.
+ // Sets refreshDisplay to false.
+ } else {
+ refreshDisplay = false;
+ Toast.makeText(context, R.string.lost_connection, Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+}
diff --git a/samples/training/network-usage/src/com/example/android/networkusage/SettingsActivity.java b/samples/training/network-usage/src/com/example/android/networkusage/SettingsActivity.java
new file mode 100644
index 0000000..73b72d2
--- /dev/null
+++ b/samples/training/network-usage/src/com/example/android/networkusage/SettingsActivity.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.example.android.networkusage;
+
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import com.example.android.networkusage.R;
+
+/**
+ * This preference activity has in its manifest declaration an intent filter for
+ * the ACTION_MANAGE_NETWORK_USAGE action. This activity provides a settings UI
+ * for users to specify network settings to control data usage.
+ */
+public class SettingsActivity extends PreferenceActivity
+ implements
+ OnSharedPreferenceChangeListener {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Loads the XML preferences file.
+ addPreferencesFromResource(R.xml.preferences);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ // Registers a callback to be invoked whenever a user changes a preference.
+ getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ // Unregisters the listener set in onResume().
+ // It's best practice to unregister listeners when your app isn't using them to cut down on
+ // unnecessary system overhead. You do this in onPause().
+ getPreferenceScreen()
+ .getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ // Fires when the user changes a preference.
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ // Sets refreshDisplay to true so that when the user returns to the main
+ // activity, the display refreshes to reflect the new settings.
+ NetworkActivity.refreshDisplay = true;
+ }
+}
diff --git a/samples/training/network-usage/src/com/example/android/networkusage/StackOverflowXmlParser.java b/samples/training/network-usage/src/com/example/android/networkusage/StackOverflowXmlParser.java
new file mode 100644
index 0000000..6a01098
--- /dev/null
+++ b/samples/training/network-usage/src/com/example/android/networkusage/StackOverflowXmlParser.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.example.android.networkusage;
+
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class parses XML feeds from stackoverflow.com.
+ * Given an InputStream representation of a feed, it returns a List of entries,
+ * where each list element represents a single entry (post) in the XML feed.
+ */
+public class StackOverflowXmlParser {
+ private static final String ns = null;
+
+ // We don't use namespaces
+
+ public List<Entry> parse(InputStream in) throws XmlPullParserException, IOException {
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+ parser.setInput(in, null);
+ parser.nextTag();
+ return readFeed(parser);
+ } finally {
+ in.close();
+ }
+ }
+
+ private List<Entry> readFeed(XmlPullParser parser) throws XmlPullParserException, IOException {
+ List<Entry> entries = new ArrayList<Entry>();
+
+ parser.require(XmlPullParser.START_TAG, ns, "feed");
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ // Starts by looking for the entry tag
+ if (name.equals("entry")) {
+ entries.add(readEntry(parser));
+ } else {
+ skip(parser);
+ }
+ }
+ return entries;
+ }
+
+ // This class represents a single entry (post) in the XML feed.
+ // It includes the data members "title," "link," and "summary."
+ public static class Entry {
+ public final String title;
+ public final String link;
+ public final String summary;
+
+ private Entry(String title, String summary, String link) {
+ this.title = title;
+ this.summary = summary;
+ this.link = link;
+ }
+ }
+
+ // Parses the contents of an entry. If it encounters a title, summary, or link tag, hands them
+ // off
+ // to their respective &quot;read&quot; methods for processing. Otherwise, skips the tag.
+ private Entry readEntry(XmlPullParser parser) throws XmlPullParserException, IOException {
+ parser.require(XmlPullParser.START_TAG, ns, "entry");
+ String title = null;
+ String summary = null;
+ String link = null;
+ while (parser.next() != XmlPullParser.END_TAG) {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ continue;
+ }
+ String name = parser.getName();
+ if (name.equals("title")) {
+ title = readTitle(parser);
+ } else if (name.equals("summary")) {
+ summary = readSummary(parser);
+ } else if (name.equals("link")) {
+ link = readLink(parser);
+ } else {
+ skip(parser);
+ }
+ }
+ return new Entry(title, summary, link);
+ }
+
+ // Processes title tags in the feed.
+ private String readTitle(XmlPullParser parser) throws IOException, XmlPullParserException {
+ parser.require(XmlPullParser.START_TAG, ns, "title");
+ String title = readText(parser);
+ parser.require(XmlPullParser.END_TAG, ns, "title");
+ return title;
+ }
+
+ // Processes link tags in the feed.
+ private String readLink(XmlPullParser parser) throws IOException, XmlPullParserException {
+ String link = "";
+ parser.require(XmlPullParser.START_TAG, ns, "link");
+ String tag = parser.getName();
+ String relType = parser.getAttributeValue(null, "rel");
+ if (tag.equals("link")) {
+ if (relType.equals("alternate")) {
+ link = parser.getAttributeValue(null, "href");
+ parser.nextTag();
+ }
+ }
+ parser.require(XmlPullParser.END_TAG, ns, "link");
+ return link;
+ }
+
+ // Processes summary tags in the feed.
+ private String readSummary(XmlPullParser parser) throws IOException, XmlPullParserException {
+ parser.require(XmlPullParser.START_TAG, ns, "summary");
+ String summary = readText(parser);
+ parser.require(XmlPullParser.END_TAG, ns, "summary");
+ return summary;
+ }
+
+ // For the tags title and summary, extracts their text values.
+ private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
+ String result = "";
+ if (parser.next() == XmlPullParser.TEXT) {
+ result = parser.getText();
+ parser.nextTag();
+ }
+ return result;
+ }
+
+ // Skips tags the parser isn't interested in. Uses depth to handle nested tags. i.e.,
+ // if the next tag after a START_TAG isn't a matching END_TAG, it keeps going until it
+ // finds the matching END_TAG (as indicated by the value of "depth" being 0).
+ private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException();
+ }
+ int depth = 1;
+ while (depth != 0) {
+ switch (parser.next()) {
+ case XmlPullParser.END_TAG:
+ depth--;
+ break;
+ case XmlPullParser.START_TAG:
+ depth++;
+ break;
+ }
+ }
+ }
+}