/* This file is part of AbianReader. AbianReader is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. AbianReader is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with AbianReader. If not, see <http://www.gnu.org/licenses/>. */ package com.abiansoftware.lib.reader; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.Vector; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.AsyncTask; import android.util.Log; import android.widget.Toast; import com.abiansoftware.lib.reader.AbianReaderData.AbianReaderItem; public class AbianReaderDataFetcher { private static final String TAG = "AbianReaderDataFetcher"; private static final String RSS_ITEM = "item"; private static final String RSS_TITLE = "title"; private static final String RSS_LINK = "link"; private static final String RSS_DESCRIPTION = "description"; private static final String RSS_CONTENT = "content:encoded"; private static final String RSS_PUB_DATE = "pubDate"; private static final String RSS_CREATOR = "dc:creator"; private static final String RSS_COMMENTS = "comments"; private static final String RSS_COMMENT_COUNT = "slash:comments"; private static final String XML_PAGE = "abianReaderXmlPage"; private static final String XML_TIME = "abianReaderXmlTime"; private static final String XML_CREATOR = "abianReaderXmlCreator"; private static final String XML_CONTENT = "abianReaderXmlContent"; private static final String XML_COMMENT_COUNT = "abianReaderXmlCommentCount"; private static final String XML_THUMBNAIL_LINK = "abianReaderXmlThumbnailLink"; private static final String XML_FEATURED_IMAGE_LINK = "abianReaderXmlFeaturedLink"; private static final String XML_IS_FEATURED = "abianReaderXmlIsFeatured"; private static boolean s_bTryJson = false; private static String s_featuredTag; private RefreshFeedTask m_refreshFeedTask; private boolean m_bIsRefreshingFeed; private int m_numberOfItemsInFirstPage; private boolean m_bNoMoreItemsToFetch; private boolean m_bLastConnectionHadError; private Vector<AbianReaderItem> m_stagingVector; public AbianReaderDataFetcher() { m_refreshFeedTask = null; m_bIsRefreshingFeed = false; m_numberOfItemsInFirstPage = 0; m_bNoMoreItemsToFetch = false; m_bLastConnectionHadError = false; m_stagingVector = new Vector<AbianReaderItem>(); s_featuredTag = AbianReaderApplication.getInstance().getString(R.string.featured_tag); String tryJsonStr = AbianReaderApplication.getInstance().getString(R.string.try_json); if((tryJsonStr != null) && (tryJsonStr.length() > 0)) { s_bTryJson = true; } } public static String GetFeaturedTag() { return s_featuredTag; } static public boolean GetTryJson() { return s_bTryJson; } public boolean isRefreshingFeed() { return m_bIsRefreshingFeed; } private static boolean isNetworkAvailable() { boolean haveConnectedWifi = false; boolean haveConnectedMobile = false; ConnectivityManager cm = (ConnectivityManager)AbianReaderApplication.getInstance().getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo[] netInfo = cm.getAllNetworkInfo(); for(NetworkInfo ni: netInfo) { if(ni.getTypeName().equalsIgnoreCase("WIFI")) { if(ni.isConnected()) { haveConnectedWifi = true; } } if(ni.getTypeName().equalsIgnoreCase("MOBILE")) { if(ni.isConnected()) { haveConnectedMobile = true; } } } return haveConnectedWifi || haveConnectedMobile; } public void getMoreFeed() { AbianReaderData abianReaderAppData = AbianReaderApplication.getData(); if(abianReaderAppData != null) { abianReaderAppData.setPageNumber(abianReaderAppData.getPageNumber() + 1); } refreshFeed(); } public void refreshFeed() { if((m_refreshFeedTask == null) || (m_refreshFeedTask.getStatus() == AsyncTask.Status.FINISHED) || m_refreshFeedTask.isCancelled()) { try { m_refreshFeedTask = new RefreshFeedTask(); String feedUrl = AbianReaderApplication.getInstance().getString(R.string.feed_url_str); if(feedUrl.contains("?")) { feedUrl += "&"; } else { feedUrl += "/?"; } int requestedPageNumber = 1; AbianReaderData abianReaderAppData = AbianReaderApplication.getData(); if(abianReaderAppData != null) { if(abianReaderAppData.getNumberOfItems() == 0) { abianReaderAppData.setPageNumber(1); } requestedPageNumber = abianReaderAppData.getPageNumber(); } feedUrl += "paged=" + requestedPageNumber; m_refreshFeedTask.execute(feedUrl); } catch(Exception e) { Log.e(TAG, e.toString()); } } } private class RefreshFeedTask extends AsyncTask<String, Void, Void> { @Override protected Void doInBackground(String... params) { String urlToConnectTo = params[0]; try { URL urlObject = new URL(urlToConnectTo); HttpURLConnection httpConnection = (HttpURLConnection)urlObject.openConnection(); httpConnection.setConnectTimeout(30 * 1000); httpConnection.setReadTimeout(30 * 1000); if(httpConnection.getResponseCode() != HttpURLConnection.HTTP_OK) { Log.d(TAG, "getInputStream() HTTP returning null. Received HTTP response code: " + httpConnection.getResponseCode() + ", Url: " + urlToConnectTo); return null; } InputStream is = httpConnection.getInputStream(); if(is != null) { SAXParserFactory theSaxParserFactory = SAXParserFactory.newInstance(); SAXParser theSaxParser = theSaxParserFactory.newSAXParser(); XMLReader theXmlReader = theSaxParser.getXMLReader(); boolean bIsFeedBurner = false; bIsFeedBurner = AbianReaderApplication.getInstance().getString(R.string.feed_type_str).equalsIgnoreCase("feedburner"); if(bIsFeedBurner) { Log.v(TAG, "FEEDBURNER!!!!"); theXmlReader.setContentHandler(new FeedBurnerFeedHandler()); } else { theXmlReader.setContentHandler(new RSSFeedHandler()); } theXmlReader.parse(new InputSource(is)); } else { m_bLastConnectionHadError = true; } } catch(Exception e) { Log.w(getClass().getName(), "Exception thrown: " + e.getMessage() + ", Url: " + urlToConnectTo); } return null; } @Override protected void onPreExecute() { m_stagingVector.clear(); m_bIsRefreshingFeed = true; m_bLastConnectionHadError = false; m_bNoMoreItemsToFetch = false; AbianReaderApplication.getInstance().sendDataUpdatedMessage(); if(!isNetworkAvailable()) { cancel(true); String toastText = AbianReaderApplication.getInstance().getString(R.string.no_network_str); Toast.makeText(AbianReaderApplication.getInstance(), toastText, Toast.LENGTH_SHORT).show(); m_bLastConnectionHadError = true; AbianReaderApplication.getInstance().sendDataUpdatedMessage(); } } @Override protected void onPostExecute(Void param) { m_bIsRefreshingFeed = false; AbianReaderData abianReaderAppData = AbianReaderApplication.getData(); if(abianReaderAppData == null) { Log.e(getClass().getName(), "There is no application data!!!"); return; } int numberOfFetchedItems = m_stagingVector.size(); boolean bIsFirstPage = (abianReaderAppData.getPageNumber() == 1); if(bIsFirstPage) { m_numberOfItemsInFirstPage = numberOfFetchedItems; } for(int i = 0; i < m_stagingVector.size(); i++) { AbianReaderItem thisItem = m_stagingVector.get(i); ArrayList<String> readUrlArrayList = AbianReaderApplication.getInstance().getReadUrlArrayList(); if(readUrlArrayList != null) { for(int arrayListPosition = 0; arrayListPosition < readUrlArrayList.size(); arrayListPosition++) { if(readUrlArrayList.get(arrayListPosition).equalsIgnoreCase(thisItem.getLink())) { thisItem.setArticleHasBeenRead(false); break; } } } abianReaderAppData.addItem(thisItem); if(s_bTryJson) { m_stagingVector.get(i).getExtraJsonData(bIsFirstPage); } } Log.e("TAG", "Calling send data updated message from the data fetcher"); AbianReaderApplication.getInstance().sendDataUpdatedMessage(); m_stagingVector.clear(); if(m_bLastConnectionHadError) { // TODO, show a toast message? } else if(numberOfFetchedItems != m_numberOfItemsInFirstPage) { m_bNoMoreItemsToFetch = true; } AbianReaderApplication.getInstance().sendDataUpdatedMessage(); } } public boolean getLastConnectionHadError() { return m_bLastConnectionHadError; } public boolean getThereAreNoMoreItems() { return m_bNoMoreItemsToFetch; } private class RSSFeedHandler extends DefaultHandler { private AbianReaderData m_abianReaderData = null; private StringBuffer m_currentCharactersStringBuffer; private String m_title; private String m_link; private String m_description; private String m_content; private String m_pubDate; private String m_creator; private String m_comments; private String m_thumbnailLink; private String m_featuredImageLink; private boolean m_bIsFeatured; private int m_commentCount; @Override public void startDocument() throws SAXException { } @Override public void endDocument() throws SAXException { } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if(qName.compareTo(RSS_ITEM) == 0) { m_title = ""; m_description = ""; m_link = ""; m_content = ""; m_pubDate = ""; m_creator = ""; m_comments = ""; m_thumbnailLink = ""; m_featuredImageLink = ""; m_bIsFeatured = false; m_commentCount = 0; m_currentCharactersStringBuffer = new StringBuffer(); } else if((qName.compareTo(RSS_TITLE) == 0) || (qName.compareTo(RSS_LINK) == 0) || (qName.compareTo(RSS_DESCRIPTION) == 0) || (qName.compareTo(RSS_CONTENT) == 0) || (qName.compareTo(RSS_PUB_DATE) == 0) || (qName.compareTo(RSS_CREATOR) == 0) || (qName.compareTo(RSS_COMMENTS) == 0) || (qName.compareTo(RSS_COMMENT_COUNT) == 0) || (qName.compareTo(XML_PAGE) == 0) || (qName.compareTo(XML_TIME) == 0) || (qName.compareTo(XML_CONTENT) == 0) || (qName.compareTo(XML_THUMBNAIL_LINK) == 0) || (qName.compareTo(XML_FEATURED_IMAGE_LINK) == 0) || (qName.compareTo(XML_IS_FEATURED) == 0) || (qName.compareTo(XML_CREATOR) == 0) || (qName.compareTo(XML_COMMENT_COUNT) == 0)) { m_currentCharactersStringBuffer = new StringBuffer(); } else { m_currentCharactersStringBuffer = null; } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if(m_currentCharactersStringBuffer != null) { m_currentCharactersStringBuffer.append(ch, start, length); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { String thisText = ""; if(m_currentCharactersStringBuffer != null) { thisText = m_currentCharactersStringBuffer.toString(); } if(qName.compareTo(RSS_ITEM) == 0) { AbianReaderItem newItem = new AbianReaderItem(); newItem.setTitle(m_title); newItem.setDescription(m_description); newItem.setLink(m_link); newItem.setContent(m_content); newItem.setPubDate(m_pubDate); newItem.setCreator(m_creator); newItem.setCommentsLink(m_comments); newItem.setCommentCount(m_commentCount); newItem.setThumbnailLink(m_thumbnailLink); newItem.setFeaturedImageLink(m_featuredImageLink, m_bIsFeatured); m_stagingVector.add(newItem); m_title = ""; m_description = ""; m_link = ""; m_content = ""; m_pubDate = ""; m_creator = ""; m_comments = ""; m_thumbnailLink = ""; m_featuredImageLink = ""; m_bIsFeatured = false; m_commentCount = 0; } else if(qName.compareTo(RSS_TITLE) == 0) { m_title = thisText; } else if(qName.compareTo(RSS_LINK) == 0) { m_link = thisText; } else if(qName.compareTo(RSS_DESCRIPTION) == 0) { m_description = thisText; } else if((qName.compareTo(RSS_CONTENT) == 0) || (qName.compareTo(XML_CONTENT) == 0)) { m_content = thisText; } else if(qName.compareTo(RSS_PUB_DATE) == 0) { m_pubDate = thisText; } else if((qName.compareTo(RSS_CREATOR) == 0) || (qName.compareTo(XML_CREATOR) == 0)) { m_creator = thisText; } else if(qName.compareTo(RSS_COMMENTS) == 0) { m_comments = thisText; } else if(qName.compareTo(XML_THUMBNAIL_LINK) == 0) { m_thumbnailLink = thisText; } else if(qName.compareTo(XML_FEATURED_IMAGE_LINK) == 0) { m_featuredImageLink = thisText; } else if(qName.compareTo(XML_IS_FEATURED) == 0) { m_bIsFeatured = Boolean.valueOf(thisText).booleanValue(); } else if((qName.compareTo(RSS_COMMENT_COUNT) == 0) || (qName.compareTo(XML_COMMENT_COUNT) == 0)) { try { m_commentCount = Integer.parseInt(thisText); } catch(Exception e) { Log.e(TAG, e.toString()); } } else if(qName.compareTo(XML_PAGE) == 0) { try { m_abianReaderData.setPageNumber(Integer.parseInt(thisText)); } catch(Exception e) { Log.e(TAG, e.toString()); } } else if(qName.compareTo(XML_TIME) == 0) { try { m_abianReaderData.setLastUpdateTime(Long.parseLong(thisText)); } catch(Exception e) { Log.e(TAG, e.toString()); } } } @Override public void error(SAXParseException e) throws SAXException { Log.e(TAG, "SAX error: " + e.toString()); } @Override public void warning(SAXParseException e) throws SAXException { Log.w(TAG, "SAX warning: " + e.toString()); } } private class FeedBurnerFeedHandler extends DefaultHandler { private AbianReaderData m_abianReaderData = null; private StringBuffer m_currentCharactersStringBuffer; private String m_title; private String m_link; private String m_description; private String m_content; private String m_pubDate; private String m_creator; private String m_comments; private String m_thumbnailLink; private String m_featuredImageLink; private boolean m_bIsFeatured; private int m_commentCount; @Override public void startDocument() throws SAXException { } @Override public void endDocument() throws SAXException { } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if(qName.compareTo("entry") == 0) { m_title = ""; m_description = ""; m_link = ""; m_content = ""; m_pubDate = ""; m_creator = ""; m_comments = ""; m_thumbnailLink = ""; m_featuredImageLink = ""; m_bIsFeatured = false; m_commentCount = 0; m_currentCharactersStringBuffer = new StringBuffer(); } else if((qName.compareTo("title") == 0) || (qName.compareTo("feedburner:origLink") == 0) || (qName.compareTo(RSS_DESCRIPTION) == 0) || (qName.compareTo("content") == 0) || (qName.compareTo("published") == 0) || (qName.compareTo("name") == 0) || (qName.compareTo(RSS_COMMENTS) == 0) || (qName.compareTo(RSS_COMMENT_COUNT) == 0) || (qName.compareTo(XML_PAGE) == 0) || (qName.compareTo(XML_TIME) == 0) || (qName.compareTo(XML_CONTENT) == 0) || (qName.compareTo(XML_THUMBNAIL_LINK) == 0) || (qName.compareTo(XML_FEATURED_IMAGE_LINK) == 0) || (qName.compareTo(XML_IS_FEATURED) == 0) || (qName.compareTo(XML_CREATOR) == 0) || (qName.compareTo(XML_COMMENT_COUNT) == 0)) { m_currentCharactersStringBuffer = new StringBuffer(); } else { m_currentCharactersStringBuffer = null; } if(qName.compareTo("media:thumbnail") == 0) { m_thumbnailLink = attributes.getValue("url"); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if(m_currentCharactersStringBuffer != null) { m_currentCharactersStringBuffer.append(ch, start, length); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { String thisText = ""; if(m_currentCharactersStringBuffer != null) { thisText = m_currentCharactersStringBuffer.toString(); } if(qName.compareTo("entry") == 0) { AbianReaderItem newItem = new AbianReaderItem(); newItem.setTitle(m_title); newItem.setDescription(m_description); newItem.setLink(m_link); newItem.setContent(m_content); newItem.setPubDate(m_pubDate); newItem.setCreator(m_creator); newItem.setCommentsLink(m_comments); newItem.setCommentCount(m_commentCount); newItem.setThumbnailLink(m_thumbnailLink); newItem.setFeaturedImageLink(m_featuredImageLink, m_bIsFeatured); m_stagingVector.add(newItem); m_title = ""; m_description = ""; m_link = ""; m_content = ""; m_pubDate = ""; m_creator = ""; m_comments = ""; m_thumbnailLink = ""; m_featuredImageLink = ""; m_bIsFeatured = false; m_commentCount = 0; } else if(qName.compareTo("title") == 0) { m_title = thisText; } else if(qName.compareTo("feedburner:origLink") == 0) { m_link = thisText; } else if(qName.compareTo(RSS_DESCRIPTION) == 0) { m_description = thisText; } else if((qName.compareTo("content") == 0) || (qName.compareTo(XML_CONTENT) == 0)) { m_content = thisText; } else if(qName.compareTo("published") == 0) { m_pubDate = thisText; } else if((qName.compareTo("name") == 0) || (qName.compareTo(XML_CREATOR) == 0)) { m_creator = thisText; } else if(qName.compareTo(RSS_COMMENTS) == 0) { m_comments = thisText; } else if(qName.compareTo(XML_THUMBNAIL_LINK) == 0) { m_thumbnailLink = thisText; } else if(qName.compareTo(XML_FEATURED_IMAGE_LINK) == 0) { m_featuredImageLink = thisText; } else if(qName.compareTo(XML_IS_FEATURED) == 0) { m_bIsFeatured = Boolean.valueOf(thisText).booleanValue(); } else if((qName.compareTo(RSS_COMMENT_COUNT) == 0) || (qName.compareTo(XML_COMMENT_COUNT) == 0)) { try { m_commentCount = Integer.parseInt(thisText); } catch(Exception e) { Log.e(TAG, e.toString()); } } else if(qName.compareTo(XML_PAGE) == 0) { try { m_abianReaderData.setPageNumber(Integer.parseInt(thisText)); } catch(Exception e) { Log.e(TAG, e.toString()); } } else if(qName.compareTo(XML_TIME) == 0) { try { m_abianReaderData.setLastUpdateTime(Long.parseLong(thisText)); } catch(Exception e) { Log.e(TAG, e.toString()); } } } @Override public void error(SAXParseException e) throws SAXException { Log.e(TAG, "SAX error: " + e.toString()); } @Override public void warning(SAXParseException e) throws SAXException { Log.w(TAG, "SAX warning: " + e.toString()); } } public static int GetNumberOfSameCharacters(String str1, String str2) { int retVal = 0; if((str1 != null) && (str2 != null)) { for(int i = 0; ((i < str1.length()) && (i < str2.length())); i++) { if(str1.charAt(i) == str2.charAt(i)) { retVal++; } else { break; } } } return retVal; } }