Added more error handling when adding new feeds

This commit is contained in:
daniel oeh 2012-06-28 13:28:24 +02:00
parent fdd5c2dc7e
commit 3c4167ed49
8 changed files with 276 additions and 97 deletions

View File

@ -1,65 +1,71 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<!-- Activitiy titles--> <!-- Activitiy titles -->
<string name="app_name">Podfetcher</string> <string name="app_name">Podfetcher</string>
<string name="feeds_label">Feeds</string> <string name="feeds_label">Feeds</string>
<string name="new_label">New</string> <string name="new_label">New</string>
<string name="settings_label">Settings</string> <string name="settings_label">Settings</string>
<string name="add_new_feed_label">Add a new Feed</string> <string name="add_new_feed_label">Add a new Feed</string>
<string name="downloads_label">Downloads</string> <string name="downloads_label">Downloads</string>
<string name="cancel_download_label">Cancel Download</string> <string name="cancel_download_label">Cancel Download</string>
<!-- --> <!-- -->
<string name="confirm_label">Confirm</string> <string name="confirm_label">Confirm</string>
<string name="cancel_label">Cancel</string> <string name="cancel_label">Cancel</string>
<!-- AddFeed Activity labels --> <!-- AddFeed Activity labels -->
<string name="feedurl_label">Feed URL</string> <string name="feedurl_label">Feed URL</string>
<!-- Feeditemview labels--> <!-- Feeditemview labels -->
<string name="download_label">Download</string> <string name="download_label">Download</string>
<string name="play_label">Play</string> <string name="play_label">Play</string>
<string name="description_label">Description</string> <string name="description_label">Description</string>
<string name="remove_label">Remove</string> <string name="remove_label">Remove</string>
<!-- DownloadObserver Messages --> <!-- DownloadObserver Messages -->
<string name="download_successful">Download successful</string> <string name="download_successful">Download successful</string>
<string name="download_failed">Download failed</string> <string name="download_failed">Download failed</string>
<string name="download_pending">Download pending</string> <string name="download_pending">Download pending</string>
<string name="download_running">Download running</string> <string name="download_running">Download running</string>
<!-- other messages --> <!-- other messages -->
<string name="nofeeds_msg">No feeds added yet.</string> <string name="nofeeds_msg">No feeds added yet.</string>
<!-- Mediaplayer status Messages --> <!-- Mediaplayer status Messages -->
<string name="player_paused_msg">Paused</string> <string name="player_paused_msg">Paused</string>
<string name="player_error_msg">Error!</string> <string name="player_error_msg">Error!</string>
<string name="player_stopped_msg">No media playing</string> <string name="player_stopped_msg">No media playing</string>
<string name="player_preparing_msg">Preparing...</string> <string name="player_preparing_msg">Preparing...</string>
<string name="mark_read_label">Mark read</string> <string name="mark_read_label">Mark read</string>
<string name="mark_unread_label">Mark unread</string> <string name="mark_unread_label">Mark unread</string>
<string name="version_pref">Version</string> <string name="version_pref">Version</string>
<string name="other_pref">Other</string> <string name="other_pref">Other</string>
<string name="about_pref">About</string> <string name="about_pref">About</string>
<string name="show_download_log">Show Log</string> <string name="show_download_log">Show Log</string>
<string name="download_error_device_not_found">Storage device not found</string> <string name="download_error_device_not_found">Storage device not found</string>
<string name="download_error_insufficient_space">Insufficient space</string> <string name="download_error_insufficient_space">Insufficient space</string>
<string name="download_error_file_error">File error</string> <string name="download_error_file_error">File error</string>
<string name="download_error_http_data_error">HTTP Data Error</string> <string name="download_error_http_data_error">HTTP Data Error</string>
<string name="download_error_error_unknown">Unknown Error</string> <string name="download_error_error_unknown">Unknown Error</string>
<string name="show_player_label">Show player</string> <string name="show_player_label">Show player</string>
<string name="add_to_queue_label">Add to Queue</string> <string name="add_to_queue_label">Add to Queue</string>
<string name="remove_from_queue_label">Remove from Queue</string> <string name="remove_from_queue_label">Remove from Queue</string>
<string name="player_ready_msg">Ready</string> <string name="player_ready_msg">Ready</string>
<string name="stream_label">Stream</string> <string name="stream_label">Stream</string>
<string name="player_seeking_msg">Seeking</string> <string name="player_seeking_msg">Seeking</string>
<string name="player_playing_msg"></string> <string name="player_playing_msg"></string>
<string name="mark_all_read_label">Mark all read</string> <string name="mark_all_read_label">Mark all read</string>
<string name="show_info_label">Show information</string> <string name="show_info_label">Show information</string>
<string name="remove_feed_label">Remove Feed</string> <string name="remove_feed_label">Remove Feed</string>
<string name="position_default_label">00:00:00</string> <string name="position_default_label">00:00:00</string>
<string name="queue_label">Queue</string> <string name="queue_label">Queue</string>
<string name="visit_website_label">Visit Website</string> <string name="visit_website_label">Visit Website</string>
<string name="support_label">Support</string> <string name="support_label">Support</string>
</resources> <string name="download_error_parser_exception">Parser Exception</string>
<string name="download_error_unsupported_type">Unsupported Feed type</string>
<string name="error_label">Error</string>
<string name="error_msg_prefix">An error occured:</string>
<string name="download_error_connection_error">Connection error</string>
</resources>

View File

@ -4,9 +4,11 @@ import android.os.Bundle;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.view.View; import android.view.View;
import android.app.AlertDialog;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.util.Log; import android.util.Log;
@ -16,6 +18,8 @@ import de.podfetcher.asynctask.DownloadStatus;
import de.podfetcher.feed.Feed; import de.podfetcher.feed.Feed;
import de.podfetcher.feed.FeedManager; import de.podfetcher.feed.FeedManager;
import de.podfetcher.storage.DownloadRequester; import de.podfetcher.storage.DownloadRequester;
import de.podfetcher.util.ConnectionTester;
import de.podfetcher.util.DownloadError;
import de.podfetcher.util.URLChecker; import de.podfetcher.util.URLChecker;
import de.podfetcher.service.DownloadService; import de.podfetcher.service.DownloadService;
@ -52,7 +56,7 @@ public class AddFeedActivity extends SherlockActivity {
requester = DownloadRequester.getInstance(); requester = DownloadRequester.getInstance();
manager = FeedManager.getInstance(); manager = FeedManager.getInstance();
progDialog = new ProgressDialog(this) { progDialog = new ProgressDialog(this) {
@Override @Override
public void onBackPressed() { public void onBackPressed() {
@ -61,7 +65,7 @@ public class AddFeedActivity extends SherlockActivity {
} else { } else {
requester.cancelDownload(getContext(), downloadId); requester.cancelDownload(getContext(), downloadId);
} }
unregisterReceiver(downloadCompleted); unregisterReceiver(downloadCompleted);
dismiss(); dismiss();
} }
@ -93,7 +97,7 @@ public class AddFeedActivity extends SherlockActivity {
super.onStop(); super.onStop();
Log.d(TAG, "Stopping Activity"); Log.d(TAG, "Stopping Activity");
} }
@Override @Override
protected void onPause() { protected void onPause() {
super.onPause(); super.onPause();
@ -102,25 +106,48 @@ public class AddFeedActivity extends SherlockActivity {
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// ignore // ignore
} }
}
}
private void addNewFeed() { private void addNewFeed() {
String url = etxtFeedurl.getText().toString(); String url = etxtFeedurl.getText().toString();
url = URLChecker.prepareURL(url); url = URLChecker.prepareURL(url);
if (url != null) { if (url != null) {
Feed feed = new Feed(url, new Date()); final Feed feed = new Feed(url, new Date());
downloadId = requester.downloadFeed(this, feed); final ConnectionTester conTester = new ConnectionTester(url, this,
new ConnectionTester.Callback() {
@Override
public void onConnectionSuccessful() {
downloadId = requester.downloadFeed(
AddFeedActivity.this, feed);
}
@Override
public void onConnectionFailure() {
int reason = DownloadError.ERROR_CONNECTION_ERROR;
long statusId = manager.addDownloadStatus(
AddFeedActivity.this, new DownloadStatus(
feed, reason, false));
Intent intent = new Intent(DownloadService.ACTION_DOWNLOAD_HANDLED);
intent.putExtra(DownloadService.EXTRA_DOWNLOAD_ID, downloadId);
intent.putExtra(DownloadService.EXTRA_STATUS_ID, statusId);
AddFeedActivity.this.sendBroadcast(intent);
}
});
observeDownload(feed); observeDownload(feed);
new Thread(conTester).start();
} }
} }
private void observeDownload(Feed feed) { private void observeDownload(Feed feed) {
progDialog.show(); progDialog.show();
progDialog.setMessage("Downloading Feed"); progDialog.setMessage("Downloading Feed");
registerReceiver(downloadCompleted, new IntentFilter(DownloadService.ACTION_DOWNLOAD_HANDLED)); registerReceiver(downloadCompleted, new IntentFilter(
DownloadService.ACTION_DOWNLOAD_HANDLED));
} }
private void updateProgDialog(final String msg) { private void updateProgDialog(final String msg) {
@ -138,7 +165,20 @@ public class AddFeedActivity extends SherlockActivity {
} }
private void handleDownloadError(DownloadStatus status) { private void handleDownloadError(DownloadStatus status) {
final AlertDialog errorDialog = new AlertDialog.Builder(this).create();
errorDialog.setTitle(R.string.error_label);
errorDialog.setMessage(getString(R.string.error_msg_prefix) + " "
+ DownloadError.getErrorString(this, status.getReason()));
errorDialog.setButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
errorDialog.dismiss();
}
});
if (progDialog.isShowing()) {
progDialog.dismiss();
}
errorDialog.show();
} }
private BroadcastReceiver downloadCompleted = new BroadcastReceiver() { private BroadcastReceiver downloadCompleted = new BroadcastReceiver() {

View File

@ -11,6 +11,10 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import de.podfetcher.activity.DownloadActivity; import de.podfetcher.activity.DownloadActivity;
import de.podfetcher.activity.MediaplayerActivity; import de.podfetcher.activity.MediaplayerActivity;
import de.podfetcher.asynctask.DownloadStatus; import de.podfetcher.asynctask.DownloadStatus;
@ -18,6 +22,8 @@ import de.podfetcher.feed.*;
import de.podfetcher.service.PlaybackService.LocalBinder; import de.podfetcher.service.PlaybackService.LocalBinder;
import de.podfetcher.storage.DownloadRequester; import de.podfetcher.storage.DownloadRequester;
import de.podfetcher.syndication.handler.FeedHandler; import de.podfetcher.syndication.handler.FeedHandler;
import de.podfetcher.syndication.handler.UnsupportedFeedtypeException;
import de.podfetcher.util.DownloadError;
import android.R; import android.R;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
@ -188,19 +194,21 @@ public class DownloadService extends Service {
(FeedMedia) download); (FeedMedia) download);
} }
successful = true; successful = true;
queryDownloads();
} else if (status == DownloadManager.STATUS_FAILED) { } else if (status == DownloadManager.STATUS_FAILED) {
reason = c.getInt(c reason = c.getInt(c
.getColumnIndex(DownloadManager.COLUMN_REASON)); .getColumnIndex(DownloadManager.COLUMN_REASON));
Log.d(TAG, "reason code is " + reason); Log.e(TAG, "Download failed");
Log.e(TAG, "reason code is " + reason);
successful = false; successful = false;
long statusId = manager.addDownloadStatus(context, new DownloadStatus(download, long statusId = manager.addDownloadStatus(context, new DownloadStatus(download,
reason, successful)); reason, successful));
requester.removeDownload(download);
sendDownloadHandledIntent(download.getDownloadId(), statusId, false, 0); sendDownloadHandledIntent(download.getDownloadId(), statusId, false, 0);
download.setDownloadId(0); download.setDownloadId(0);
} }
queryDownloads();
c.close(); c.close();
} }
} }
@ -271,25 +279,48 @@ public class DownloadService extends Service {
public void run() { public void run() {
long imageId = 0; long imageId = 0;
boolean hasImage = false; boolean hasImage = false;
long downloadId = feed.getDownloadId();
int reason = 0;
boolean successful = true;
FeedManager manager = FeedManager.getInstance(); FeedManager manager = FeedManager.getInstance();
FeedHandler handler = new FeedHandler(); FeedHandler handler = new FeedHandler();
feed.setDownloaded(true); feed.setDownloaded(true);
feed = handler.parseFeed(feed);
Log.d(TAG, feed.getTitle() + " parsed"); try {
// Download Feed Image if provided feed = handler.parseFeed(feed);
if (feed.getImage() != null) { Log.d(TAG, feed.getTitle() + " parsed");
Log.d(TAG, "Feed has image; Downloading...."); // Download Feed Image if provided
imageId = requester.downloadImage(service, feed.getImage()); if (feed.getImage() != null) {
hasImage = true; Log.d(TAG, "Feed has image; Downloading....");
imageId = requester.downloadImage(service, feed.getImage());
hasImage = true;
}
feed.setDownloadId(0);
// Save information of feed in DB
manager.updateFeed(service, feed);
} catch (SAXException e) {
successful = false;
e.printStackTrace();
reason = DownloadError.ERROR_PARSER_EXCEPTION;
} catch (IOException e) {
successful = false;
e.printStackTrace();
reason = DownloadError.ERROR_PARSER_EXCEPTION;
} catch (ParserConfigurationException e) {
successful = false;
e.printStackTrace();
reason = DownloadError.ERROR_PARSER_EXCEPTION;
} catch (UnsupportedFeedtypeException e) {
e.printStackTrace();
successful = false;
reason = DownloadError.ERROR_UNSUPPORTED_TYPE;
} }
requester.removeDownload(feed); requester.removeDownload(feed);
cleanup(); cleanup();
long statusId = manager.addDownloadStatus(service, new DownloadStatus(feed, 0, true)); long statusId = manager.addDownloadStatus(service, new DownloadStatus(feed, reason, successful));
sendDownloadHandledIntent(feed.getDownloadId(), statusId, hasImage, imageId); sendDownloadHandledIntent(downloadId, statusId, hasImage, imageId);
feed.setDownloadId(0);
// Save information of feed in DB
manager.updateFeed(service, feed);
queryDownloads(); queryDownloads();
} }

View File

@ -12,25 +12,18 @@ import org.xml.sax.SAXException;
import de.podfetcher.feed.Feed; import de.podfetcher.feed.Feed;
public class FeedHandler { public class FeedHandler {
public Feed parseFeed(Feed feed) throws SAXException, IOException,
public Feed parseFeed(Feed feed) { ParserConfigurationException, UnsupportedFeedtypeException {
TypeGetter tg = new TypeGetter(); TypeGetter tg = new TypeGetter();
TypeGetter.Type type = tg.getType(feed); TypeGetter.Type type = tg.getType(feed);
SyndHandler handler = new SyndHandler(feed, type); SyndHandler handler = new SyndHandler(feed, type);
try {
SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true); factory.setNamespaceAware(true);
SAXParser saxParser = factory.newSAXParser(); SAXParser saxParser = factory.newSAXParser();
saxParser.parse(new File(feed.getFile_url()), handler); saxParser.parse(new File(feed.getFile_url()), handler);
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch(ParserConfigurationException e) {
e.printStackTrace();
}
return handler.state.feed; return handler.state.feed;
} }
} }

View File

@ -25,7 +25,7 @@ public class TypeGetter {
private static final String ATOM_ROOT = "feed"; private static final String ATOM_ROOT = "feed";
private static final String RSS_ROOT = "rss"; private static final String RSS_ROOT = "rss";
public Type getType(Feed feed) { public Type getType(Feed feed) throws UnsupportedFeedtypeException {
XmlPullParserFactory factory; XmlPullParserFactory factory;
try { try {
factory = XmlPullParserFactory.newInstance(); factory = XmlPullParserFactory.newInstance();
@ -47,7 +47,7 @@ public class TypeGetter {
return Type.RSS20; return Type.RSS20;
} else { } else {
Log.d(TAG, "Type is invalid"); Log.d(TAG, "Type is invalid");
return Type.INVALID; throw new UnsupportedFeedtypeException(Type.INVALID);
} }
} else { } else {
eventType = xpp.next(); eventType = xpp.next();
@ -60,7 +60,7 @@ public class TypeGetter {
e.printStackTrace(); e.printStackTrace();
} }
Log.d(TAG, "Type is invalid"); Log.d(TAG, "Type is invalid");
return Type.INVALID; throw new UnsupportedFeedtypeException(Type.INVALID);
} }
private Reader createReader(Feed feed) { private Reader createReader(Feed feed) {

View File

@ -0,0 +1,29 @@
package de.podfetcher.syndication.handler;
import de.podfetcher.syndication.handler.TypeGetter.Type;
public class UnsupportedFeedtypeException extends Exception {
private static final long serialVersionUID = 9105878964928170669L;
private TypeGetter.Type type;
public UnsupportedFeedtypeException(Type type) {
super();
this.type = type;
}
public TypeGetter.Type getType() {
return type;
}
@Override
public String getMessage() {
if (type == TypeGetter.Type.INVALID) {
return "Invalid type";
} else {
return "Type " + type + " not supported";
}
}
}

View File

@ -0,0 +1,66 @@
package de.podfetcher.util;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import android.content.Context;
import android.util.Log;
/** Tests a connection before downloading something. */
public class ConnectionTester implements Runnable {
private static final String TAG = "ConnectionTester";
private String strUrl;
private Context context;
private int connectTimeout;
private int readTimeout;
private Callback callback;
private int reason;
public ConnectionTester(String url, Context context, Callback callback) {
super();
this.strUrl = url;
this.context = context;
this.callback = callback;
connectTimeout = 500;
readTimeout = connectTimeout;
}
@Override
public void run() {
Log.d(TAG, "Testing connection");
try {
URL url = new URL(strUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.connect();
callback.onConnectionSuccessful();
Log.d(TAG, "Connection seems to work");
} catch (MalformedURLException e) {
e.printStackTrace();
reason = DownloadError.ERROR_CONNECTION_ERROR;
Log.d(TAG, "Connection failed");
callback.onConnectionFailure();
} catch (IOException e) {
e.printStackTrace();
reason = DownloadError.ERROR_CONNECTION_ERROR;
Log.d(TAG, "Connection failed");
callback.onConnectionFailure();
}
}
public static abstract class Callback {
public abstract void onConnectionSuccessful();
public abstract void onConnectionFailure();
}
public int getReason() {
return reason;
}
}

View File

@ -6,6 +6,11 @@ import android.content.Context;
/** Utility class for Download Errors. */ /** Utility class for Download Errors. */
public class DownloadError { public class DownloadError {
public static final int ERROR_PARSER_EXCEPTION = 1;
public static final int ERROR_UNSUPPORTED_TYPE = 2;
public static final int ERROR_CONNECTION_ERROR = 3;
/** Get a human-readable string for a specific error code. */ /** Get a human-readable string for a specific error code. */
public static String getErrorString(Context context, int code) { public static String getErrorString(Context context, int code) {
int resId; int resId;
@ -19,6 +24,15 @@ public class DownloadError {
case DownloadManager.ERROR_HTTP_DATA_ERROR: case DownloadManager.ERROR_HTTP_DATA_ERROR:
resId = R.string.download_error_http_data_error; resId = R.string.download_error_http_data_error;
break; break;
case ERROR_PARSER_EXCEPTION:
resId = R.string.download_error_parser_exception;
break;
case ERROR_UNSUPPORTED_TYPE:
resId = R.string.download_error_unsupported_type;
break;
case ERROR_CONNECTION_ERROR:
resId = R.string.download_error_connection_error;
break;
default: default:
resId = R.string.download_error_error_unknown; resId = R.string.download_error_error_unknown;
} }