am 130b7e43: Merge "cherrypick from ics-mr1 docs: network sample Change-Id: If50f407a0e56fa802fe9beedaa650e3a131872b2" into jb-mr1-dev
* commit '130b7e43f91e154cd1e9a63c37089c223c3e1f1e': cherrypick from ics-mr1 docs: network sample Change-Id: If50f407a0e56fa802fe9beedaa650e3a131872b2
This commit is contained in:
48
samples/training/network-usage/AndroidManifest.xml
Normal file
48
samples/training/network-usage/AndroidManifest.xml
Normal file
@@ -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>
|
||||||
14
samples/training/network-usage/README.txt
Normal file
14
samples/training/network-usage/README.txt
Normal file
@@ -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.
|
||||||
BIN
samples/training/network-usage/res/drawable-hdpi/ic_launcher.png
Normal file
BIN
samples/training/network-usage/res/drawable-hdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
BIN
samples/training/network-usage/res/drawable-ldpi/ic_launcher.png
Normal file
BIN
samples/training/network-usage/res/drawable-ldpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
BIN
samples/training/network-usage/res/drawable-mdpi/ic_launcher.png
Normal file
BIN
samples/training/network-usage/res/drawable-mdpi/ic_launcher.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
12
samples/training/network-usage/res/layout/main.xml
Normal file
12
samples/training/network-usage/res/layout/main.xml
Normal file
@@ -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>
|
||||||
24
samples/training/network-usage/res/menu/mainmenu.xml
Normal file
24
samples/training/network-usage/res/menu/mainmenu.xml
Normal file
@@ -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>
|
||||||
28
samples/training/network-usage/res/values/arrays.xml
Normal file
28
samples/training/network-usage/res/values/arrays.xml
Normal file
@@ -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>
|
||||||
35
samples/training/network-usage/res/values/strings.xml
Normal file
35
samples/training/network-usage/res/values/strings.xml
Normal file
@@ -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>
|
||||||
33
samples/training/network-usage/res/xml/preferences.xml
Normal file
33
samples/training/network-usage/res/xml/preferences.xml
Normal file
@@ -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>
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 "read" 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user