Eric Kok
12 years ago
25 changed files with 885 additions and 673 deletions
@ -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 @@ |
|||||||
/* |
|
||||||
* 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 @@ |
|||||||
/* |
|
||||||
* 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 @@ |
|||||||
/* |
|
||||||
* 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 @@ |
|||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
|
/* |
||||||
|
* 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