upload android base code part7
This commit is contained in:
parent
4e516ec6ed
commit
841ae54672
25229 changed files with 1709508 additions and 0 deletions
14
android/development/samples/MySampleRss/Android.mk
Normal file
14
android/development/samples/MySampleRss/Android.mk
Normal file
|
@ -0,0 +1,14 @@
|
|||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE_TAGS := samples
|
||||
|
||||
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||
|
||||
LOCAL_PACKAGE_NAME := MyRSSReader
|
||||
|
||||
LOCAL_SDK_VERSION := current
|
||||
|
||||
LOCAL_DEX_PREOPT := false
|
||||
|
||||
##include $(BUILD_PACKAGE)
|
66
android/development/samples/MySampleRss/AndroidManifest.xml
Executable file
66
android/development/samples/MySampleRss/AndroidManifest.xml
Executable file
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<!-- Declare the contents of this Android application. The namespace
|
||||
attribute brings in the Android platform namespace, and the package
|
||||
supplies a unique name for the application. When writing your
|
||||
own application, the package name must be changed from "com.example.*"
|
||||
to come from a domain that you own or have control over. -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.codelab.rssexample">
|
||||
<application android:name="MyRssReader" android:label="My Rss Reader">
|
||||
<activity>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="MyRssReader2" android:label="My Rss Reader V2">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="MyRssReader3" android:label="@string/reader_3_label">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="MyRssReader4" android:label="@string/reader_4_label">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="MyRssReader5" android:label="@string/reader_5_label">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="AddRssItem" android:label="@string/add_item_label" android:theme="@android:style/Theme.Dialog"/>
|
||||
<provider android:name="RssContentProvider" android:authorities="my_rss_item" android:multiprocess="true" />
|
||||
<service android:name="RssService" android:process=":myrss"/>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
|
BIN
android/development/samples/MySampleRss/res/drawable/rss_icon.PNG
Executable file
BIN
android/development/samples/MySampleRss/res/drawable/rss_icon.PNG
Executable file
Binary file not shown.
After Width: | Height: | Size: 285 B |
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent">
|
||||
|
||||
<TextView android:id="@+id/title_label"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:text="@string/add_item_title"/>
|
||||
<EditText android:id="@+id/title_textbox"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_toRightOf="@id/title_label"/>
|
||||
<EditText android:id="@+id/url_textbox"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_below="@id/title_textbox"
|
||||
android:layout_alignLeft="@id/title_textbox"/>
|
||||
|
||||
<!-- Note that we declare url_label *after* url_textbox in this file
|
||||
because it references url_textbox, and a resource file is
|
||||
evaluated sequentially. -->
|
||||
<TextView android:id="@+id/url_label"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_toRightOf="url_textbox"
|
||||
android:layout_alignTop="@id/url_textbox"
|
||||
android:text="@string/add_item_url"/>
|
||||
<Button android:id="@+id/submit"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:text="@string/submit"/>
|
||||
<Button android:id="@+id/cancel"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_toLeftOf="@id/submit"
|
||||
android:layout_alignTop="@id/submit"
|
||||
android:text="@string/cancel"/>
|
||||
</RelativeLayout>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/list_item"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"/>
|
35
android/development/samples/MySampleRss/res/layout/main_screen.xml
Executable file
35
android/development/samples/MySampleRss/res/layout/main_screen.xml
Executable file
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:scrollbars="vertical">
|
||||
|
||||
<ListView android:id="@+id/rssListView"
|
||||
android:layout_height="0px"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="#00CC00"/>
|
||||
|
||||
<WebView android:id="@+id/rssWebView"
|
||||
android:background="#77CC0000"
|
||||
android:layout_height="0px"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:scrollbars="vertical">
|
||||
|
||||
<ListView android:id="@+id/rssListView"
|
||||
android:layout_height="0px"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="#9900FF00"/>
|
||||
|
||||
<WebView android:id="@+id/rssWebView"
|
||||
android:layout_height="0px"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_weight="2"/>
|
||||
</LinearLayout>
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
<string name="menu_option_start">Start RSS Service</string>
|
||||
<string name="menu_option_stop">Stop RSS Service</string>
|
||||
<string name="menu_option_add">Add New Feed</string>
|
||||
<string name="menu_option_delete">Delete Feed</string>
|
||||
<string name="menu_option_update">Update All Feeds</string>
|
||||
<string name="add_item_title">Title</string>
|
||||
<string name="add_item_url">URL</string>
|
||||
<string name="submit">Submit</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="reader_3_label">MyRssReader3</string>
|
||||
<string name="reader_4_label">MyRssReader4</string>
|
||||
<string name="reader_5_label">MyRssReader5</string>
|
||||
<string name="add_item_label">Add a new Feed</string>
|
||||
</resources>
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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", null);
|
||||
}
|
||||
//END_INCLUDE(5_4)
|
||||
|
||||
public void onNothingSelected(AdapterView parent){
|
||||
mWebView.loadData("<html><body><p>No selection chosen</p></body></html>", "text/html", null);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue