Eric Kok
12 years ago
25 changed files with 885 additions and 673 deletions
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:orientation="horizontal" |
||||
android:baselineAligned="false" |
||||
tools:context=".RssfeedsActivity" > |
||||
|
||||
<fragment |
||||
android:id="@+id/rssfeeds_list" |
||||
android:layout_width="0dip" |
||||
android:layout_height="match_parent" |
||||
android:layout_weight="1" |
||||
class="org.transdroid.core.gui.rss.RssFeedsFragment_" |
||||
tools:layout="@layout/fragment_rssfeeds" /> |
||||
|
||||
<fragment |
||||
android:id="@+id/rssitems_list" |
||||
android:layout_width="0dip" |
||||
android:layout_height="match_parent" |
||||
android:layout_weight="1" |
||||
class="org.transdroid.core.gui.rss.RssItemsFragment_" |
||||
tools:layout="@layout/fragment_rssitems" /> |
||||
|
||||
</LinearLayout> |
@ -1,149 +0,0 @@
@@ -1,149 +0,0 @@
|
||||
/* |
||||
* Taken from the 'Learning Android' project,; |
||||
* released as Public Domain software at |
||||
* http://github.com/digitalspaghetti/learning-android
|
||||
*/ |
||||
package org.ifies.android.sax; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Date; |
||||
import java.util.List; |
||||
|
||||
import android.os.Parcel; |
||||
import android.os.Parcelable; |
||||
|
||||
public class Channel implements Parcelable { |
||||
|
||||
public Channel() { |
||||
setCategories(new ArrayList<String>()); |
||||
setItems(new ArrayList<Item>()); |
||||
} |
||||
|
||||
public void setId(int id) { |
||||
m_Id = id; |
||||
} |
||||
public int getId() { |
||||
return m_Id; |
||||
} |
||||
|
||||
public void setTitle(String title) { |
||||
m_Title = title; |
||||
} |
||||
|
||||
public String getTitle() { |
||||
return m_Title; |
||||
} |
||||
|
||||
public void setLink(String link) { |
||||
m_Link = link; |
||||
} |
||||
|
||||
public String getLink() { |
||||
return m_Link; |
||||
} |
||||
|
||||
public void setDescription(String description) { |
||||
m_Description = description; |
||||
} |
||||
|
||||
public String getDescription() { |
||||
return m_Description; |
||||
} |
||||
|
||||
public void setPubDate(Date date) { |
||||
m_PubDate = date; |
||||
} |
||||
|
||||
public Date getPubDate() { |
||||
return m_PubDate; |
||||
} |
||||
|
||||
public void setLastBuildDate(long lastBuildDate) { |
||||
m_LastBuildDate = lastBuildDate; |
||||
} |
||||
|
||||
public long getLastBuildDate() { |
||||
return m_LastBuildDate; |
||||
} |
||||
|
||||
public void setCategories(List<String> categories) { |
||||
m_Categories = categories; |
||||
} |
||||
|
||||
public void addCategory(String category) { |
||||
m_Categories.add(category); |
||||
} |
||||
|
||||
public List<String> getCategories() { |
||||
return m_Categories; |
||||
} |
||||
|
||||
public void setItems(List<Item> items) { |
||||
m_Items = items; |
||||
} |
||||
|
||||
public void addItem(Item item) { |
||||
m_Items.add(item); |
||||
} |
||||
|
||||
public List<Item> getItems() { |
||||
return m_Items; |
||||
} |
||||
|
||||
public void setImage(String image) { |
||||
m_Image = image; |
||||
} |
||||
|
||||
public String getImage() { |
||||
return m_Image; |
||||
} |
||||
|
||||
private int m_Id; |
||||
private String m_Title; |
||||
private String m_Link; |
||||
private String m_Description; |
||||
private Date m_PubDate; |
||||
private long m_LastBuildDate; |
||||
private List<String> m_Categories; |
||||
private List<Item> m_Items; |
||||
private String m_Image; |
||||
|
||||
@Override |
||||
public int describeContents() { |
||||
return 0; |
||||
} |
||||
@Override |
||||
public void writeToParcel(Parcel out, int flags) { |
||||
out.writeInt(m_Id); |
||||
out.writeString(m_Title); |
||||
out.writeString(m_Link); |
||||
out.writeString(m_Description); |
||||
out.writeLong(m_PubDate == null? -1: m_PubDate.getTime()); |
||||
out.writeLong(m_LastBuildDate); |
||||
out.writeStringList(m_Categories); |
||||
out.writeTypedList(m_Items); |
||||
out.writeString(m_Image); |
||||
} |
||||
public static final Parcelable.Creator<Channel> CREATOR = new Parcelable.Creator<Channel>() { |
||||
public Channel createFromParcel(Parcel in) { |
||||
return new Channel(in); |
||||
} |
||||
public Channel[] newArray(int size) { |
||||
return new Channel[size]; |
||||
} |
||||
}; |
||||
private Channel(Parcel in) { |
||||
m_Id = in.readInt(); |
||||
m_Title = in.readString(); |
||||
m_Link = in.readString(); |
||||
m_Description = in.readString(); |
||||
long pubDate = in.readLong(); |
||||
m_PubDate = pubDate == -1? null: new Date(pubDate); |
||||
m_LastBuildDate = in.readLong(); |
||||
m_Categories = new ArrayList<String>(); |
||||
in.readTypedList(m_Items, Item.CREATOR); |
||||
in.readStringList(m_Categories); |
||||
m_Image = in.readString(); |
||||
} |
||||
|
||||
} |
@ -1,146 +0,0 @@
@@ -1,146 +0,0 @@
|
||||
/* |
||||
* Taken from the 'Learning Android' project,; |
||||
* released as Public Domain software at |
||||
* http://github.com/digitalspaghetti/learning-android
|
||||
*/ |
||||
package org.ifies.android.sax; |
||||
|
||||
import java.util.Date; |
||||
|
||||
import android.os.Parcel; |
||||
import android.os.Parcelable; |
||||
|
||||
public class Item implements Comparable<Item>, Parcelable { |
||||
|
||||
public void setId(int id) { |
||||
this._id = id; |
||||
} |
||||
|
||||
public int getId() { |
||||
return _id; |
||||
} |
||||
|
||||
public void setTitle(String title) { |
||||
this.title = title; |
||||
} |
||||
|
||||
public String getTitle() { |
||||
return this.title; |
||||
} |
||||
|
||||
public void setDescription(String description) { |
||||
this.description = description; |
||||
} |
||||
|
||||
public String getDescription() { |
||||
return this.description; |
||||
} |
||||
|
||||
public void setLink(String link) { |
||||
this.link = link; |
||||
} |
||||
|
||||
public String getLink() { |
||||
return this.link; |
||||
} |
||||
|
||||
public void setPubdate(Date pubdate) { |
||||
this.pubDate = pubdate; |
||||
} |
||||
|
||||
public Date getPubdate() { |
||||
return this.pubDate; |
||||
} |
||||
|
||||
public void setEnclosureUrl(String enclosureUrl) { |
||||
this.enclosureUrl = enclosureUrl; |
||||
} |
||||
|
||||
public void setEnclosureLength(long enclosureLength) { |
||||
this.enclosureLength = enclosureLength; |
||||
} |
||||
|
||||
public void setEnclosureType(String enclosureType) { |
||||
this.enclosureType = enclosureType; |
||||
} |
||||
|
||||
public String getEnclosureUrl() { |
||||
return this.enclosureUrl; |
||||
} |
||||
|
||||
public String getEnclosureType() { |
||||
return this.enclosureType; |
||||
} |
||||
|
||||
public long getEnclosureLength() { |
||||
return this.enclosureLength; |
||||
} |
||||
|
||||
private int _id; |
||||
private String title; |
||||
private String link; |
||||
private String description; |
||||
private Date pubDate; |
||||
private String enclosureUrl; |
||||
private String enclosureType; |
||||
private long enclosureLength; |
||||
|
||||
/** |
||||
* Returns 'the' item link, which preferably is the enclosure url, but otherwise the link (or null if that is empty too) |
||||
* @return A single link url to be used |
||||
*/ |
||||
public String getTheLink() { |
||||
if (this.getEnclosureUrl() != null) { |
||||
return this.getEnclosureUrl(); |
||||
} else { |
||||
return this.getLink(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* CompareTo is used to compare (and sort) item based on their publication dates |
||||
*/ |
||||
@Override |
||||
public int compareTo(Item another) { |
||||
if (another == null || this.pubDate == null || another.getPubdate() == null) { |
||||
return 0; |
||||
} |
||||
return this.pubDate.compareTo(another.getPubdate()); |
||||
} |
||||
|
||||
@Override |
||||
public int describeContents() { |
||||
return 0; |
||||
} |
||||
@Override |
||||
public void writeToParcel(Parcel out, int flags) { |
||||
out.writeInt(_id); |
||||
out.writeString(title); |
||||
out.writeString(link); |
||||
out.writeString(description); |
||||
out.writeLong(pubDate == null? -1: pubDate.getTime()); |
||||
out.writeString(enclosureUrl); |
||||
out.writeString(enclosureType); |
||||
out.writeLong(enclosureLength); |
||||
} |
||||
public static final Parcelable.Creator<Item> CREATOR = new Parcelable.Creator<Item>() { |
||||
public Item createFromParcel(Parcel in) { |
||||
return new Item(in); |
||||
} |
||||
public Item[] newArray(int size) { |
||||
return new Item[size]; |
||||
} |
||||
}; |
||||
private Item(Parcel in) { |
||||
_id = in.readInt(); |
||||
title = in.readString(); |
||||
link = in.readString(); |
||||
description = in.readString(); |
||||
long pubDateIn = in.readLong(); |
||||
pubDate = pubDateIn == -1? null: new Date(pubDateIn); |
||||
enclosureUrl = in.readString(); |
||||
enclosureType = in.readString(); |
||||
enclosureLength = in.readLong(); |
||||
} |
||||
|
||||
} |
@ -1,237 +0,0 @@
@@ -1,237 +0,0 @@
|
||||
/* |
||||
* Taken from the 'Learning Android' project,; |
||||
* released as Public Domain software at |
||||
* http://github.com/digitalspaghetti/learning-android
|
||||
* and modified heavily for Transdroid |
||||
*/ |
||||
package org.ifies.android.sax; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Date; |
||||
|
||||
import javax.xml.parsers.ParserConfigurationException; |
||||
import javax.xml.parsers.SAXParser; |
||||
import javax.xml.parsers.SAXParserFactory; |
||||
|
||||
import org.apache.http.HttpResponse; |
||||
import org.apache.http.client.methods.HttpGet; |
||||
import org.apache.http.conn.scheme.PlainSocketFactory; |
||||
import org.apache.http.conn.scheme.Scheme; |
||||
import org.apache.http.conn.scheme.SchemeRegistry; |
||||
import org.apache.http.impl.client.DefaultHttpClient; |
||||
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; |
||||
import org.apache.http.params.BasicHttpParams; |
||||
import org.apache.http.params.HttpConnectionParams; |
||||
import org.apache.http.params.HttpParams; |
||||
import org.xml.sax.Attributes; |
||||
import org.xml.sax.SAXException; |
||||
import org.xml.sax.helpers.DefaultHandler; |
||||
|
||||
public class RssParser extends DefaultHandler |
||||
{ |
||||
/** |
||||
* The constructor for the RSS Parser |
||||
* @param url |
||||
*/ |
||||
public RssParser(String url) { |
||||
this.urlString = url; |
||||
this.text = new StringBuilder(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the feed as a RssFeed, which is a ListArray |
||||
* @return RssFeed rssFeed |
||||
*/ |
||||
public Channel getChannel() { |
||||
return (this.channel); |
||||
} |
||||
|
||||
public void parse() throws ParserConfigurationException, SAXException, IOException { |
||||
|
||||
DefaultHttpClient httpclient = initialise(); |
||||
HttpResponse result = httpclient.execute(new HttpGet(urlString)); |
||||
//FileInputStream urlInputStream = new FileInputStream("/sdcard/rsstest2.txt");
|
||||
SAXParserFactory spf = SAXParserFactory.newInstance(); |
||||
if (spf != null) { |
||||
SAXParser sp = spf.newSAXParser(); |
||||
sp.parse(result.getEntity().getContent(), this); |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Instantiates an HTTP client that can be used for all requests. |
||||
* @param connectionTimeout The connection timeout in milliseconds |
||||
* @throws DaemonException On conflicting or missing settings |
||||
*/ |
||||
protected DefaultHttpClient initialise() { |
||||
|
||||
SchemeRegistry registry = new SchemeRegistry(); |
||||
registry.register(new Scheme("http", new PlainSocketFactory(), 80)); |
||||
|
||||
HttpParams httpparams = new BasicHttpParams(); |
||||
HttpConnectionParams.setConnectionTimeout(httpparams, 5000); |
||||
HttpConnectionParams.setSoTimeout(httpparams, 5000); |
||||
DefaultHttpClient httpclient = new DefaultHttpClient(new ThreadSafeClientConnManager(httpparams, registry), httpparams); |
||||
|
||||
httpclient.addRequestInterceptor(HttpHelper.gzipRequestInterceptor); |
||||
httpclient.addResponseInterceptor(HttpHelper.gzipResponseInterceptor); |
||||
|
||||
return httpclient; |
||||
|
||||
} |
||||
|
||||
/** |
||||
* By default creates a standard Item (with title, description and links), which |
||||
* may to overriden to add more data. |
||||
* @return A possibly decorated Item instance |
||||
*/ |
||||
protected Item createNewItem() { |
||||
return new Item(); |
||||
} |
||||
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes) { |
||||
|
||||
/** First lets check for the channel */ |
||||
if (localName.equalsIgnoreCase("channel")) { |
||||
this.channel = new Channel(); |
||||
} |
||||
|
||||
/** Now lets check for an item */ |
||||
if (localName.equalsIgnoreCase("item") && (this.channel != null)) { |
||||
this.item = createNewItem(); |
||||
this.channel.addItem(this.item); |
||||
} |
||||
|
||||
/** Now lets check for an image */ |
||||
if (localName.equalsIgnoreCase("image") && (this.channel != null)) { |
||||
this.imgStatus = true; |
||||
} |
||||
|
||||
/** Checking for a enclosure */ |
||||
if (localName.equalsIgnoreCase("enclosure")) { |
||||
/** Lets check we are in an item */ |
||||
if (this.item != null && attributes != null && attributes.getLength() > 0) { |
||||
if (attributes.getValue("url") != null) { |
||||
this.item.setEnclosureUrl(parseLink(attributes.getValue("url"))); |
||||
} |
||||
if (attributes.getValue("type") != null) { |
||||
this.item.setEnclosureType(attributes.getValue("type")); |
||||
} |
||||
if (attributes.getValue("length") != null) { |
||||
this.item.setEnclosureLength(Long.parseLong(attributes.getValue("length"))); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* This is where we actually parse for the elements contents |
||||
*/ |
||||
@SuppressWarnings("deprecation") |
||||
public void endElement(String uri, String localName, String qName) { |
||||
/** Check we have an RSS Feed */ |
||||
if (this.channel == null) { |
||||
return; |
||||
} |
||||
|
||||
/** Check are at the end of an item */ |
||||
if (localName.equalsIgnoreCase("item")) { |
||||
this.item = null; |
||||
} |
||||
|
||||
/** Check we are at the end of an image */ |
||||
if (localName.equalsIgnoreCase("image")) |
||||
this.imgStatus = false; |
||||
|
||||
/** Now we need to parse which title we are in */ |
||||
if (localName.equalsIgnoreCase("title")) |
||||
{ |
||||
/** We are an item, so we set the item title */ |
||||
if (this.item != null){ |
||||
this.item.setTitle(this.text.toString().trim()); |
||||
/** We are in an image */ |
||||
} else { |
||||
this.channel.setTitle(this.text.toString().trim()); |
||||
} |
||||
} |
||||
|
||||
/** Now we are checking for a link */ |
||||
if (localName.equalsIgnoreCase("link")) { |
||||
/** Check we are in an item **/ |
||||
if (this.item != null) { |
||||
this.item.setLink(parseLink(this.text.toString())); |
||||
/** Check we are in an image */ |
||||
} else if (this.imgStatus) { |
||||
this.channel.setImage(parseLink(this.text.toString())); |
||||
/** Check we are in a channel */ |
||||
} else { |
||||
this.channel.setLink(parseLink(this.text.toString())); |
||||
} |
||||
} |
||||
|
||||
/** Checking for a description */ |
||||
if (localName.equalsIgnoreCase("description")) { |
||||
/** Lets check we are in an item */ |
||||
if (this.item != null) { |
||||
this.item.setDescription(this.text.toString().trim()); |
||||
/** Lets check we are in the channel */ |
||||
} else { |
||||
this.channel.setDescription(this.text.toString().trim()); |
||||
} |
||||
} |
||||
|
||||
/** Checking for a pubdate */ |
||||
if (localName.equalsIgnoreCase("pubDate")) { |
||||
/** Lets check we are in an item */ |
||||
if (this.item != null) { |
||||
try { |
||||
this.item.setPubdate(new Date(Date.parse(this.text.toString().trim()))); |
||||
} catch (Exception e) { |
||||
// Date is malformed (not parsable by Date.parse)
|
||||
} |
||||
/** Lets check we are in the channel */ |
||||
} else { |
||||
try { |
||||
this.channel.setPubDate(new Date(Date.parse(this.text.toString().trim()))); |
||||
} catch (Exception e) { |
||||
// Date is malformed (not parsable by Date.parse)
|
||||
} |
||||
} |
||||
} |
||||
|
||||
/** Check for the category */ |
||||
if (localName.equalsIgnoreCase("category") && (this.item != null)) { |
||||
this.channel.addCategory(this.text.toString().trim()); |
||||
} |
||||
|
||||
addAdditionalData(localName, this.item, this.text.toString()); |
||||
|
||||
this.text.setLength(0); |
||||
} |
||||
|
||||
/** |
||||
* May be overridden to add additional data from tags that are not standard in RSS. |
||||
* Not used by this default RSS style parser. |
||||
* @param localName The tag name |
||||
* @param item The Item we are currently parsing |
||||
* @param text The new text content |
||||
*/ |
||||
protected void addAdditionalData(String localName, Item item, String text) { } |
||||
|
||||
public void characters(char[] ch, int start, int length) { |
||||
this.text.append(ch, start, length); |
||||
} |
||||
|
||||
private String parseLink(String string) { |
||||
return string.trim(); |
||||
} |
||||
|
||||
private String urlString; |
||||
private Channel channel; |
||||
private StringBuilder text; |
||||
private Item item; |
||||
private boolean imgStatus; |
||||
|
||||
} |
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
package org.transdroid.core.gui.rss; |
||||
|
||||
import org.transdroid.core.app.settings.RssfeedSetting; |
||||
import org.transdroid.core.rssparser.Channel; |
||||
import org.transdroid.core.rssparser.Item; |
||||
|
||||
/** |
||||
* A container class that holds RSS feed settings and, after they have been retrieved, the contents as {@link Channel}, |
||||
* the number of new items and an indication of a connection error. |
||||
* @author Eric Kok |
||||
*/ |
||||
public class RssfeedLoader { |
||||
|
||||
private final RssfeedSetting setting; |
||||
private Channel channel = null; |
||||
private int newCount = -1; |
||||
private boolean hasError = false; |
||||
|
||||
public RssfeedLoader(RssfeedSetting setting) { |
||||
this.setting = setting; |
||||
} |
||||
|
||||
public void update(Channel channel, boolean hasError) { |
||||
this.channel = channel; |
||||
this.hasError = hasError; |
||||
if (channel == null || hasError) { |
||||
hasError = true; |
||||
newCount = -1; |
||||
return; |
||||
} |
||||
// Count the number of new items, based on the date that this RSS feed was last viewed by the user
|
||||
newCount = 0; |
||||
for (Item item : channel.getItems()) { |
||||
if (item.getPubdate() == null || setting.getLastViewed() == null |
||||
|| item.getPubdate().after(setting.getLastViewed())) { |
||||
newCount++; |
||||
item.setIsNew(true); |
||||
} else { |
||||
item.setIsNew(true); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public Channel getChannel() { |
||||
return channel; |
||||
} |
||||
|
||||
public RssfeedSetting getSetting() { |
||||
return setting; |
||||
} |
||||
|
||||
public int getNewCount() { |
||||
return newCount; |
||||
} |
||||
|
||||
public boolean hasError() { |
||||
return hasError ; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
package org.transdroid.core.gui.rss; |
||||
|
||||
import org.androidannotations.annotations.AfterViews; |
||||
import org.androidannotations.annotations.EActivity; |
||||
import org.androidannotations.annotations.Extra; |
||||
import org.androidannotations.annotations.FragmentById; |
||||
import org.transdroid.core.rssparser.Channel; |
||||
|
||||
import com.actionbarsherlock.app.SherlockFragmentActivity; |
||||
|
||||
@EActivity(resName = "activity_rssfeeds") |
||||
public class RssitemsActivity extends SherlockFragmentActivity { |
||||
|
||||
@Extra |
||||
protected Channel rssfeed = null; |
||||
|
||||
@FragmentById(resName = "rssitems_list") |
||||
protected RssitemsFragment fragmentItems; |
||||
|
||||
@AfterViews |
||||
protected void init() { |
||||
// Get the intent extras and show them to the already loaded fragment
|
||||
fragmentItems.update(rssfeed); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,153 @@
@@ -0,0 +1,153 @@
|
||||
/* |
||||
* Taken from the 'Learning Android' project, released as Public Domain software at |
||||
* http://github.com/digitalspaghetti/learning-android and modified heavily for Transdroid
|
||||
*/ |
||||
package org.transdroid.core.rssparser; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Date; |
||||
import java.util.List; |
||||
|
||||
import android.os.Parcel; |
||||
import android.os.Parcelable; |
||||
|
||||
public class Channel implements Parcelable { |
||||
|
||||
private int id; |
||||
private String title; |
||||
private String link; |
||||
private String description; |
||||
private Date pubDate; |
||||
private long lastBuildDate; |
||||
private List<String> categories; |
||||
private List<Item> items; |
||||
private String image; |
||||
|
||||
public Channel() { |
||||
this.categories = new ArrayList<String>(); |
||||
this.items = new ArrayList<Item>(); |
||||
} |
||||
|
||||
public void setId(int id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public int getId() { |
||||
return id; |
||||
} |
||||
|
||||
public void setTitle(String title) { |
||||
this.title = title; |
||||
} |
||||
|
||||
public String getTitle() { |
||||
return title; |
||||
} |
||||
|
||||
public void setLink(String link) { |
||||
this.link = link; |
||||
} |
||||
|
||||
public String getLink() { |
||||
return link; |
||||
} |
||||
|
||||
public void setDescription(String description) { |
||||
this.description = description; |
||||
} |
||||
|
||||
public String getDescription() { |
||||
return description; |
||||
} |
||||
|
||||
public void setPubDate(Date date) { |
||||
this.pubDate = date; |
||||
} |
||||
|
||||
public Date getPubDate() { |
||||
return pubDate; |
||||
} |
||||
|
||||
public void setLastBuildDate(long lastBuildDate) { |
||||
this.lastBuildDate = lastBuildDate; |
||||
} |
||||
|
||||
public long getLastBuildDate() { |
||||
return lastBuildDate; |
||||
} |
||||
|
||||
public void setCategories(List<String> categories) { |
||||
this.categories = categories; |
||||
} |
||||
|
||||
public void addCategory(String category) { |
||||
this.categories.add(category); |
||||
} |
||||
|
||||
public List<String> getCategories() { |
||||
return categories; |
||||
} |
||||
|
||||
public void setItems(List<Item> items) { |
||||
this.items = items; |
||||
} |
||||
|
||||
public void addItem(Item item) { |
||||
this.items.add(item); |
||||
} |
||||
|
||||
public List<Item> getItems() { |
||||
return items; |
||||
} |
||||
|
||||
public void setImage(String image) { |
||||
this.image = image; |
||||
} |
||||
|
||||
public String getImage() { |
||||
return image; |
||||
} |
||||
|
||||
@Override |
||||
public int describeContents() { |
||||
return 0; |
||||
} |
||||
|
||||
@Override |
||||
public void writeToParcel(Parcel out, int flags) { |
||||
out.writeInt(id); |
||||
out.writeString(title); |
||||
out.writeString(link); |
||||
out.writeString(description); |
||||
out.writeLong(pubDate == null ? -1 : pubDate.getTime()); |
||||
out.writeLong(lastBuildDate); |
||||
out.writeStringList(categories); |
||||
out.writeTypedList(items); |
||||
out.writeString(image); |
||||
} |
||||
|
||||
public static final Parcelable.Creator<Channel> CREATOR = new Parcelable.Creator<Channel>() { |
||||
public Channel createFromParcel(Parcel in) { |
||||
return new Channel(in); |
||||
} |
||||
|
||||
public Channel[] newArray(int size) { |
||||
return new Channel[size]; |
||||
} |
||||
}; |
||||
|
||||
private Channel(Parcel in) { |
||||
id = in.readInt(); |
||||
title = in.readString(); |
||||
link = in.readString(); |
||||
description = in.readString(); |
||||
long pubDateIn = in.readLong(); |
||||
pubDate = pubDateIn == -1 ? null : new Date(pubDateIn); |
||||
lastBuildDate = in.readLong(); |
||||
categories = new ArrayList<String>(); |
||||
in.readTypedList(items, Item.CREATOR); |
||||
in.readStringList(categories); |
||||
image = in.readString(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,157 @@
@@ -0,0 +1,157 @@
|
||||
/* |
||||
* Taken from the 'Learning Android' project, released as Public Domain software at |
||||
* http://github.com/digitalspaghetti/learning-android and modified heavily for Transdroid
|
||||
*/ |
||||
package org.transdroid.core.rssparser; |
||||
|
||||
import java.util.Date; |
||||
|
||||
import android.os.Parcel; |
||||
import android.os.Parcelable; |
||||
|
||||
public class Item implements Parcelable { |
||||
|
||||
private int id; |
||||
private String title; |
||||
private String link; |
||||
private String description; |
||||
private Date pubDate; |
||||
private String enclosureUrl; |
||||
private String enclosureType; |
||||
private long enclosureLength; |
||||
|
||||
/** |
||||
* isNew is not parsed from the RSS feed but may be set using {@link #setIsNew(boolean)} manually |
||||
*/ |
||||
private boolean isNew; |
||||
|
||||
public void setId(int id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public int getId() { |
||||
return id; |
||||
} |
||||
|
||||
public void setTitle(String title) { |
||||
this.title = title; |
||||
} |
||||
|
||||
public String getTitle() { |
||||
return this.title; |
||||
} |
||||
|
||||
public void setDescription(String description) { |
||||
this.description = description; |
||||
} |
||||
|
||||
public String getDescription() { |
||||
return this.description; |
||||
} |
||||
|
||||
public void setLink(String link) { |
||||
this.link = link; |
||||
} |
||||
|
||||
public String getLink() { |
||||
return this.link; |
||||
} |
||||
|
||||
public void setPubdate(Date pubdate) { |
||||
this.pubDate = pubdate; |
||||
} |
||||
|
||||
public Date getPubdate() { |
||||
return this.pubDate; |
||||
} |
||||
|
||||
public void setEnclosureUrl(String enclosureUrl) { |
||||
this.enclosureUrl = enclosureUrl; |
||||
} |
||||
|
||||
public void setEnclosureLength(long enclosureLength) { |
||||
this.enclosureLength = enclosureLength; |
||||
} |
||||
|
||||
public void setEnclosureType(String enclosureType) { |
||||
this.enclosureType = enclosureType; |
||||
} |
||||
|
||||
public String getEnclosureUrl() { |
||||
return this.enclosureUrl; |
||||
} |
||||
|
||||
public String getEnclosureType() { |
||||
return this.enclosureType; |
||||
} |
||||
|
||||
public long getEnclosureLength() { |
||||
return this.enclosureLength; |
||||
} |
||||
|
||||
public void setIsNew(boolean isNew) { |
||||
this.isNew = isNew; |
||||
} |
||||
|
||||
public boolean isNew() { |
||||
return isNew; |
||||
} |
||||
|
||||
/** |
||||
* Returns 'the' item link, which preferably is the enclosure url, but otherwise the link (or null if that is empty |
||||
* too). |
||||
* @return A single link url to be used |
||||
*/ |
||||
public String getTheLink() { |
||||
if (this.getEnclosureUrl() != null) { |
||||
return this.getEnclosureUrl(); |
||||
} else { |
||||
return this.getLink(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int describeContents() { |
||||
return 0; |
||||
} |
||||
|
||||
@Override |
||||
public void writeToParcel(Parcel out, int flags) { |
||||
out.writeInt(id); |
||||
out.writeString(title); |
||||
out.writeString(link); |
||||
out.writeString(description); |
||||
out.writeLong(pubDate == null ? -1 : pubDate.getTime()); |
||||
out.writeString(enclosureUrl); |
||||
out.writeString(enclosureType); |
||||
out.writeLong(enclosureLength); |
||||
out.writeInt(isNew? 1: 0); |
||||
} |
||||
|
||||
public static final Parcelable.Creator<Item> CREATOR = new Parcelable.Creator<Item>() { |
||||
public Item createFromParcel(Parcel in) { |
||||
return new Item(in); |
||||
} |
||||
|
||||
public Item[] newArray(int size) { |
||||
return new Item[size]; |
||||
} |
||||
}; |
||||
|
||||
public Item() { |
||||
} |
||||
|
||||
private Item(Parcel in) { |
||||
id = in.readInt(); |
||||
title = in.readString(); |
||||
link = in.readString(); |
||||
description = in.readString(); |
||||
long pubDateIn = in.readLong(); |
||||
pubDate = pubDateIn == -1 ? null : new Date(pubDateIn); |
||||
enclosureUrl = in.readString(); |
||||
enclosureType = in.readString(); |
||||
enclosureLength = in.readLong(); |
||||
isNew = in.readInt() == 1? true: false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,235 @@
@@ -0,0 +1,235 @@
|
||||
/* |
||||
* Taken from the 'Learning Android' project, released as Public Domain software at |
||||
* http://github.com/digitalspaghetti/learning-android and modified heavily for Transdroid
|
||||
*/ |
||||
package org.transdroid.core.rssparser; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Date; |
||||
|
||||
import javax.xml.parsers.ParserConfigurationException; |
||||
import javax.xml.parsers.SAXParser; |
||||
import javax.xml.parsers.SAXParserFactory; |
||||
|
||||
import org.apache.http.HttpResponse; |
||||
import org.apache.http.client.methods.HttpGet; |
||||
import org.apache.http.conn.scheme.PlainSocketFactory; |
||||
import org.apache.http.conn.scheme.Scheme; |
||||
import org.apache.http.conn.scheme.SchemeRegistry; |
||||
import org.apache.http.impl.client.DefaultHttpClient; |
||||
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; |
||||
import org.apache.http.params.BasicHttpParams; |
||||
import org.apache.http.params.HttpConnectionParams; |
||||
import org.apache.http.params.HttpParams; |
||||
import org.xml.sax.Attributes; |
||||
import org.xml.sax.SAXException; |
||||
import org.xml.sax.helpers.DefaultHandler; |
||||
|
||||
public class RssParser extends DefaultHandler { |
||||
|
||||
private String urlString; |
||||
private Channel channel; |
||||
private StringBuilder text; |
||||
private Item item; |
||||
private boolean imageStatus; |
||||
|
||||
/** |
||||
* The constructor for the RSS parser; call {@link #parse()} to synchronously create an HTTP connection and parse |
||||
* the RSS feed contents. The results can be retrieved with {@link #getChannel()}. |
||||
* @param url |
||||
*/ |
||||
public RssParser(String url) { |
||||
this.urlString = url; |
||||
this.text = new StringBuilder(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the loaded RSS feed as channel which contains the individual {@link Item}s |
||||
* @return A channel object that ocntains the feed details and individual items |
||||
*/ |
||||
public Channel getChannel() { |
||||
return this.channel; |
||||
} |
||||
|
||||
/** |
||||
* Initialises an HTTP connection, retrieves the content and parses the RSS feed as standard XML. |
||||
* @throws ParserConfigurationException Thrown if the SX parser is not working corectly |
||||
* @throws SAXException Thrown if the SAX parser can encounters non-standard XML content |
||||
* @throws IOException Thrown if the RSS feed content can not be retrieved, such as when no connection is available |
||||
*/ |
||||
public void parse() throws ParserConfigurationException, SAXException, IOException { |
||||
|
||||
DefaultHttpClient httpclient = initialise(); |
||||
HttpResponse result = httpclient.execute(new HttpGet(urlString)); |
||||
SAXParserFactory spf = SAXParserFactory.newInstance(); |
||||
if (spf != null) { |
||||
SAXParser sp = spf.newSAXParser(); |
||||
sp.parse(result.getEntity().getContent(), this); |
||||
} |
||||
|
||||
} |
||||
|
||||
private DefaultHttpClient initialise() { |
||||
|
||||
SchemeRegistry registry = new SchemeRegistry(); |
||||
registry.register(new Scheme("http", new PlainSocketFactory(), 80)); |
||||
|
||||
HttpParams httpparams = new BasicHttpParams(); |
||||
HttpConnectionParams.setConnectionTimeout(httpparams, 5000); |
||||
HttpConnectionParams.setSoTimeout(httpparams, 5000); |
||||
DefaultHttpClient httpclient = new DefaultHttpClient(new ThreadSafeClientConnManager(httpparams, registry), |
||||
httpparams); |
||||
|
||||
httpclient.addRequestInterceptor(HttpHelper.gzipRequestInterceptor); |
||||
httpclient.addResponseInterceptor(HttpHelper.gzipResponseInterceptor); |
||||
|
||||
return httpclient; |
||||
|
||||
} |
||||
|
||||
/** |
||||
* By default creates a standard Item (with title, description and links), which may to overridden to add more data |
||||
* (i.e. custom tags that a feed may supply). |
||||
* @return A possibly decorated Item instance |
||||
*/ |
||||
protected Item createNewItem() { |
||||
return new Item(); |
||||
} |
||||
|
||||
@Override |
||||
public final void startElement(String uri, String localName, String qName, Attributes attributes) { |
||||
|
||||
/** First lets check for the channel */ |
||||
if (localName.equalsIgnoreCase("channel")) { |
||||
this.channel = new Channel(); |
||||
} |
||||
|
||||
/** Now lets check for an item */ |
||||
if (localName.equalsIgnoreCase("item") && (this.channel != null)) { |
||||
this.item = createNewItem(); |
||||
this.channel.addItem(this.item); |
||||
} |
||||
|
||||
/** Now lets check for an image */ |
||||
if (localName.equalsIgnoreCase("image") && (this.channel != null)) { |
||||
this.imageStatus = true; |
||||
} |
||||
|
||||
/** Checking for a enclosure */ |
||||
if (localName.equalsIgnoreCase("enclosure")) { |
||||
/** Lets check we are in an item */ |
||||
if (this.item != null && attributes != null && attributes.getLength() > 0) { |
||||
if (attributes.getValue("url") != null) { |
||||
this.item.setEnclosureUrl(attributes.getValue("url").trim()); |
||||
} |
||||
if (attributes.getValue("type") != null) { |
||||
this.item.setEnclosureType(attributes.getValue("type")); |
||||
} |
||||
if (attributes.getValue("length") != null) { |
||||
this.item.setEnclosureLength(Long.parseLong(attributes.getValue("length"))); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* This is where we actually parse for the elements contents |
||||
*/ |
||||
@SuppressWarnings("deprecation") |
||||
public final void endElement(String uri, String localName, String qName) { |
||||
/** Check we have an RSS Feed */ |
||||
if (this.channel == null) { |
||||
return; |
||||
} |
||||
|
||||
/** Check are at the end of an item */ |
||||
if (localName.equalsIgnoreCase("item")) { |
||||
this.item = null; |
||||
} |
||||
|
||||
/** Check we are at the end of an image */ |
||||
if (localName.equalsIgnoreCase("image")) |
||||
this.imageStatus = false; |
||||
|
||||
/** Now we need to parse which title we are in */ |
||||
if (localName.equalsIgnoreCase("title")) { |
||||
/** We are an item, so we set the item title */ |
||||
if (this.item != null) { |
||||
this.item.setTitle(this.text.toString().trim()); |
||||
/** We are in an image */ |
||||
} else { |
||||
this.channel.setTitle(this.text.toString().trim()); |
||||
} |
||||
} |
||||
|
||||
/** Now we are checking for a link */ |
||||
if (localName.equalsIgnoreCase("link")) { |
||||
/** Check we are in an item **/ |
||||
if (this.item != null) { |
||||
this.item.setLink(this.text.toString().trim()); |
||||
/** Check we are in an image */ |
||||
} else if (this.imageStatus) { |
||||
this.channel.setImage(this.text.toString().trim()); |
||||
/** Check we are in a channel */ |
||||
} else { |
||||
this.channel.setLink(this.text.toString().trim()); |
||||
} |
||||
} |
||||
|
||||
/** Checking for a description */ |
||||
if (localName.equalsIgnoreCase("description")) { |
||||
/** Lets check we are in an item */ |
||||
if (this.item != null) { |
||||
this.item.setDescription(this.text.toString().trim()); |
||||
/** Lets check we are in the channel */ |
||||
} else { |
||||
this.channel.setDescription(this.text.toString().trim()); |
||||
} |
||||
} |
||||
|
||||
/** Checking for a pubdate */ |
||||
if (localName.equalsIgnoreCase("pubDate")) { |
||||
/** Lets check we are in an item */ |
||||
if (this.item != null) { |
||||
try { |
||||
this.item.setPubdate(new Date(Date.parse(this.text.toString().trim()))); |
||||
} catch (Exception e) { |
||||
// Date is malformed (not parsable by Date.parse)
|
||||
} |
||||
/** Lets check we are in the channel */ |
||||
} else { |
||||
try { |
||||
this.channel.setPubDate(new Date(Date.parse(this.text.toString().trim()))); |
||||
} catch (Exception e) { |
||||
// Date is malformed (not parsable by Date.parse)
|
||||
} |
||||
} |
||||
} |
||||
|
||||
/** Check for the category */ |
||||
if (localName.equalsIgnoreCase("category") && (this.item != null)) { |
||||
this.channel.addCategory(this.text.toString().trim()); |
||||
} |
||||
|
||||
addAdditionalData(localName, this.item, this.text.toString()); |
||||
|
||||
this.text.setLength(0); |
||||
} |
||||
|
||||
/** |
||||
* May be overridden to add additional data from tags that are not standard in RSS. Not used by this default RSS |
||||
* style parser. Usually used in conjunction with {@link #createNewItem()}. |
||||
* @param localName The tag name |
||||
* @param item The Item we are currently parsing |
||||
* @param text The new text content |
||||
*/ |
||||
protected void addAdditionalData(String localName, Item item, String text) { |
||||
} |
||||
|
||||
@Override |
||||
public final void characters(char[] ch, int start, int length) { |
||||
this.text.append(ch, start, length); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue