auto import from //depot/cupcake/@135843

This commit is contained in:
The Android Open Source Project
2009-03-03 19:29:09 -08:00
parent d4aee0c0ca
commit 52d4c30ca5
2386 changed files with 299112 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2007 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.codelab.rssexample;
import android.app.Activity;
import android.content.Intent;
import android.view.View.OnClickListener;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.text.TextUtils;
import android.os.Bundle;
/*** Form to add a new RSS feed.
It is a dialog form,**/
public class AddRssItem extends Activity {
// Button handler for Submit/Cancel.
// It is a dialog style form because it's declared as such
// in the manifest.
private OnClickListener mClickListener = new OnClickListener(){
public void onClick(View v){
if(v.getId() == R.id.submit){
String title = ((TextView) findViewById(R.id.title_textbox)).getText().toString();
String url = ((TextView) findViewById(R.id.url_textbox)).getText().toString();
if(TextUtils.isEmpty(title) || TextUtils.isEmpty(url)){
showAlert("Missing Values",
"You must specify both a title and a URL value",
"OK",
null, false, null);
return;
}
Intent res = new Intent("Accepted");
res.putExtra(RssContentProvider.TITLE, title);
res.putExtra(RssContentProvider.URL, url);
res.putExtra(RssContentProvider.LAST_UPDATED, 0);
res.putExtra(RssContentProvider.CONTENT, "<html><body><h2>Not updated yet.</h2></body></html>");
setResult(RESULT_OK, res);
}
else
setResult(RESULT_CANCELED, (new Intent()).setAction("Canceled" + v.getId()));
finish();
}
};
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.add_item);
setTitle(getString(R.string.add_item_label));
Button btn = (Button) findViewById(R.id.cancel);
btn.setOnClickListener(mClickListener);
btn = (Button) findViewById(R.id.submit);
btn.setOnClickListener(mClickListener);
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright (C) 2007 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.codelab.rssexample;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.ArrayAdapter;
import android.widget.ListView;
//BEGIN_INCLUDE(1_1)
public class MyRssReader extends Activity {
/** Called with the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// Load screen layout.
setContentView(R.layout.main_screen);
//END_INCLUDE(1_1)
//BEGIN_INCLUDE(1_2)
// Load some simple values into the ListView
mRssList = (ListView) findViewById(R.id.rssListView);
mRssList.setAdapter(
new ArrayAdapter<String>(
this,
R.layout.list_element,
new String[] { "Scientific American", "BBC", "The Onion", "Engadget" }));
//END_INCLUDE(1_2)
}
// Store our state before we are potentially bumped from memory.
// We'd like to store the current ListView selection.
@Override
protected void onSaveInstanceState(Bundle outState){
int index = mRssList.getSelectedItemIndex();
if(index > -1){
outState.putInteger("lastIndexItem", index);
}
}
// Add our initial menu options. We will tweak this menu when it's loaded swap out
// "start service" or "stop service", depending on whether the service is currently running.
@Override
public boolean onCreateOptionsMenu(Menu menu){
// Always call the superclass implementation to
// provide standard items.
super.onCreateOptionsMenu(menu);
menu.add(0, 0, "Start RSS Service", null);
menu.add(0, 1, "Stop RSS Service", null);
menu.add(0, 2, "Add New Feed", null);
menu.add(0, 3, "Delete Feed", null);
menu.add(0, 4, "Update All Feeds", null);
return true;
}
// Toggle out start service/stop service depending on whether the service is running.
@Override
public boolean onPrepareOptionsMenu(Menu menu){
return true;
}
// Handle our menu clicks.
@Override
public boolean onOptionsItemSelected(Menu.Item item){
switch (item.getId()) {
case 0:
showAlert(null, "You clicked 'start'!", "ok", null, false, null);
break;
case 1:
showAlert(null, "You clicked stop!", "ok", null, false, null);
break;
case 2:
showAlert(null, "You clicked 'Add'!", "ok", null, false, null);
break;
case 3:
showAlert(null, "You clicked 'Delete'!", "ok", null, false, null);
break;
case 4:
showAlert(null, "You clicked 'Update'!", "ok", null, false, null);
break;
default:
showAlert(null, "I have no idea what you clicked!", "ok", null, false, null);
break;
}
return true;
}
ListView mRssList;
}

View File

@@ -0,0 +1,181 @@
/*
* Copyright (C) 2007 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.codelab.rssexample;
import android.app.Activity;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
public class MyRssReader2 extends Activity{
private ArrayList<RssItem> mFeeds = null;
ListView mRssList = null;
private Logger mLogger = Logger.getLogger("com.example.codelab.rssexample");
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// Load screen layout.
setContentView(R.layout.main_screen2);
// Populate our list
mFeeds = initializeList();
mLogger.info("MyRssReader.onCreate-1 mFeeds value:" + mFeeds.size());
// BEGIN_INCLUDE(2_2)
// Populate ArrayAdapter and bind it to ListView
mRssList = (ListView)findViewById(R.id.rssListView);
if(mRssList == null){
// Note: Calling showAlert() would fail here because dialogs opened
// in onCreate won't be displayed properly, if at all.
mLogger.warning("MyRssReader.onCreate-2 -- Couldn't instantiate a ListView!");
}
RssDataAdapter<RssItem> adap = new RssDataAdapter<RssItem>(this, R.layout.add_item, mFeeds);
if(adap == null){
mLogger.warning("MyRssReader.onCreate-3 -- Couldn't instantiate RssDataAdapter!");
}
if(mFeeds == null){
mLogger.warning("MyRssReader.onCreate-4 -- Couldn't instantiate a ListView!");
}
mRssList.setAdapter(adap);
// END_INCLUDE(2_2)
mLogger.info("MyRssReader.onCreate-5 -- Loading preferences.");
// Set the last selected item.
// (icicle is only set if this is being restarted).
if(savedInstanceState != null && savedInstanceState.containsKey("lastIndexItem"))
{
Integer selectedItem = savedInstanceState.getInteger("lastIndexItem");
if(selectedItem >= 0 && selectedItem < mRssList.getChildCount()){
mRssList.setSelection(savedInstanceState.getInteger("lastIndexItem"));
}
mLogger.info("MyRssReader.onCreate-6 -- Last selected item:" + selectedItem);
}
}
// Store our state before we are potentially bumped from memory.
// We'd like to store the current ListView selection.
@Override
protected void onSaveInstanceState(Bundle outState){
int index = mRssList.getSelectedItemIndex();
if(index > -1){
outState.putInteger("lastIndexItem", index);
}
}
// Add our initial menu options. We will tweak this menu when it's loaded swap out
// "start service" or "stop service", depending on whether the service is currently running.
@Override
public boolean onCreateOptionsMenu(Menu menu){
// Always call the superclass implementation to
// provide standard items.
super.onCreateOptionsMenu(menu);
menu.add(0, 0, "Start RSS Service", null);
menu.add(0, 1, "Stop RSS Service", null);
menu.add(0, 2, "Add New Feed", null);
menu.add(0, 3, "Delete Feed", null);
menu.add(0, 4, "Update All Feeds", null);
return true;
}
// Toggle out start service/stop service depending on whether the service is running.
@Override
public boolean onPrepareOptionsMenu(Menu menu){
return true;
}
// Handle our menu clicks.
@Override
public boolean onOptionsItemSelected(Menu.Item item){
switch (item.getId()){
case 0:
showAlert(null, "You clicked 'start'!", "ok", null, false, null);
break;
case 1:
showAlert(null, "You clicked stop!", "ok", null, false, null);
break;
case 2:
showAlert(null, "You clicked 'Add'!", "ok", null, false, null);
break;
case 3:
showAlert(null, "You clicked 'Delete'!", "ok", null, false, null);
break;
case 4:
showAlert(null, "You clicked 'Update'!", "ok", null, false, null);
break;
default:
showAlert(null, "I have no idea what you clicked!", "ok", null, false, null);
break;
}
return true;
}
// Our private ArrayAdapter implementation that returns a bold TextView for
// RSS items that are unread, or a normal TextView for items that have been read.
// BEGIN_INCLUDE(2_3)
private class RssDataAdapter<T> extends ArrayAdapter<T> {
public RssDataAdapter(Context context, int resource, List objects) {
super(context, resource, objects);
}
// END_INCLUDE(2_3)
// Here's our only important override--returning the list item.
@Override
public View getView(int position, View convertView, ViewGroup parent){
TextView view = null;
// Get the item from the underlying array,
// Create a TextView wrapper, and change the typeface, if necessary.
RssItem item = (RssItem)this.getItem(position);
if(item != null)
{
view = new TextView(parent.getContext());
view.setText(item.toString());
if(! item.hasBeenRead){
Typeface type = view.getTypeface();
view.setTypeface(Typeface.create(type, Typeface.BOLD_ITALIC));
}
}
return view;
}
}
//BEGIN_INCLUDE(2_1)
// Method to initialize our list of RSS items.
private ArrayList<RssItem> initializeList(){
ArrayList<RssItem> list = new ArrayList<RssItem>();
list.add(new RssItem("http://www.sciam.com/xml/sciam.xml", "Scientific American"));
list.add(new RssItem("http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml", "BBC"));
list.add(new RssItem("http://www.theonion.com/content/feeds/daily.", "The Onion"));
list.add(new RssItem("http://feeds.engadget.com/weblogsinc/engadget", "Engadget"));
return list;
}
//END_INCLUDE(2_1)
}

View File

@@ -0,0 +1,184 @@
/*
* Copyright (C) 2007 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.codelab.rssexample;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MyRssReader3 extends Activity{
private ArrayList<RssItem> mFeeds;
ListView mRssList;
ArrayAdapter mAdap;
private static final int ADD_ELEMENT_REQUEST = 1;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// Load screen layout.
setContentView(R.layout.main_screen2);
// Populate our list
mFeeds = initializeList();
// Populate ArrayAdapter and bind it to ListView
mRssList = (ListView)findViewById(R.id.rssListView);
mAdap = new RssDataAdapter<RssItem>(this, R.layout.list_element, mFeeds);
mRssList.setAdapter(mAdap);
// Set the last selected item.
// (icicle is only set if this is being restarted).
if(savedInstanceState != null && savedInstanceState.containsKey("lastIndexItem"))
mRssList.setSelection(savedInstanceState.getInteger("lastIndexItem"));
}
// Store our state before we are potentially bumped from memory.
// We'd like to store the current ListView selection.
@Override
protected void onSaveInstanceState(Bundle outState){
int index = mRssList.getSelectedItemIndex();
if(index > -1){
outState.putInteger("lastIndexItem", index);
}
}
// Add our initial menu options. We will tweak this menu when it's loaded swap out
// "start service" or "stop service", depending on whether the service is currently running.
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Always call the superclass implementation to
// provide standard items.
super.onCreateOptionsMenu(menu);
menu.add(0, 0, R.string.menu_option_start, null);
menu.add(0, 1, R.string.menu_option_stop, null);
menu.add(0, 2, R.string.menu_option_add, null);
menu.add(0, 3, R.string.menu_option_delete, null);
menu.add(0, 4, R.string.menu_option_update, null);
return true;
}
// Toggle out start service/stop service depending on whether the service is running.
@Override
public boolean onPrepareOptionsMenu(Menu menu){
return true;
}
// Handle our menu clicks.
@Override
public boolean onOptionsItemSelected(Menu.Item item){
super.onOptionsItemSelected(item);
switch (item.getId()){
case 0: // Start service
showAlert(null, "You clicked 'start'!", "ok", null, false, null);
break;
case 1: // Stop service
showAlert(null, "You clicked stop!", "ok", null, false, null);
break;
case 2: // Add Item
Intent addIntent = new Intent(AddRssItem.class);
// Use an ID so that if we create a "remove item" form we
// can tell which form is returning a value.
startActivityForResult(addIntent, ADD_ELEMENT_REQUEST);
break;
case 3: // Delete item.
if(mRssList.hasFocus()){
Object selectedItem = mRssList.getSelectedItem();
mAdap.removeObject(mRssList.getSelectedItem());
}
break;
case 4: // Update all
showAlert(null, "You clicked 'Update'!", "ok", null, false, null);
break;
default:
showAlert(null, "I have no idea what you clicked!", "ok", null, false, null);
break;
}
return true;
}
// Called by the "Add RSS Item" floating screen when it closes.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if(resultCode == RESULT_OK){
switch (requestCode){
case ADD_ELEMENT_REQUEST:
RssItem newIt = new RssItem(
data.getStringExtra("url").toString(),
data.getStringExtra("title").toString());
mAdap.addObject(newIt);
mRssList.setSelection(mRssList.getCount() - 1);
break;
default:
break;
}
}
}
// Our private ArrayAdapter implementation that returns a bold TextView for
// RSS items that are unread, or a normal TextView for items that have been read.
private class RssDataAdapter<T> extends ArrayAdapter<T> {
public RssDataAdapter(Context context, int resource, List objects) {
super(context, resource, objects);
}
// Here's our only important override--returning the list item.
@Override
public View getView(int position, View convertView, ViewGroup parent){
// Get the item from the underlying array,
// Create a TextView wrapper, and change the typeface, if necessary.
RssItem item = (RssItem)this.getItem(position);
TextView view = new TextView(parent.getContext());
view.setText(item.toString());
if(! item.hasBeenRead){
Typeface type = view.getTypeface();
view.setTypeface(Typeface.create(type, Typeface.BOLD_ITALIC));
}
return view;
}
}
// Method to initialize our list of RSS items.
private ArrayList<RssItem> initializeList(){
ArrayList<RssItem> list = new ArrayList<RssItem>();
list.add(new RssItem("http://www.sciam.com/xml/sciam.xml", "Scientific American"));
list.add(new RssItem("http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml", "BBC"));
list.add(new RssItem("http://feeds.theonion.com/theonion/daily", "The Onion"));
list.add(new RssItem("http://feeds.engadget.com/weblogsinc/engadget", "Engadget"));
return list;
}
}

View File

@@ -0,0 +1,197 @@
/*
* Copyright (C) 2007 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.codelab.rssexample;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.SimpleCursorAdapter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
public class MyRssReader4 extends Activity {
ListView mRssList;
Cursor mCur;
RssCursorAdapter mAdap;
private static final int ADD_ELEMENT_REQUEST = 1;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// Load screen layout.
setContentView(R.layout.main_screen2);
// Populate ArrayAdapter and bind it to ListView
mRssList = (ListView)findViewById(R.id.rssListView);
mCur = managedQuery(RssContentProvider.CONTENT_URI, // Query for all items.
null,
null,
RssContentProvider.DEFAULT_SORT_ORDER);
// BEGIN_INCLUDE(4_1)
mAdap = new RssCursorAdapter(
this,
R.layout.list_element, // Our layout resource.
mCur,
new String[]{RssContentProvider.TITLE}, // Columns to retrieve.
new int[]{R.id.list_item}); // IDs of widgets to display
mRssList.setAdapter(mAdap); // the corresponding column.
// END_INCLUDE(4_1)
// Set the last selected item.
// (icicle is only set if this is being restarted).
if(savedInstanceState != null && savedInstanceState.containsKey("lastIndexItem")){
mRssList.setSelection(savedInstanceState.getInteger("lastIndexItem"));
}
}
// Store our state before we are potentially bumped from memory.
// We'd like to store the current ListView selection.
@Override
protected void onSaveInstanceState(Bundle outState){
int index = mRssList.getSelectedItemIndex();
if(index > -1){
outState.putInteger("lastIndexItem", index);
}
}
// Add our initial menu options. We will tweak this menu when it's loaded swap out
// "start service" or "stop service", depending on whether the service is currently running.
@Override
public boolean onCreateOptionsMenu(Menu menu){
// Always call the superclass implementation to
// provide standard items.
super.onCreateOptionsMenu(menu);
menu.add(0, 0, R.string.menu_option_start, null);
menu.add(0, 1, R.string.menu_option_stop, null);
menu.add(0, 2, R.string.menu_option_add, null);
menu.add(0, 3, R.string.menu_option_delete, null);
menu.add(0, 4, R.string.menu_option_update, null);
return true;
}
// Toggle out start service/stop service depending on whether the service is running.
@Override
public boolean onPrepareOptionsMenu(Menu menu){
return true;
}
// Handle our menu clicks.
@Override
public boolean onOptionsItemSelected(Menu.Item item){
super.onOptionsItemSelected(item);
switch (item.getId()){
case 0: // Start service
showAlert(null, "You clicked 'start'!", "ok", null, false, null);
break;
case 1: // Stop service
showAlert(null, "You clicked stop!", "ok", null, false, null);
break;
case 2: // Add Item
Intent addIntent = new Intent(AddRssItem.class);
// Use an ID so that if we create a "remove item" form we
// can tell which form is returning a value.
startActivityForResult(addIntent, ADD_ELEMENT_REQUEST);
break;
case 3: // Delete item.
if(mRssList.hasFocus()){
int currentSelectionIndex = mRssList.getSelectedItemIndex();
// Create our content URI by adding the ID of the currently selected item using a
// convenience method.
Long itemID = mAdap.getItemId(currentSelectionIndex);
getContentResolver().delete(RssContentProvider.CONTENT_URI.addId(itemID), null);
}
break;
case 4: // Update all
showAlert(null, "You clicked 'Update'!", "ok", null, false, null);
break;
default:
showAlert(null, "I have no idea what you clicked!", "ok", null, false, null);
break;
}
return true;
}
// Called by the "Add RSS Item" floating screen when it closes.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if(resultCode == RESULT_OK){
switch (requestCode){
case ADD_ELEMENT_REQUEST:
ContentValues vals = new ContentValues(4);
vals.put(RssContentProvider.TITLE, data.getStringExtra(RssContentProvider.TITLE));
vals.put(RssContentProvider.URL, data.getStringExtra(RssContentProvider.URL));
vals.put(RssContentProvider.CONTENT, data.getStringExtra(RssContentProvider.CONTENT));
vals.put(RssContentProvider.LAST_UPDATED, data.getIntExtra(RssContentProvider.LAST_UPDATED, 0));
Uri uri = getContentResolver().insert(
RssContentProvider.CONTENT_URI,
vals);
if(uri != null){
mRssList.setSelection(mRssList.getCount() - 1);
}
break;
default:
break;
}
}
}
// Our private ArrayAdapter implementation that returns a bold TextView for
// RSS items that are unread, or a normal TextView for items that have been read.
private class RssCursorAdapter extends SimpleCursorAdapter {
public RssCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to){
super(context, layout, c, from, to);
}
// Here's our only important override--returning the list item.
@Override
public View getView(int position, View convertView, ViewGroup parent){
TextView view = (TextView)super.getView(position, convertView, parent);
if(view != null){
// Now get the hasBeenRead value to determine the font.
int hasBeenReadColumnIndex = getCursor().getColumnIndex(
RssContentProvider.HAS_BEEN_READ);
boolean hasBeenRead = (getCursor().getInt(hasBeenReadColumnIndex) == 1 ? true : false);
if(! hasBeenRead){
Typeface type = view.getTypeface();
view.setTypeface(Typeface.create(type, Typeface.BOLD_ITALIC));
}
}
return view;
}
}
}

View File

@@ -0,0 +1,241 @@
/*
* Copyright (C) 2007 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.codelab.rssexample;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemSelectedListener;
import java.util.logging.Logger;
public class MyRssReader5 extends Activity implements OnItemSelectedListener {
private ListView mRssList;
private Cursor mCur;
private RssCursorAdapter mAdap;
private WebView mWebView;
private static final int ADD_ELEMENT_REQUEST = 1;
private Logger mLogger = Logger.getLogger(this.getPackageName());
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//
// Load screen layout.
setContentView(R.layout.main_screen2);
// Populate ArrayAdapter and bind it to ListView
mRssList = (ListView)findViewById(R.id.rssListView);
mRssList.setOnItemSelectedListener(this);
mWebView = (WebView)findViewById(R.id.rssWebView);
mCur = managedQuery(RssContentProvider.CONTENT_URI, // Query for all items.
null,
null,
RssContentProvider.DEFAULT_SORT_ORDER);
mAdap = new RssCursorAdapter(
this,
R.layout.list_element, // Our layout resource.
mCur,
new String[]{RssContentProvider.TITLE}, // Columns to retrieve.
new int[]{R.id.list_item}); // IDs of widgets to display
mRssList.setAdapter(mAdap); // the corresponding column.
// Set the last selected item.
// (icicle is only set if this is being restarted).
if(savedInstanceState != null && savedInstanceState.containsKey("lastIndexItem")){
mRssList.setSelection(savedInstanceState.getInteger("lastIndexItem"));
}
}
//BEGIN_INCLUDE(5_4)
// Listener to listen for list selection changes, and send the new text to
// the web view.
public void onItemSelected(AdapterView parent, View v, int position, long id){
// Need to nest this in a try block because we get called sometimes
// with the index of a recently deleted item.
String content = "";
try{
content = mCur.getString(mCur.getColumnIndex(RssContentProvider.CONTENT));
mLogger.info("MyRssReader5 content string:" + content);
}
catch (Exception e){
// This method is sometimes called after a backing data item
// is deleted. In that case, we don't want to throw an error.
mLogger.warning("MyRssReader5.onItemSelected() couldn't get the content" +
"from the cursor " + e.getMessage());
}
mWebView.loadData(content, "text/html", "utf-8");
}
//END_INCLUDE(5_4)
public void onNothingSelected(AdapterView parent){
mWebView.loadData("<html><body><p>No selection chosen</p></body></html>", "text/html", "utf-8");
}
// Store our state before we are potentially bumped from memory.
// We'd like to store the current ListView selection.
@Override
protected void onSaveInstanceState(Bundle outState){
int index = mRssList.getSelectedItemIndex();
if(index > -1){
outState.putInteger("lastIndexItem", index);
}
}
// Add our initial menu options. We will tweak this menu when it's loaded swap out
// "start service" or "stop service", depending on whether the service is currently running.
@Override
public boolean onCreateOptionsMenu(Menu menu){
// Always call the superclass implementation to
// provide standard items.
super.onCreateOptionsMenu(menu);
menu.add(0, 0, R.string.menu_option_start, null);
menu.add(0, 1, R.string.menu_option_stop, null);
menu.add(0, 2, R.string.menu_option_add, null);
menu.add(0, 3, R.string.menu_option_delete, null);
menu.add(0, 4, R.string.menu_option_update, null);
return true;
}
// Toggle out start service/stop service depending on whether the service is running.
@Override
public boolean onPrepareOptionsMenu(Menu menu){
return true;
}
// Handle our menu clicks.
@Override
public boolean onOptionsItemSelected(Menu.Item item){
super.onOptionsItemSelected(item);
switch (item.getId()){
case 0: // Start service
Intent basicStartIntent = new Intent(RssService.class);
startService(basicStartIntent);
break;
case 1: // Stop service
Intent stopIntent = new Intent(RssService.class);
stopService(stopIntent);
break;
case 2: // Add Item
Intent addIntent = new Intent(AddRssItem.class);
// Use an ID so that if we create a "remove item" form we
// can tell which form is returning a value.
startActivityForResult(addIntent, ADD_ELEMENT_REQUEST);
break;
case 3: // Delete item.
if(mRssList.hasFocus()){
int currentSelectionIndex = mRssList.getSelectedItemIndex();
mLogger.info("MyRssReader5.onOptionsItemSelected(): Deleting list member:" +
mRssList.getSelectedItemIndex());
// Create our content URI by adding the ID of the currently selected item using a
// convenience method.
Long itemID = mAdap.getItemId(currentSelectionIndex);
getContentResolver().delete(RssContentProvider.CONTENT_URI.addId(itemID), null);
}
break;
case 4: // Requery all
Bundle startupVals = new Bundle(1);
startupVals.putBoolean(RssService.REQUERY_KEY, true);
Intent requeryIntent = new Intent(RssService.class);
startService(requeryIntent, startupVals);
break;
default:
showAlert(null, "I have no idea what you clicked!", "ok", null, false, null);
break;
}
return true;
}
// Called by the "Add RSS Item" floating screen when it closes.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
if(resultCode == RESULT_OK){
switch (requestCode){
case ADD_ELEMENT_REQUEST:
ContentValues vals = new ContentValues(5);
vals.put(RssContentProvider.TITLE, data.getStringExtra(RssContentProvider.TITLE));
vals.put(RssContentProvider.URL, data.getStringExtra(RssContentProvider.URL));
vals.put(RssContentProvider.CONTENT, data.getStringExtra(RssContentProvider.CONTENT));
vals.put(RssContentProvider.LAST_UPDATED, data.getIntExtra(RssContentProvider.LAST_UPDATED, 0));
Uri uri = getContentResolver().insert(
RssContentProvider.CONTENT_URI,
vals);
if(uri != null){
// Tell the service to requery the service, then set
// it as the active selection.
Bundle startupVals = new Bundle(1);
startupVals.putString(RssService.RSS_URL, data.getStringExtra("URL"));
Intent startIntent = new Intent(RssService.class);
startIntent.putExtras(startupVals);
startService(startIntent);
mRssList.setSelection(mRssList.getCount() - 1);
}
break;
default:
break;
}
}
}
// Our private ArrayAdapter implementation that returns a bold TextView for
// RSS items that are unread, or a normal TextView for items that have been read.
private class RssCursorAdapter extends SimpleCursorAdapter {
public RssCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
}
// Here's our only important override--returning the list item.
@Override
public View getView(int position, View convertView, ViewGroup parent){
TextView view = (TextView)super.getView(position, convertView, parent);
if(view != null){
// Now get the hasBeenRead value to determine the font.
int hasBeenReadColumnIndex = getCursor().getColumnIndex(RssContentProvider.HAS_BEEN_READ);
boolean hasBeenRead = (getCursor().getInt(hasBeenReadColumnIndex) == 1 ? true : false);
if(! hasBeenRead){
Typeface type = view.getTypeface();
view.setTypeface(Typeface.create(type, Typeface.BOLD_ITALIC));
}
}
return view;
}
}
}

View File

@@ -0,0 +1,202 @@
/*
* Copyright (C) 2007 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.codelab.rssexample;
import android.content.ContentProvider;
import android.content.ContentProviderDatabaseHelper;
import android.content.UriMatcher;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.content.ContentValues;
import android.text.TextUtils;
import java.util.logging.Logger;
// Content Provider for RSS feed information. Each row describes a single
// RSS feed. See the public static constants at the end of this class
// to learn what each record contains.
public class RssContentProvider extends ContentProvider {
private Logger mLogger = Logger.getLogger("com.example.codelab.rssexample");
private SQLiteDatabase mDb;
private DatabaseHelper mDbHelper = new DatabaseHelper();
private static final String DATABASE_NAME = "rssitems.db";
private static final String DATABASE_TABLE_NAME = "rssItems";
private static final int DB_VERSION = 1;
private static final int ALL_MESSAGES = 1;
private static final int SPECIFIC_MESSAGE = 2;
// Set up our URL matchers to help us determine what an
// incoming URI parameter is.
private static final UriMatcher URI_MATCHER;
static{
URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
URI_MATCHER.addURI("my_rss_item", "rssitem", ALL_MESSAGES);
URI_MATCHER.addURI("my_rss_item", "rssitem/#", SPECIFIC_MESSAGE);
}
// Here's the public URI used to query for RSS items.
public static final Uri CONTENT_URI = Uri.parse( "content://my_rss_item/rssitem");
// Here are our column name constants, used to query for field values.
public static final String ID = "_id";
public static final String URL = "url";
public static final String TITLE = "title";
public static final String HAS_BEEN_READ = "hasbeenread";
public static final String CONTENT = "rawcontent";
public static final String LAST_UPDATED = "lastupdated";
public static final String DEFAULT_SORT_ORDER = TITLE + " DESC";
// Database creation/version management helper.
// Create it statically because we don't need to have customized instances.
private static class DatabaseHelper extends ContentProviderDatabaseHelper{
@Override
public void onCreate(SQLiteDatabase db){
try{
String sql = "CREATE TABLE " + DATABASE_TABLE_NAME + "(" +
ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
URL + " TEXT," +
TITLE + " TEXT," +
HAS_BEEN_READ + " BOOLEAN DEFAULT 0," +
CONTENT + " TEXT," +
LAST_UPDATED + " INTEGER DEFAULT 0);";
Logger.getLogger("com.example.codelab.rssexample").info("DatabaseHelper.onCreate(): SQL statement: " + sql);
db.execSQL(sql);
Logger.getLogger("com.example.codelab.rssexample").info("DatabaseHelper.onCreate(): Created a database");
} catch (SQLException e) {
Logger.getLogger("com.example.codelab.rssexample").warning("DatabaseHelper.onCreate(): Couldn't create a database!");
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
// Don't have any upgrades yet, so if this gets called for some reason we'll
// just drop the existing table, and recreate the database with the
// standard method.
db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE_NAME + ";");
}
}
@Override
public boolean onCreate() {
// First we need to open the database. If this is our first time,
// the attempt to retrieve a database will throw
// FileNotFoundException, and we will then create the database.
final Context con = getContext();
try{
mDb = mDbHelper.openDatabase(getContext(), DATABASE_NAME, null, DB_VERSION);
mLogger.info("RssContentProvider.onCreate(): Opened a database");
} catch (Exception ex) {
return false;
}
if(mDb == null){
return false;
} else {
return true;
}
}
// Convert the URI into a custom MIME type.
// Our UriMatcher will parse the URI to decide whether the
// URI is for a single item or a list.
@Override
public String getType(Uri uri) {
switch (URI_MATCHER.match(uri)){
case ALL_MESSAGES:
return "vnd.android.cursor.dir/rssitem"; // List of items.
case SPECIFIC_MESSAGE:
return "vnd.android.cursor.item/rssitem"; // Specific item.
default:
return null;
}
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String groupBy, String having, String sortOrder) {
// We won't bother checking the validity of params here, but you should!
// SQLiteQueryBuilder is the helper class that creates the
// proper SQL syntax for us.
SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
// Set the table we're querying.
qBuilder.setTables(DATABASE_TABLE_NAME);
// If the query ends in a specific record number, we're
// being asked for a specific record, so set the
// WHERE clause in our query.
if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
qBuilder.appendWhere("_id=" + uri.getPathLeafId());
}
// Set sort order. If none specified, use default.
if(TextUtils.isEmpty(sortOrder)){
sortOrder = DEFAULT_SORT_ORDER;
}
// Make the query.
Cursor c = qBuilder.query(mDb,
projection,
selection,
selectionArgs,
groupBy,
having,
sortOrder);
c.setNotificationUri(getContext().getContentResolver(), uri);
return c;
}
@Override
public int update(Uri uri, ContentValues values, String whereClause) {
// NOTE Argument checking code omitted. Check your parameters!
int updateCount = mDb.update(DATABASE_TABLE_NAME, values, whereClause);
// Notify any listeners and return the updated row count.
getContext().getContentResolver().notifyUpdate(uri, null);
return updateCount;
}
@Override
public Uri insert(Uri requestUri, ContentValues initialValues) {
// NOTE Argument checking code omitted. Check your parameters! Check that
// your row addition request succeeded!
long rowId = -1;
rowId = mDb.insert(DATABASE_TABLE_NAME, "rawcontent", initialValues);
Uri newUri = CONTENT_URI.addId(rowId);
// Notify any listeners and return the URI of the new row.
getContext().getContentResolver().notifyInsert(CONTENT_URI, null);
return newUri;
}
@Override
public int delete(Uri uri, String where) {
// NOTE Argument checking code omitted. Check your parameters!
int rowCount = mDb.delete(DATABASE_TABLE_NAME, ID + " = " + uri.getPathLeafId());
// Notify any listeners and return the deleted row count.
getContext().getContentResolver().notifyDelete(uri, null);
return rowCount;
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2007 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.codelab.rssexample;
import java.util.Date;
// Custom class to hold an RSS item.
public class RssItem{
public String url;
public String title;
public boolean hasBeenRead = false;
public String content;
public Date lastUpdated;
public RssItem(String url, String title){
this.url = url;
this.title = title;
}
@Override public String toString(){
return title;
}
}

View File

@@ -0,0 +1,263 @@
/*
* Copyright (C) 2007 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.codelab.rssexample;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Bundle;
import android.database.Cursor;
import android.content.ContentResolver;
import android.os.Handler;
import android.text.TextUtils;
import java.io.BufferedReader;
import java.net.URL;
import java.net.MalformedURLException;
import java.lang.StringBuilder;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.GregorianCalendar;
import java.text.SimpleDateFormat;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.text.ParseException;
public class RssService extends Service implements Runnable{
private Logger mLogger = Logger.getLogger(this.getPackageName());
public static final String REQUERY_KEY = "Requery_All"; // Sent to tell us force a requery.
public static final String RSS_URL = "RSS_URL"; // Sent to tell us to requery a specific item.
private NotificationManager mNM;
private Cursor mCur; // RSS content provider cursor.
private GregorianCalendar mLastCheckedTime; // Time we last checked our feeds.
private final String LAST_CHECKED_PREFERENCE = "last_checked";
static final int UPDATE_FREQUENCY_IN_MINUTES = 60;
private Handler mHandler; // Handler to trap our update reminders.
private final int NOTIFY_ID = 1; // Identifies our service icon in the icon tray.
@Override
protected void onCreate(){
// Display an icon to show that the service is running.
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Intent clickIntent = new Intent(Intent.ACTION_MAIN);
clickIntent.setClassName(MyRssReader5.class.getName());
Notification note = new Notification(this, R.drawable.rss_icon, "RSS Service",
clickIntent, null);
mNM.notify(NOTIFY_ID, note);
mHandler = new Handler();
// Create the intent that will be launched if the user clicks the
// icon on the status bar. This will launch our RSS Reader app.
Intent intent = new Intent(MyRssReader.class);
// Get a cursor over the RSS items.
ContentResolver rslv = getContentResolver();
mCur = rslv.query(RssContentProvider.CONTENT_URI, null, null, null, null);
// Load last updated value.
// We store last updated value in preferences.
SharedPreferences pref = getSharedPreferences("", 0);
mLastCheckedTime = new GregorianCalendar();
mLastCheckedTime.setTimeInMillis(pref.getLong(LAST_CHECKED_PREFERENCE, 0));
//BEGIN_INCLUDE(5_1)
// Need to run ourselves on a new thread, because
// we will be making resource-intensive HTTP calls.
// Our run() method will check whether we need to requery
// our sources.
Thread thr = new Thread(null, this, "rss_service_thread");
thr.start();
//END_INCLUDE(5_1)
mLogger.info("RssService created");
}
//BEGIN_INCLUDE(5_3)
// A cheap way to pass a message to tell the service to requery.
@Override
protected void onStart(Intent intent, int startId){
super.onStart(startId, arguments);
Bundle arguments = intent.getExtras();
if(arguments != null) {
if(arguments.containsKey(REQUERY_KEY)) {
queryRssItems();
}
if(arguments.containsKey(RSS_URL)) {
// Typically called after adding a new RSS feed to the list.
queryItem(arguments.getString(RSS_URL));
}
}
}
//END_INCLUDE(5_3)
// When the service is destroyed, get rid of our persistent icon.
@Override
protected void onDestroy(){
mNM.cancel(NOTIFY_ID);
}
// Determines whether the next scheduled check time has passed.
// Loads this value from a stored preference. If it has (or if no
// previous value has been stored), it will requery all RSS feeds;
// otherwise, it will post a delayed reminder to check again after
// now - next_check_time milliseconds.
public void queryIfPeriodicRefreshRequired() {
GregorianCalendar nextCheckTime = new GregorianCalendar();
nextCheckTime = (GregorianCalendar) mLastCheckedTime.clone();
nextCheckTime.add(GregorianCalendar.MINUTE, UPDATE_FREQUENCY_IN_MINUTES);
mLogger.info("last checked time:" + mLastCheckedTime.toString() + " Next checked time: " + nextCheckTime.toString());
if(mLastCheckedTime.before(nextCheckTime)) {
queryRssItems();
} else {
// Post a message to query again when we get to the next check time.
long timeTillNextUpdate = mLastCheckedTime.getTimeInMillis() - GregorianCalendar.getInstance().getTimeInMillis();
mHandler.postDelayed(this, 1000 * 60 * UPDATE_FREQUENCY_IN_MINUTES);
}
}
// Query all feeds. If the new feed has a newer pubDate than the previous,
// then update it.
void queryRssItems(){
mLogger.info("Querying Rss feeds...");
// The cursor might have gone stale. Requery to be sure.
// We need to call next() after a requery to get to the
// first record.
mCur.requery();
while (mCur.next()){
// Get the URL for the feed from the cursor.
int urlColumnIndex = mCur.getColumnIndex(RssContentProvider.URL);
String url = mCur.getString(urlColumnIndex);
queryItem(url);
}
// Reset the global "last checked" time
mLastCheckedTime.setTimeInMillis(System.currentTimeMillis());
// Post a message to query again in [update_frequency] minutes
mHandler.postDelayed(this, 1000 * 60 * UPDATE_FREQUENCY_IN_MINUTES);
}
// Query an individual RSS feed. Returns true if successful, false otherwise.
private boolean queryItem(String url) {
try {
URL wrappedUrl = new URL(url);
String rssFeed = readRss(wrappedUrl);
mLogger.info("RSS Feed " + url + ":\n " + rssFeed);
if(TextUtils.isEmpty(rssFeed)) {
return false;
}
// Parse out the feed update date, and compare to the current version.
// If feed update time is newer, or zero (if never updated, for new
// items), then update the content, date, and hasBeenRead fields.
// lastUpdated = <rss><channel><pubDate>value</pubDate></channel></rss>.
// If that value doesn't exist, the current date is used.
GregorianCalendar feedPubDate = parseRssDocPubDate(rssFeed);
GregorianCalendar lastUpdated = new GregorianCalendar();
int lastUpdatedColumnIndex = mCur.getColumnIndex(RssContentProvider.LAST_UPDATED);
lastUpdated.setTimeInMillis(mCur.getLong(lastUpdatedColumnIndex));
if(lastUpdated.getTimeInMillis() == 0 ||
lastUpdated.before(feedPubDate) && !TextUtils.isEmpty(rssFeed)) {
// Get column indices.
int contentColumnIndex = mCur.getColumnIndex(RssContentProvider.CONTENT);
int updatedColumnIndex = mCur.getColumnIndex(RssContentProvider.HAS_BEEN_READ);
// Update values.
mCur.updateString(contentColumnIndex, rssFeed);
mCur.updateLong(lastUpdatedColumnIndex, feedPubDate.getTimeInMillis());
mCur.updateInt(updatedColumnIndex, 0);
mCur.commitUpdates();
}
} catch (MalformedURLException ex) {
mLogger.warning("Error in queryItem: Bad url");
return false;
}
return true;
}
// BEGIN_INCLUDE(5_2)
// Get the <pubDate> content from a feed and return a
// GregorianCalendar version of the date.
// If the element doesn't exist or otherwise can't be
// found, return a date of 0 to force a refresh.
private GregorianCalendar parseRssDocPubDate(String xml){
GregorianCalendar cal = new GregorianCalendar();
cal.setTimeInMillis(0);
String patt ="<[\\s]*pubDate[\\s]*>(.+?)</pubDate[\\s]*>";
Pattern p = Pattern.compile(patt);
Matcher m = p.matcher(xml);
try {
if(m.find()) {
mLogger.info("pubDate: " + m.group());
SimpleDateFormat pubDate = new SimpleDateFormat();
cal.setTime(pubDate.parse(m.group(1)));
}
} catch(ParseException ex) {
mLogger.warning("parseRssDocPubDate couldn't find a <pubDate> tag. Returning default value.");
}
return cal;
}
// Read the submitted RSS page.
String readRss(URL url){
String html = "<html><body><h2>No data</h2></body></html>";
try {
mLogger.info("URL is:" + url.toString());
BufferedReader inStream =
new BufferedReader(new InputStreamReader(url.openStream()),
1024);
String line;
StringBuilder rssFeed = new StringBuilder();
while ((line = inStream.readLine()) != null){
rssFeed.append(line);
}
html = rssFeed.toString();
} catch(IOException ex) {
mLogger.warning("Couldn't open an RSS stream");
}
return html;
}
//END_INCLUDE(5_2)
// Callback we send to ourself to requery all feeds.
public void run() {
queryIfPeriodicRefreshRequired();
}
// Required by Service. We won't implement it here, but need to
// include this basic code.
@Override
public IBinder onBind(Intent intent){
return mBinder;
}
// This is the object that receives RPC calls from clients.See
// RemoteService for a more complete example.
private final IBinder mBinder = new Binder() {
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
return super.onTransact(code, data, reply, flags);
}
};
}