summaryrefslogtreecommitdiff
path: root/src/de
diff options
context:
space:
mode:
Diffstat (limited to 'src/de')
-rw-r--r--src/de/danoeh/antennapod/PodcastApp.java246
-rw-r--r--src/de/danoeh/antennapod/activity/AddFeedActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/AudioplayerActivity.java61
-rw-r--r--src/de/danoeh/antennapod/activity/DirectoryChooserActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/DownloadActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/DownloadLogActivity.java25
-rw-r--r--src/de/danoeh/antennapod/activity/FeedInfoActivity.java8
-rw-r--r--src/de/danoeh/antennapod/activity/FeedItemlistActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/FlattrAuthActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/ItemviewActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/MainActivity.java37
-rw-r--r--src/de/danoeh/antennapod/activity/MediaplayerActivity.java149
-rw-r--r--src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java7
-rw-r--r--src/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java10
-rw-r--r--src/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java18
-rw-r--r--src/de/danoeh/antennapod/activity/OpmlImportHolder.java4
-rw-r--r--src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java66
-rw-r--r--src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/PreferenceActivity.java14
-rw-r--r--src/de/danoeh/antennapod/activity/SearchActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/StorageErrorActivity.java4
-rw-r--r--src/de/danoeh/antennapod/activity/VideoplayerActivity.java37
-rw-r--r--src/de/danoeh/antennapod/adapter/AbstractFeedItemlistAdapter.java52
-rw-r--r--src/de/danoeh/antennapod/adapter/ChapterListAdapter.java9
-rw-r--r--src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java36
-rw-r--r--src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java57
-rw-r--r--src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java18
-rw-r--r--src/de/danoeh/antennapod/adapter/FeedlistAdapter.java45
-rw-r--r--src/de/danoeh/antennapod/adapter/SearchlistAdapter.java6
-rw-r--r--src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java31
-rw-r--r--src/de/danoeh/antennapod/asynctask/ImageLoader.java (renamed from src/de/danoeh/antennapod/asynctask/FeedImageLoader.java)114
-rw-r--r--src/de/danoeh/antennapod/asynctask/OpmlExportWorker.java6
-rw-r--r--src/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java1
-rw-r--r--src/de/danoeh/antennapod/asynctask/OpmlImportWorker.java3
-rw-r--r--src/de/danoeh/antennapod/feed/Chapter.java10
-rw-r--r--src/de/danoeh/antennapod/feed/EventDistributor.java140
-rw-r--r--src/de/danoeh/antennapod/feed/Feed.java80
-rw-r--r--src/de/danoeh/antennapod/feed/FeedItem.java25
-rw-r--r--src/de/danoeh/antennapod/feed/FeedManager.java315
-rw-r--r--src/de/danoeh/antennapod/feed/FeedMedia.java173
-rw-r--r--src/de/danoeh/antennapod/fragment/CoverFragment.java39
-rw-r--r--src/de/danoeh/antennapod/fragment/EpisodesFragment.java45
-rw-r--r--src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java14
-rw-r--r--src/de/danoeh/antennapod/fragment/FeedlistFragment.java50
-rw-r--r--src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java100
-rw-r--r--src/de/danoeh/antennapod/fragment/ItemlistFragment.java95
-rw-r--r--src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java46
-rw-r--r--src/de/danoeh/antennapod/preferences/PlaybackPreferences.java193
-rw-r--r--src/de/danoeh/antennapod/preferences/UserPreferences.java320
-rw-r--r--src/de/danoeh/antennapod/receiver/FeedUpdateReceiver.java8
-rw-r--r--src/de/danoeh/antennapod/service/PlaybackService.java404
-rw-r--r--src/de/danoeh/antennapod/service/PlayerStatus.java1
-rw-r--r--src/de/danoeh/antennapod/service/PlayerWidgetService.java8
-rw-r--r--src/de/danoeh/antennapod/service/download/DownloadService.java48
-rw-r--r--src/de/danoeh/antennapod/storage/DownloadRequester.java18
-rw-r--r--src/de/danoeh/antennapod/storage/PodDBAdapter.java4
-rw-r--r--src/de/danoeh/antennapod/syndication/handler/HandlerState.java35
-rw-r--r--src/de/danoeh/antennapod/syndication/handler/SyndHandler.java6
-rw-r--r--src/de/danoeh/antennapod/syndication/namespace/NSRSS20.java2
-rw-r--r--src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java2
-rw-r--r--src/de/danoeh/antennapod/util/BitmapDecoder.java3
-rw-r--r--src/de/danoeh/antennapod/util/ChapterUtils.java102
-rw-r--r--src/de/danoeh/antennapod/util/StorageUtils.java5
-rw-r--r--src/de/danoeh/antennapod/util/ThemeUtils.java4
-rw-r--r--src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java2
-rw-r--r--src/de/danoeh/antennapod/util/playback/ExternalMedia.java238
-rw-r--r--src/de/danoeh/antennapod/util/playback/MediaPlayerError.java (renamed from src/de/danoeh/antennapod/util/MediaPlayerError.java)2
-rw-r--r--src/de/danoeh/antennapod/util/playback/Playable.java197
-rw-r--r--src/de/danoeh/antennapod/util/playback/PlaybackController.java (renamed from src/de/danoeh/antennapod/util/PlaybackController.java)29
74 files changed, 2555 insertions, 1324 deletions
diff --git a/src/de/danoeh/antennapod/PodcastApp.java b/src/de/danoeh/antennapod/PodcastApp.java
index 0e3fab80d..9a3332788 100644
--- a/src/de/danoeh/antennapod/PodcastApp.java
+++ b/src/de/danoeh/antennapod/PodcastApp.java
@@ -1,54 +1,24 @@
package de.danoeh.antennapod;
-import java.io.File;
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-
-import android.app.AlarmManager;
import android.app.Application;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.res.Configuration;
-import android.preference.PreferenceManager;
import android.util.Log;
-import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
-import de.danoeh.antennapod.asynctask.FeedImageLoader;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.FeedManager;
-import de.danoeh.antennapod.feed.FeedMedia;
-import de.danoeh.antennapod.receiver.FeedUpdateReceiver;
-import de.danoeh.antennapod.service.PlaybackService;
+import de.danoeh.antennapod.preferences.PlaybackPreferences;
+import de.danoeh.antennapod.preferences.UserPreferences;
/** Main application class. */
-public class PodcastApp extends Application implements
- SharedPreferences.OnSharedPreferenceChangeListener {
+public class PodcastApp extends Application {
private static final String TAG = "PodcastApp";
public static final String EXPORT_DIR = "export/";
- public static final String PREF_PAUSE_ON_HEADSET_DISCONNECT = "prefPauseOnHeadsetDisconnect";
- public static final String PREF_FOLLOW_QUEUE = "prefFollowQueue";
- public static final String PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY = "prefDownloadMediaOnWifiOnly";
- public static final String PREF_UPDATE_INTERVALL = "prefAutoUpdateIntervall";
- public static final String PREF_MOBILE_UPDATE = "prefMobileUpdate";
- public static final String PREF_AUTO_QUEUE = "prefAutoQueue";
- public static final String PREF_DISPLAY_ONLY_EPISODES = "prefDisplayOnlyEpisodes";
- public static final String PREF_AUTO_DELETE = "prefAutoDelete";
- public static final String PREF_THEME = "prefTheme";
- public static final String PREF_DATA_FOLDER = "prefDataFolder";
-
private static float LOGICAL_DENSITY;
private static PodcastApp singleton;
- private boolean displayOnlyEpisodes;
-
- private static long currentlyPlayingMediaId;
-
- /** Resource id of the currently selected theme. */
- private static int theme;
-
public static PodcastApp getInstance() {
return singleton;
}
@@ -58,225 +28,29 @@ public class PodcastApp extends Application implements
super.onCreate();
singleton = this;
LOGICAL_DENSITY = getResources().getDisplayMetrics().density;
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(this);
- displayOnlyEpisodes = prefs.getBoolean(PREF_DISPLAY_ONLY_EPISODES,
- false);
- currentlyPlayingMediaId = prefs.getLong(
- PlaybackService.PREF_CURRENTLY_PLAYING_MEDIA,
- PlaybackService.NO_MEDIA_PLAYING);
- readThemeValue();
- createImportDirectory();
- createNoMediaFile();
- prefs.registerOnSharedPreferenceChangeListener(this);
+
+ UserPreferences.createInstance(this);
+ PlaybackPreferences.createInstance(this);
+ EventDistributor.getInstance();
FeedManager manager = FeedManager.getInstance();
manager.loadDBData(getApplicationContext());
}
- /** Create a .nomedia file to prevent scanning by the media scanner. */
- private void createNoMediaFile() {
- File f = new File(getExternalFilesDir(null), ".nomedia");
- if (!f.exists()) {
- try {
- f.createNewFile();
- } catch (IOException e) {
- Log.e(TAG, "Could not create .nomedia file");
- e.printStackTrace();
- }
- if (AppConfig.DEBUG)
- Log.d(TAG, ".nomedia file created");
- }
- }
-
- /**
- * Creates the import directory if it doesn't exist and if storage is
- * available
- */
- private void createImportDirectory() {
- File importDir = getDataFolder(this, OpmlImportFromPathActivity.IMPORT_DIR);
- if (importDir != null) {
- if (importDir.exists()) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Import directory already exists");
- } else {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Creating import directory");
- importDir.mkdir();
- }
- } else {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Could not access external storage.");
- }
- }
-
@Override
public void onLowMemory() {
super.onLowMemory();
Log.w(TAG, "Received onLowOnMemory warning. Cleaning image cache...");
- FeedImageLoader.getInstance().wipeImageCache();
- }
-
- /**
- * Listens for changes in the 'update intervall'-preference and changes the
- * alarm if necessary.
- */
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Registered change of application preferences");
- if (key.equals(PREF_UPDATE_INTERVALL)) {
- AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
- int hours = Integer.parseInt(sharedPreferences.getString(
- PREF_UPDATE_INTERVALL, "0"));
- PendingIntent updateIntent = PendingIntent.getBroadcast(this, 0,
- new Intent(FeedUpdateReceiver.ACTION_REFRESH_FEEDS), 0);
- alarmManager.cancel(updateIntent);
- if (hours != 0) {
- long newIntervall = TimeUnit.HOURS.toMillis(hours);
- alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
- newIntervall, newIntervall, updateIntent);
- if (AppConfig.DEBUG)
- Log.d(TAG, "Changed alarm to new intervall");
- } else {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Automatic update was deactivated");
- }
- } else if (key.equals(PREF_DISPLAY_ONLY_EPISODES)) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "PREF_DISPLAY_ONLY_EPISODES changed");
- displayOnlyEpisodes = sharedPreferences.getBoolean(
- PREF_DISPLAY_ONLY_EPISODES, false);
- } else if (key.equals(PlaybackService.PREF_LAST_PLAYED_ID)) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "PREF_LAST_PLAYED_ID changed");
- long mediaId = sharedPreferences.getLong(
- PlaybackService.PREF_AUTODELETE_MEDIA_ID, -1);
- if (mediaId != -1) {
- FeedManager manager = FeedManager.getInstance();
- FeedMedia media = manager.getFeedMedia(mediaId);
- if (media != null) {
- manager.autoDeleteIfPossible(this, media);
- }
- }
- } else if (key.equals(PlaybackService.PREF_CURRENTLY_PLAYING_MEDIA)) {
- long id = sharedPreferences.getLong(
- PlaybackService.PREF_CURRENTLY_PLAYING_MEDIA,
- PlaybackService.NO_MEDIA_PLAYING);
- if (AppConfig.DEBUG)
- Log.d(TAG, "Currently playing media set to " + id);
- if (id != currentlyPlayingMediaId) {
- currentlyPlayingMediaId = id;
- }
- } else if (key.equals(PREF_THEME)) {
- readThemeValue();
- }
+ ImageLoader.getInstance().wipeImageCache();
}
public static float getLogicalDensity() {
return LOGICAL_DENSITY;
}
- public boolean displayOnlyEpisodes() {
- return displayOnlyEpisodes;
- }
-
- public static long getCurrentlyPlayingMediaId() {
- return currentlyPlayingMediaId;
- }
-
public boolean isLargeScreen() {
return (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE
|| (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE;
}
- public static int getThemeResourceId() {
- return theme;
- }
-
- /** Read value of prefTheme and determine the correct resource id. */
- private void readThemeValue() {
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(this);
- int prefTheme = Integer.parseInt(prefs.getString(PREF_THEME, "0"));
- switch (prefTheme) {
- case 0:
- theme = R.style.Theme_AntennaPod_Light;
- break;
- case 1:
- theme = R.style.Theme_AntennaPod_Dark;
- break;
- }
- }
-
- /**
- * Return the folder where the app stores all of its data. This method will
- * return the standard data folder if none has been set by the user.
- *
- * @param type
- * The name of the folder inside the data folder. May be null
- * when accessing the root of the data folder.
- * @return The data folder that has been requested or null if the folder
- * could not be created.
- */
- public static File getDataFolder(Context context, String type) {
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(context.getApplicationContext());
- String strDir = prefs.getString(PREF_DATA_FOLDER, null);
- if (strDir == null) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Using default data folder");
- return context.getExternalFilesDir(type);
- } else {
- File dataDir = new File(strDir);
- if (!dataDir.exists()) {
- if (!dataDir.mkdir()) {
- Log.w(TAG, "Could not create data folder");
- return null;
- }
- }
-
- if (type == null) {
- return dataDir;
- } else {
- // handle path separators
- String[] dirs = type.split("/");
- for (int i = 0; i < dirs.length; i++) {
- if (dirs.length > 0) {
- if (i < dirs.length - 1) {
- dataDir = getDataFolder(context, dirs[i]);
- if (dataDir == null) {
- return null;
- }
- }
- type = dirs[i];
- }
- }
- File typeDir = new File(dataDir, type);
- if (!typeDir.exists()) {
- if (dataDir.canWrite()) {
- if (!typeDir.mkdir()) {
- Log.e(TAG, "Could not create data folder named "
- + type);
- return null;
- }
- }
- }
- return typeDir;
- }
-
- }
- }
-
- public void setDataFolder(String dir) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Result from DirectoryChooser: " + dir);
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(this);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(PodcastApp.PREF_DATA_FOLDER, dir);
- editor.commit();
- createImportDirectory();
- }
}
diff --git a/src/de/danoeh/antennapod/activity/AddFeedActivity.java b/src/de/danoeh/antennapod/activity/AddFeedActivity.java
index 44486b5ef..39434fa87 100644
--- a/src/de/danoeh/antennapod/activity/AddFeedActivity.java
+++ b/src/de/danoeh/antennapod/activity/AddFeedActivity.java
@@ -18,9 +18,9 @@ import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.ConnectionTester;
@@ -44,7 +44,7 @@ public class AddFeedActivity extends SherlockActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
StorageUtils.checkStorageAvailability(this);
diff --git a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
index 48b09b92b..3e38d7b5c 100644
--- a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
+++ b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java
@@ -1,5 +1,7 @@
package de.danoeh.antennapod.activity;
+import java.io.File;
+
import android.content.Intent;
import android.content.res.TypedArray;
import android.os.Bundle;
@@ -20,13 +22,15 @@ import com.actionbarsherlock.view.Window;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.ChapterListAdapter;
-import de.danoeh.antennapod.asynctask.FeedImageLoader;
+import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.feed.Chapter;
-import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.feed.MediaType;
import de.danoeh.antennapod.feed.SimpleChapter;
import de.danoeh.antennapod.fragment.CoverFragment;
import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
import de.danoeh.antennapod.service.PlaybackService;
+import de.danoeh.antennapod.util.playback.ExternalMedia;
+import de.danoeh.antennapod.util.playback.Playable;
/** Activity for playing audio files. */
public class AudioplayerActivity extends MediaplayerActivity {
@@ -71,10 +75,32 @@ public class AudioplayerActivity extends MediaplayerActivity {
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
super.onCreate(savedInstanceState);
+ getSupportActionBar().setDisplayShowTitleEnabled(false);
detachedFragments = new Fragment[NUM_CONTENT_FRAGMENTS];
}
@Override
+ protected void onResume() {
+ super.onResume();
+ if (getIntent().getAction() != null
+ && getIntent().getAction().equals(Intent.ACTION_VIEW)) {
+ Intent intent = getIntent();
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Received VIEW intent: "
+ + intent.getData().getPath());
+ ExternalMedia media = new ExternalMedia(intent.getData().getPath(), MediaType.AUDIO);
+ Intent launchIntent = new Intent(this, PlaybackService.class);
+ launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
+ launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED,
+ true);
+ launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, false);
+ launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
+ true);
+ startService(launchIntent);
+ }
+ }
+
+ @Override
protected void onAwaitingVideoSurface() {
startActivity(new Intent(this, VideoplayerActivity.class));
}
@@ -101,7 +127,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
if (AppConfig.DEBUG)
Log.d(TAG, "Switching contentView to position " + pos);
if (currentlyShownPosition != pos) {
- FeedMedia media = controller.getMedia();
+ Playable media = controller.getMedia();
if (media != null) {
FragmentTransaction ft = getSupportFragmentManager()
.beginTransaction();
@@ -113,15 +139,14 @@ public class AudioplayerActivity extends MediaplayerActivity {
case POS_COVER:
if (coverFragment == null) {
Log.i(TAG, "Using new coverfragment");
- coverFragment = CoverFragment.newInstance(media
- .getItem());
+ coverFragment = CoverFragment.newInstance(media);
}
currentlyShownFragment = coverFragment;
break;
case POS_DESCR:
if (descriptionFragment == null) {
descriptionFragment = ItemDescriptionFragment
- .newInstance(media.getItem());
+ .newInstance(media);
}
currentlyShownFragment = descriptionFragment;
break;
@@ -140,7 +165,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
};
chapterFragment.setListAdapter(new ChapterListAdapter(
- AudioplayerActivity.this, 0, media.getItem()
+ AudioplayerActivity.this, 0, media
.getChapters(), media));
}
currentlyShownFragment = chapterFragment;
@@ -167,7 +192,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
private void updateNavButtonDrawable() {
TypedArray drawables = obtainStyledAttributes(new int[] {
R.attr.navigation_shownotes, R.attr.navigation_chapters });
- final FeedMedia media = controller.getMedia();
+ final Playable media = controller.getMedia();
if (butNavLeft != null && butNavRight != null && media != null) {
switch (currentlyShownPosition) {
case POS_COVER:
@@ -181,9 +206,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
@Override
public void run() {
- FeedImageLoader.getInstance().loadThumbnailBitmap(
- media.getItem().getFeed().getImage(),
- butNavLeft);
+ ImageLoader.getInstance().loadThumbnailBitmap(
+ media.getImageFileUrl(), butNavLeft);
}
});
butNavRight.setImageDrawable(drawables.getDrawable(1));
@@ -194,9 +218,8 @@ public class AudioplayerActivity extends MediaplayerActivity {
@Override
public void run() {
- FeedImageLoader.getInstance().loadThumbnailBitmap(
- media.getItem().getFeed().getImage(),
- butNavLeft);
+ ImageLoader.getInstance().loadThumbnailBitmap(
+ media.getImageFileUrl(), butNavLeft);
}
});
butNavRight.setImageDrawable(drawables.getDrawable(0));
@@ -251,11 +274,11 @@ public class AudioplayerActivity extends MediaplayerActivity {
@Override
protected void loadMediaInfo() {
super.loadMediaInfo();
- final FeedMedia media = controller.getMedia();
+ final Playable media = controller.getMedia();
if (media != null) {
- txtvTitle.setText(media.getItem().getTitle());
- txtvFeed.setText(media.getItem().getFeed().getTitle());
- if (media.getItem().getChapters() != null) {
+ txtvTitle.setText(media.getEpisodeTitle());
+ txtvFeed.setText(media.getFeedTitle());
+ if (media.getChapters() != null) {
butNavRight.setVisibility(View.VISIBLE);
} else {
butNavRight.setVisibility(View.GONE);
@@ -302,7 +325,7 @@ public class AudioplayerActivity extends MediaplayerActivity {
}
public interface AudioplayerContentFragment {
- public void onDataSetChanged(FeedMedia media);
+ public void onDataSetChanged(Playable media);
}
}
diff --git a/src/de/danoeh/antennapod/activity/DirectoryChooserActivity.java b/src/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
index 6e1163508..54c4f0589 100644
--- a/src/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
+++ b/src/de/danoeh/antennapod/activity/DirectoryChooserActivity.java
@@ -30,8 +30,8 @@ import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.preferences.UserPreferences;
/**
* Let's the user choose a directory on the storage device. The selected folder
@@ -61,7 +61,7 @@ public class DirectoryChooserActivity extends SherlockActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
diff --git a/src/de/danoeh/antennapod/activity/DownloadActivity.java b/src/de/danoeh/antennapod/activity/DownloadActivity.java
index 0c10abefd..10ebb1285 100644
--- a/src/de/danoeh/antennapod/activity/DownloadActivity.java
+++ b/src/de/danoeh/antennapod/activity/DownloadActivity.java
@@ -22,10 +22,10 @@ import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.DownloadlistAdapter;
import de.danoeh.antennapod.asynctask.DownloadStatus;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.download.DownloadService;
import de.danoeh.antennapod.storage.DownloadRequester;
@@ -52,7 +52,7 @@ public class DownloadActivity extends SherlockListActivity implements
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
if (AppConfig.DEBUG)
Log.d(TAG, "Creating Activity");
diff --git a/src/de/danoeh/antennapod/activity/DownloadLogActivity.java b/src/de/danoeh/antennapod/activity/DownloadLogActivity.java
index 45d31cda9..232a7ba1d 100644
--- a/src/de/danoeh/antennapod/activity/DownloadLogActivity.java
+++ b/src/de/danoeh/antennapod/activity/DownloadLogActivity.java
@@ -1,18 +1,15 @@
package de.danoeh.antennapod.activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Bundle;
import com.actionbarsherlock.app.SherlockListActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.adapter.DownloadLogAdapter;
+import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.FeedManager;
+import de.danoeh.antennapod.preferences.UserPreferences;
/**
* Displays completed and failed downloads in a list. The data comes from the
@@ -26,11 +23,11 @@ public class DownloadLogActivity extends SherlockListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
manager = FeedManager.getInstance();
- dla = new DownloadLogAdapter(this, 0, manager.getDownloadLog());
+ dla = new DownloadLogAdapter(this);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setListAdapter(dla);
}
@@ -38,14 +35,13 @@ public class DownloadLogActivity extends SherlockListActivity {
@Override
protected void onPause() {
super.onPause();
- unregisterReceiver(contentUpdate);
+ EventDistributor.getInstance().unregister(contentUpdate);
}
@Override
protected void onResume() {
super.onResume();
- registerReceiver(contentUpdate, new IntentFilter(
- FeedManager.ACTION_DOWNLOADLOG_UPDATE));
+ EventDistributor.getInstance().register(contentUpdate);
dla.notifyDataSetChanged();
}
@@ -66,12 +62,11 @@ public class DownloadLogActivity extends SherlockListActivity {
return true;
}
- private BroadcastReceiver contentUpdate = new BroadcastReceiver() {
-
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+
@Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction()
- .equals(FeedManager.ACTION_DOWNLOADLOG_UPDATE)) {
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((arg & EventDistributor.DOWNLOADLOG_UPDATE) != 0) {
dla.notifyDataSetChanged();
}
}
diff --git a/src/de/danoeh/antennapod/activity/FeedInfoActivity.java b/src/de/danoeh/antennapod/activity/FeedInfoActivity.java
index 0ff1d7c1c..c57a5794b 100644
--- a/src/de/danoeh/antennapod/activity/FeedInfoActivity.java
+++ b/src/de/danoeh/antennapod/activity/FeedInfoActivity.java
@@ -11,12 +11,12 @@ import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.asynctask.FeedImageLoader;
+import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedManager;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.util.LangUtils;
import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
@@ -37,7 +37,7 @@ public class FeedInfoActivity extends SherlockActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
setContentView(R.layout.feedinfo);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@@ -58,7 +58,7 @@ public class FeedInfoActivity extends SherlockActivity {
@Override
public void run() {
- FeedImageLoader.getInstance().loadThumbnailBitmap(
+ ImageLoader.getInstance().loadThumbnailBitmap(
feed.getImage(), imgvCover);
}
});
diff --git a/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java b/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java
index 1be29ddbe..fdca48e8a 100644
--- a/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java
+++ b/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java
@@ -15,7 +15,6 @@ import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.Window;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.FeedRemover;
import de.danoeh.antennapod.dialog.ConfirmationDialog;
@@ -25,6 +24,7 @@ import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.fragment.ExternalPlayerFragment;
import de.danoeh.antennapod.fragment.FeedlistFragment;
import de.danoeh.antennapod.fragment.ItemlistFragment;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.util.StorageUtils;
import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
@@ -42,7 +42,7 @@ public class FeedItemlistActivity extends SherlockFragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
StorageUtils.checkStorageAvailability(this);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
diff --git a/src/de/danoeh/antennapod/activity/FlattrAuthActivity.java b/src/de/danoeh/antennapod/activity/FlattrAuthActivity.java
index b78b37afa..75e513816 100644
--- a/src/de/danoeh/antennapod/activity/FlattrAuthActivity.java
+++ b/src/de/danoeh/antennapod/activity/FlattrAuthActivity.java
@@ -17,8 +17,8 @@ import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.util.flattr.FlattrUtils;
/** Guides the user through the authentication process */
@@ -36,7 +36,7 @@ public class FlattrAuthActivity extends SherlockActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
singleton = this;
authSuccessful = false;
diff --git a/src/de/danoeh/antennapod/activity/ItemviewActivity.java b/src/de/danoeh/antennapod/activity/ItemviewActivity.java
index 668cb3a28..63dcb78f1 100644
--- a/src/de/danoeh/antennapod/activity/ItemviewActivity.java
+++ b/src/de/danoeh/antennapod/activity/ItemviewActivity.java
@@ -16,7 +16,6 @@ import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.Window;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
import de.danoeh.antennapod.feed.Feed;
@@ -25,6 +24,7 @@ import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.fragment.FeedlistFragment;
import de.danoeh.antennapod.fragment.ItemDescriptionFragment;
import de.danoeh.antennapod.fragment.ItemlistFragment;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.util.StorageUtils;
import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
@@ -42,7 +42,7 @@ public class ItemviewActivity extends SherlockFragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
StorageUtils.checkStorageAvailability(this);
manager = FeedManager.getInstance();
diff --git a/src/de/danoeh/antennapod/activity/MainActivity.java b/src/de/danoeh/antennapod/activity/MainActivity.java
index 67d7424b6..0ec66ff35 100644
--- a/src/de/danoeh/antennapod/activity/MainActivity.java
+++ b/src/de/danoeh/antennapod/activity/MainActivity.java
@@ -1,9 +1,7 @@
package de.danoeh.antennapod.activity;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
@@ -20,12 +18,13 @@ import com.actionbarsherlock.view.Window;
import com.viewpagerindicator.TabPageIndicator;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.fragment.EpisodesFragment;
import de.danoeh.antennapod.fragment.ExternalPlayerFragment;
import de.danoeh.antennapod.fragment.FeedlistFragment;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.PlaybackService;
import de.danoeh.antennapod.service.download.DownloadService;
import de.danoeh.antennapod.storage.DownloadRequester;
@@ -35,6 +34,9 @@ import de.danoeh.antennapod.util.StorageUtils;
public class MainActivity extends SherlockFragmentActivity {
private static final String TAG = "MainActivity";
+ private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
+ | EventDistributor.DOWNLOAD_QUEUED;
+
private FeedManager manager;
private ViewPager viewpager;
private MainPagerAdapter pagerAdapter;
@@ -45,7 +47,7 @@ public class MainActivity extends SherlockFragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
StorageUtils.checkStorageAvailability(this);
manager = FeedManager.getInstance();
@@ -69,7 +71,7 @@ public class MainActivity extends SherlockFragmentActivity {
if (!appLaunched && getIntent().getAction() != null
&& getIntent().getAction().equals(Intent.ACTION_MAIN)) {
appLaunched = true;
- if (manager.getUnreadItems().size() > 0) {
+ if (manager.getUnreadItemsSize(true) > 0) {
viewpager.setCurrentItem(MainPagerAdapter.POS_EPISODES);
}
@@ -79,7 +81,7 @@ public class MainActivity extends SherlockFragmentActivity {
@Override
protected void onPause() {
super.onPause();
- unregisterReceiver(contentUpdate);
+ EventDistributor.getInstance().unregister(contentUpdate);
}
@Override
@@ -87,18 +89,19 @@ public class MainActivity extends SherlockFragmentActivity {
super.onResume();
StorageUtils.checkStorageAvailability(this);
updateProgressBarVisibility();
- IntentFilter filter = new IntentFilter();
- filter.addAction(DownloadService.ACTION_DOWNLOAD_HANDLED);
- filter.addAction(DownloadRequester.ACTION_DOWNLOAD_QUEUED);
- registerReceiver(contentUpdate, filter);
+ EventDistributor.getInstance().register(contentUpdate);
+
}
- private BroadcastReceiver contentUpdate = new BroadcastReceiver() {
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+
@Override
- public void onReceive(Context context, Intent intent) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Received contentUpdate Intent.");
- updateProgressBarVisibility();
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((EVENTS & arg) != 0) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Received contentUpdate Intent.");
+ updateProgressBarVisibility();
+ }
}
};
@@ -109,7 +112,7 @@ public class MainActivity extends SherlockFragmentActivity {
} else {
setSupportProgressBarIndeterminateVisibility(false);
}
- invalidateOptionsMenu();
+ supportInvalidateOptionsMenu();
}
@Override
@@ -151,7 +154,7 @@ public class MainActivity extends SherlockFragmentActivity {
refreshAll.setVisible(true);
}
- boolean hasFeeds = !manager.getFeeds().isEmpty();
+ boolean hasFeeds = manager.getFeedsSize() > 0;
menu.findItem(R.id.all_feed_refresh).setVisible(hasFeeds);
return true;
}
diff --git a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
index 952cddf8b..c217a4628 100644
--- a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
+++ b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java
@@ -5,6 +5,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
+import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageButton;
@@ -18,19 +19,18 @@ import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.asynctask.FlattrClickWorker;
import de.danoeh.antennapod.dialog.TimeDialog;
import de.danoeh.antennapod.feed.FeedManager;
-import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.PlaybackService;
-import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.util.Converter;
-import de.danoeh.antennapod.util.MediaPlayerError;
-import de.danoeh.antennapod.util.PlaybackController;
+import de.danoeh.antennapod.util.ShareUtils;
import de.danoeh.antennapod.util.StorageUtils;
-import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
+import de.danoeh.antennapod.util.playback.MediaPlayerError;
+import de.danoeh.antennapod.util.playback.Playable;
+import de.danoeh.antennapod.util.playback.PlaybackController;
/**
* Provides general features which are both needed for playing audio and video
@@ -91,7 +91,7 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
@Override
public void onSleepTimerUpdate() {
- invalidateOptionsMenu();
+ supportInvalidateOptionsMenu();
}
@Override
@@ -133,12 +133,12 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
}
protected void onServiceQueried() {
- invalidateOptionsMenu();
+ supportInvalidateOptionsMenu();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
if (AppConfig.DEBUG)
Log.d(TAG, "Creating Activity");
@@ -219,14 +219,14 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
- FeedMedia media = controller.getMedia();
+ Playable media = controller.getMedia();
menu.findItem(R.id.support_item).setVisible(
- media != null && media.getItem().getPaymentLink() != null);
+ media != null && media.getPaymentLink() != null);
menu.findItem(R.id.share_link_item).setVisible(
- media != null && media.getItem().getLink() != null);
+ media != null && media.getWebsiteLink() != null);
menu.findItem(R.id.visit_website_item).setVisible(
- media != null && media.getItem().getLink() != null);
+ media != null && media.getWebsiteLink() != null);
boolean sleepTimerSet = controller.sleepTimerActive();
boolean sleepTimerNotSet = controller.sleepTimerNotActive();
@@ -237,69 +237,80 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case android.R.id.home:
+ Playable media = controller.getMedia();
+ if (item.getItemId() == android.R.id.home) {
Intent intent = new Intent(MediaplayerActivity.this,
MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
- break;
- case R.id.disable_sleeptimer_item:
- if (controller.serviceAvailable()) {
- AlertDialog.Builder stDialog = new AlertDialog.Builder(this);
- stDialog.setTitle(R.string.sleep_timer_label);
- stDialog.setMessage(getString(R.string.time_left_label)
- + Converter.getDurationStringLong((int) controller
- .getSleepTimerTimeLeft()));
- stDialog.setPositiveButton(R.string.disable_sleeptimer_label,
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- dialog.dismiss();
- controller.disableSleepTimer();
- }
- });
- stDialog.setNegativeButton(R.string.cancel_label,
- new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- dialog.dismiss();
- }
- });
- stDialog.create().show();
- }
- break;
- case R.id.set_sleeptimer_item:
- if (controller.serviceAvailable()) {
- TimeDialog td = new TimeDialog(this,
- R.string.set_sleeptimer_label,
- R.string.set_sleeptimer_label) {
-
- @Override
- public void onTimeEntered(long millis) {
- controller.setSleepTimer(millis);
- }
- };
- td.show();
+ return true;
+ } else if (media != null) {
+ switch (item.getItemId()) {
+ case R.id.disable_sleeptimer_item:
+ if (controller.serviceAvailable()) {
+ AlertDialog.Builder stDialog = new AlertDialog.Builder(this);
+ stDialog.setTitle(R.string.sleep_timer_label);
+ stDialog.setMessage(getString(R.string.time_left_label)
+ + Converter.getDurationStringLong((int) controller
+ .getSleepTimerTimeLeft()));
+ stDialog.setPositiveButton(
+ R.string.disable_sleeptimer_label,
+ new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ dialog.dismiss();
+ controller.disableSleepTimer();
+ }
+ });
+ stDialog.setNegativeButton(R.string.cancel_label,
+ new DialogInterface.OnClickListener() {
+
+ @Override
+ public void onClick(DialogInterface dialog,
+ int which) {
+ dialog.dismiss();
+ }
+ });
+ stDialog.create().show();
+ }
+ break;
+ case R.id.set_sleeptimer_item:
+ if (controller.serviceAvailable()) {
+ TimeDialog td = new TimeDialog(this,
+ R.string.set_sleeptimer_label,
+ R.string.set_sleeptimer_label) {
+
+ @Override
+ public void onTimeEntered(long millis) {
+ controller.setSleepTimer(millis);
+ }
+ };
+ td.show();
+ break;
+
+ }
+ case R.id.visit_website_item:
+ Uri uri = Uri.parse(media.getWebsiteLink());
+ startActivity(new Intent(Intent.ACTION_VIEW, uri));
break;
+ case R.id.support_item:
+ new FlattrClickWorker(this, media.getPaymentLink())
+ .executeAsync();
+ break;
+ case R.id.share_link_item:
+ ShareUtils.shareLink(this, media.getWebsiteLink());
+ break;
+ default:
+ return false;
}
- default:
- try {
- return FeedItemMenuHandler.onMenuItemClicked(this, item.getItemId(),
- controller.getMedia().getItem());
- } catch (DownloadRequestException e) {
- e.printStackTrace();
- DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
- e.getMessage());
- }
+ return true;
+ } else {
+ return false;
}
- return true;
}
@Override
@@ -363,7 +374,7 @@ public abstract class MediaplayerActivity extends SherlockFragmentActivity
protected void loadMediaInfo() {
if (AppConfig.DEBUG)
Log.d(TAG, "Loading media info");
- FeedMedia media = controller.getMedia();
+ Playable media = controller.getMedia();
if (media != null) {
txtvPosition.setText(Converter.getDurationStringLong((media
.getPosition())));
diff --git a/src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java
index 7a765a893..bb50944cc 100644
--- a/src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java
+++ b/src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java
@@ -12,9 +12,9 @@ import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.viewpagerindicator.TabPageIndicator;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.fragment.MiroGuideChannellistFragment;
+import de.danoeh.antennapod.preferences.UserPreferences;
/**
* Shows channels of a category sorted by different criteria in lists. The
@@ -34,7 +34,7 @@ public class MiroGuideCategoryActivity extends SherlockFragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(arg0);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.miroguide_category);
diff --git a/src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java
index 05d346bb4..f9fe912cd 100644
--- a/src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java
+++ b/src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java
@@ -21,7 +21,6 @@ import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.MiroGuideItemlistAdapter;
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
@@ -30,6 +29,7 @@ import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.miroguide.conn.MiroGuideException;
import de.danoeh.antennapod.miroguide.conn.MiroGuideService;
import de.danoeh.antennapod.miroguide.model.MiroGuideChannel;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.storage.DownloadRequester;
@@ -62,7 +62,7 @@ public class MiroGuideChannelViewActivity extends SherlockActivity {
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.miroguide_channelview);
diff --git a/src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java
index 6dcb1bdca..8b33ef1da 100644
--- a/src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java
+++ b/src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java
@@ -15,10 +15,10 @@ import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.miroguide.conn.MiroGuideException;
import de.danoeh.antennapod.miroguide.conn.MiroGuideService;
+import de.danoeh.antennapod.preferences.UserPreferences;
/**
* Shows a list of available categories and offers a search button. If the user
@@ -34,7 +34,7 @@ public class MiroGuideMainActivity extends SherlockListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.miroguide_categorylist);
diff --git a/src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java
index 2943339ad..a30777fb1 100644
--- a/src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java
+++ b/src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java
@@ -11,9 +11,9 @@ import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.fragment.MiroGuideChannellistFragment;
+import de.danoeh.antennapod.preferences.UserPreferences;
/**
* Displays results when a search for miroguide channels has been performed. It
@@ -26,7 +26,7 @@ public class MiroGuideSearchActivity extends SherlockFragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(arg0);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setContentView(R.layout.miroguidesearch);
diff --git a/src/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java b/src/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
index 2301d2f0f..9ba355baf 100644
--- a/src/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
+++ b/src/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java
@@ -16,9 +16,9 @@ import com.actionbarsherlock.app.SherlockActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.opml.OpmlElement;
+import de.danoeh.antennapod.preferences.UserPreferences;
/**
* Displays the feeds that the OPML-Importer has read and lets the user choose
@@ -36,7 +36,7 @@ public class OpmlFeedChooserActivity extends SherlockActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
setContentView(R.layout.opml_selection);
diff --git a/src/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java b/src/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
index cf3028307..f887fdd94 100644
--- a/src/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
+++ b/src/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java
@@ -1,14 +1,17 @@
package de.danoeh.antennapod.activity;
+import java.io.Reader;
+import java.util.ArrayList;
+
import android.content.Intent;
import android.util.Log;
+
import com.actionbarsherlock.app.SherlockActivity;
+
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.asynctask.OpmlFeedQueuer;
import de.danoeh.antennapod.asynctask.OpmlImportWorker;
import de.danoeh.antennapod.opml.OpmlElement;
-import java.io.Reader;
-import java.util.ArrayList;
/**
* Base activity for Opml Import - e.g. with code what to do afterwards
diff --git a/src/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java b/src/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java
index cbe69d48c..dc698a851 100644
--- a/src/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java
+++ b/src/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java
@@ -1,17 +1,19 @@
package de.danoeh.antennapod.activity;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URL;
+
import android.app.AlertDialog;
import android.os.Bundle;
-import de.danoeh.antennapod.PodcastApp;
-import java.io.*;
-import java.net.URL;
+import de.danoeh.antennapod.preferences.UserPreferences;
/** Lets the user start the OPML-import process. */
public class OpmlImportFromIntentActivity extends OpmlImportBaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
diff --git a/src/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java b/src/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
index bb5734b57..b38e0c443 100644
--- a/src/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
+++ b/src/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java
@@ -1,5 +1,10 @@
package de.danoeh.antennapod.activity;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.Reader;
+
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
@@ -9,18 +14,15 @@ import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
+
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
+
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.util.StorageUtils;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.Reader;
-
/**
* Lets the user start the OPML-import process from a path
*/
@@ -33,7 +35,7 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@@ -63,7 +65,7 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity {
* directory.
*/
private void setImportPath() {
- File importDir = PodcastApp.getDataFolder(this, IMPORT_DIR);
+ File importDir = UserPreferences.getDataFolder(this, IMPORT_DIR);
boolean success = true;
if (!importDir.exists()) {
if (AppConfig.DEBUG)
diff --git a/src/de/danoeh/antennapod/activity/OpmlImportHolder.java b/src/de/danoeh/antennapod/activity/OpmlImportHolder.java
index ec53ed7b6..8d51eb3de 100644
--- a/src/de/danoeh/antennapod/activity/OpmlImportHolder.java
+++ b/src/de/danoeh/antennapod/activity/OpmlImportHolder.java
@@ -1,9 +1,9 @@
package de.danoeh.antennapod.activity;
-import de.danoeh.antennapod.opml.OpmlElement;
-
import java.util.ArrayList;
+import de.danoeh.antennapod.opml.OpmlElement;
+
/**
* Hold infos gathered by Ompl-Import
* <p/>
diff --git a/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java b/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java
index a7017d2fb..56e42f79f 100644
--- a/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java
+++ b/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java
@@ -1,17 +1,12 @@
package de.danoeh.antennapod.activity;
-import java.util.List;
-
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
@@ -20,11 +15,12 @@ import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.mobeta.android.dslv.DragSortListView;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.asynctask.FeedImageLoader;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedManager;
+import de.danoeh.antennapod.preferences.UserPreferences;
public class OrganizeQueueActivity extends SherlockListActivity {
private static final String TAG = "OrganizeQueueActivity";
@@ -35,7 +31,7 @@ public class OrganizeQueueActivity extends SherlockListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
setContentView(R.layout.organize_queue);
@@ -43,38 +39,32 @@ public class OrganizeQueueActivity extends SherlockListActivity {
listView.setDropListener(dropListener);
listView.setRemoveListener(removeListener);
- adapter = new OrganizeAdapter(this, 0, FeedManager.getInstance()
- .getQueue());
+ adapter = new OrganizeAdapter(this);
setListAdapter(adapter);
}
@Override
protected void onPause() {
super.onPause();
- try {
- unregisterReceiver(contentUpdate);
- } catch (IllegalArgumentException e) {
-
- }
+ EventDistributor.getInstance().unregister(contentUpdate);
}
@Override
protected void onResume() {
super.onResume();
- IntentFilter filter = new IntentFilter(FeedManager.ACTION_QUEUE_UPDATE);
- filter.addAction(FeedManager.ACTION_FEED_LIST_UPDATE);
- registerReceiver(contentUpdate, filter);
+ EventDistributor.getInstance().register(contentUpdate);
}
- private BroadcastReceiver contentUpdate = new BroadcastReceiver() {
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
@Override
- public void onReceive(Context context, Intent intent) {
- if (adapter != null) {
- adapter.notifyDataSetChanged();
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if (((EventDistributor.QUEUE_UPDATE | EventDistributor.FEED_LIST_UPDATE) & arg) != 0) {
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
}
}
-
};
private DragSortListView.DropListener dropListener = new DragSortListView.DropListener() {
@@ -120,13 +110,12 @@ public class OrganizeQueueActivity extends SherlockListActivity {
}
}
- private static class OrganizeAdapter extends ArrayAdapter<FeedItem> {
+ private static class OrganizeAdapter extends BaseAdapter {
private Context context;
- public OrganizeAdapter(Context context, int textViewResourceId,
- List<FeedItem> objects) {
- super(context, textViewResourceId, objects);
+ public OrganizeAdapter(Context context) {
+ super();
this.context = context;
}
@@ -156,8 +145,9 @@ public class OrganizeQueueActivity extends SherlockListActivity {
holder.title.setText(item.getTitle());
holder.feedTitle.setText(item.getFeed().getTitle());
- holder.feedImage.setTag(item.getFeed().getImage());
- FeedImageLoader.getInstance().loadThumbnailBitmap(
+ holder.feedImage.setTag((item.getFeed().getImage() != null) ? item
+ .getFeed().getImage().getFile_url() : null);
+ ImageLoader.getInstance().loadThumbnailBitmap(
item.getFeed().getImage(),
holder.feedImage,
(int) convertView.getResources().getDimension(
@@ -172,6 +162,22 @@ public class OrganizeQueueActivity extends SherlockListActivity {
ImageView feedImage;
}
+ @Override
+ public int getCount() {
+ return FeedManager.getInstance().getQueueSize(true);
+ }
+
+ @Override
+ public FeedItem getItem(int position) {
+ return FeedManager.getInstance()
+ .getQueueItemAtIndex(position, true);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
}
}
diff --git a/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java b/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java
index 22958b058..1a5a2cac9 100644
--- a/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java
+++ b/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java
@@ -10,10 +10,10 @@ import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
+import de.danoeh.antennapod.preferences.UserPreferences;
public class PlaybackHistoryActivity extends SherlockFragmentActivity {
private static final String TAG = "PlaybackHistoryActivity";
@@ -44,7 +44,7 @@ public class PlaybackHistoryActivity extends SherlockFragmentActivity {
@Override
protected void onCreate(Bundle arg0) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(arg0);
if (AppConfig.DEBUG)
diff --git a/src/de/danoeh/antennapod/activity/PreferenceActivity.java b/src/de/danoeh/antennapod/activity/PreferenceActivity.java
index fa0c42b37..360ff610d 100644
--- a/src/de/danoeh/antennapod/activity/PreferenceActivity.java
+++ b/src/de/danoeh/antennapod/activity/PreferenceActivity.java
@@ -15,11 +15,11 @@ import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.FlattrClickWorker;
import de.danoeh.antennapod.asynctask.OpmlExportWorker;
import de.danoeh.antennapod.feed.FeedManager;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.util.flattr.FlattrUtils;
/** The main preference activity */
@@ -36,7 +36,7 @@ public class PreferenceActivity extends SherlockPreferenceActivity {
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@@ -82,7 +82,7 @@ public class PreferenceActivity extends SherlockPreferenceActivity {
@Override
public boolean onPreferenceClick(Preference preference) {
- if (!FeedManager.getInstance().getFeeds().isEmpty()) {
+ if (FeedManager.getInstance().getFeedsSize() > 0) {
new OpmlExportWorker(PreferenceActivity.this)
.executeAsync();
}
@@ -102,7 +102,7 @@ public class PreferenceActivity extends SherlockPreferenceActivity {
return true;
}
});
- findPreference(PodcastApp.PREF_THEME).setOnPreferenceChangeListener(
+ findPreference(UserPreferences.PREF_THEME).setOnPreferenceChangeListener(
new OnPreferenceChangeListener() {
@Override
@@ -137,7 +137,7 @@ public class PreferenceActivity extends SherlockPreferenceActivity {
}
private void setDataFolderText() {
- File f = PodcastApp.getDataFolder(this, null);
+ File f = UserPreferences.getDataFolder(this, null);
if (f != null) {
findPreference(PREF_CHOOSE_DATA_DIR)
.setSummary(f.getAbsolutePath());
@@ -165,7 +165,7 @@ public class PreferenceActivity extends SherlockPreferenceActivity {
@Override
protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
- theme.applyStyle(PodcastApp.getThemeResourceId(), true);
+ theme.applyStyle(UserPreferences.getTheme(), true);
}
@Override
@@ -176,7 +176,7 @@ public class PreferenceActivity extends SherlockPreferenceActivity {
.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
if (AppConfig.DEBUG)
Log.d(TAG, "Setting data folder");
- PodcastApp.getInstance().setDataFolder(dir);
+ UserPreferences.setDataFolder(dir);
}
}
diff --git a/src/de/danoeh/antennapod/activity/SearchActivity.java b/src/de/danoeh/antennapod/activity/SearchActivity.java
index bb2eb54cc..152710112 100644
--- a/src/de/danoeh/antennapod/activity/SearchActivity.java
+++ b/src/de/danoeh/antennapod/activity/SearchActivity.java
@@ -16,7 +16,6 @@ import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.adapter.SearchlistAdapter;
import de.danoeh.antennapod.feed.Feed;
@@ -26,6 +25,7 @@ import de.danoeh.antennapod.feed.FeedSearcher;
import de.danoeh.antennapod.feed.SearchResult;
import de.danoeh.antennapod.fragment.FeedlistFragment;
import de.danoeh.antennapod.fragment.ItemlistFragment;
+import de.danoeh.antennapod.preferences.UserPreferences;
/** Displays the results when the user searches for FeedItems or Feeds. */
public class SearchActivity extends SherlockListActivity {
@@ -43,7 +43,7 @@ public class SearchActivity extends SherlockListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
diff --git a/src/de/danoeh/antennapod/activity/StorageErrorActivity.java b/src/de/danoeh/antennapod/activity/StorageErrorActivity.java
index 514b1f69d..4d9184dcf 100644
--- a/src/de/danoeh/antennapod/activity/StorageErrorActivity.java
+++ b/src/de/danoeh/antennapod/activity/StorageErrorActivity.java
@@ -10,8 +10,8 @@ import android.util.Log;
import com.actionbarsherlock.app.SherlockActivity;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.util.StorageUtils;
/** Is show if there is now external storage available. */
@@ -20,7 +20,7 @@ public class StorageErrorActivity extends SherlockActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
setContentView(R.layout.storage_error);
diff --git a/src/de/danoeh/antennapod/activity/VideoplayerActivity.java b/src/de/danoeh/antennapod/activity/VideoplayerActivity.java
index f6ea4f69e..2d9834a3e 100644
--- a/src/de/danoeh/antennapod/activity/VideoplayerActivity.java
+++ b/src/de/danoeh/antennapod/activity/VideoplayerActivity.java
@@ -18,11 +18,13 @@ import android.widget.VideoView;
import com.actionbarsherlock.view.Window;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.feed.MediaType;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.PlaybackService;
import de.danoeh.antennapod.service.PlayerStatus;
+import de.danoeh.antennapod.util.playback.ExternalMedia;
+import de.danoeh.antennapod.util.playback.Playable;
/** Activity for playing audio files. */
public class VideoplayerActivity extends MediaplayerActivity implements
@@ -41,7 +43,7 @@ public class VideoplayerActivity extends MediaplayerActivity implements
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
- setTheme(PodcastApp.getThemeResourceId());
+ setTheme(UserPreferences.getTheme());
super.onCreate(savedInstanceState);
}
@@ -55,13 +57,34 @@ public class VideoplayerActivity extends MediaplayerActivity implements
}
@Override
+ protected void onResume() {
+ super.onResume();
+ if (getIntent().getAction() != null
+ && getIntent().getAction().equals(Intent.ACTION_VIEW)) {
+ Intent intent = getIntent();
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Received VIEW intent: "
+ + intent.getData().getPath());
+ ExternalMedia media = new ExternalMedia(intent.getData().getPath(),
+ MediaType.VIDEO);
+ Intent launchIntent = new Intent(this, PlaybackService.class);
+ launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
+ launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED,
+ true);
+ launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM, false);
+ launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
+ true);
+ startService(launchIntent);
+ }
+ }
+
+ @Override
protected void loadMediaInfo() {
super.loadMediaInfo();
- FeedMedia media = controller.getMedia();
+ Playable media = controller.getMedia();
if (media != null) {
- getSupportActionBar().setSubtitle(media.getItem().getTitle());
- getSupportActionBar()
- .setTitle(media.getItem().getFeed().getTitle());
+ getSupportActionBar().setSubtitle(media.getEpisodeTitle());
+ getSupportActionBar().setTitle(media.getFeedTitle());
}
}
diff --git a/src/de/danoeh/antennapod/adapter/AbstractFeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/AbstractFeedItemlistAdapter.java
index 5c720d652..6f4cf7c29 100644
--- a/src/de/danoeh/antennapod/adapter/AbstractFeedItemlistAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/AbstractFeedItemlistAdapter.java
@@ -1,49 +1,39 @@
package de.danoeh.antennapod.adapter;
-import java.util.List;
-
-import android.content.Context;
-import android.widget.ArrayAdapter;
-import de.danoeh.antennapod.PodcastApp;
+import android.widget.BaseAdapter;
import de.danoeh.antennapod.feed.FeedItem;
-import de.danoeh.antennapod.util.EpisodeFilter;
-public abstract class AbstractFeedItemlistAdapter extends
- ArrayAdapter<FeedItem> {
+public abstract class AbstractFeedItemlistAdapter extends BaseAdapter {
- private List<FeedItem> objects;
- private boolean isExpanded = true;
+ ItemAccess itemAccess;
- public AbstractFeedItemlistAdapter(Context context, int textViewResourceId,
- List<FeedItem> objects) {
- super(context, textViewResourceId, objects);
- this.objects = objects;
+ public AbstractFeedItemlistAdapter(ItemAccess itemAccess) {
+ super();
+ if (itemAccess == null) {
+ throw new IllegalArgumentException("itemAccess must not be null");
+ }
+ this.itemAccess = itemAccess;
}
@Override
public int getCount() {
- if (isExpanded) {
- if (PodcastApp.getInstance().displayOnlyEpisodes()) {
- return EpisodeFilter.countItemsWithEpisodes(objects);
- } else {
- return super.getCount();
- }
- } else {
- return 0;
- }
+ return itemAccess.getCount();
+
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
}
@Override
public FeedItem getItem(int position) {
- if (PodcastApp.getInstance().displayOnlyEpisodes()) {
- return EpisodeFilter.accessEpisodeByIndex(objects, position);
- } else {
- return super.getItem(position);
- }
+ return itemAccess.getItem(position);
}
- public void toggleExpandedState() {
- isExpanded = !isExpanded;
- notifyDataSetChanged();
+ public static interface ItemAccess {
+ int getCount();
+
+ FeedItem getItem(int position);
}
}
diff --git a/src/de/danoeh/antennapod/adapter/ChapterListAdapter.java b/src/de/danoeh/antennapod/adapter/ChapterListAdapter.java
index 145ca4230..3e9b586ce 100644
--- a/src/de/danoeh/antennapod/adapter/ChapterListAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/ChapterListAdapter.java
@@ -20,20 +20,21 @@ import android.widget.ArrayAdapter;
import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.feed.Chapter;
-import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.util.ChapterUtils;
import de.danoeh.antennapod.util.Converter;
+import de.danoeh.antennapod.util.playback.Playable;
public class ChapterListAdapter extends ArrayAdapter<Chapter> {
private static final String TAG = "ChapterListAdapter";
private List<Chapter> chapters;
- private FeedMedia media;
+ private Playable media;
private int defaultTextColor;
public ChapterListAdapter(Context context, int textViewResourceId,
- List<Chapter> objects, FeedMedia media) {
+ List<Chapter> objects, Playable media) {
super(context, textViewResourceId, objects);
this.chapters = objects;
this.media = media;
@@ -122,7 +123,7 @@ public class ChapterListAdapter extends ArrayAdapter<Chapter> {
}
});
- Chapter current = sc.getItem().getCurrentChapter();
+ Chapter current = ChapterUtils.getCurrentChapter(media);
if (current != null) {
if (current == sc) {
holder.title.setTextColor(convertView.getResources().getColor(
diff --git a/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
index ce339be88..c0ccdc7fe 100644
--- a/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -1,39 +1,40 @@
package de.danoeh.antennapod.adapter;
import java.text.DateFormat;
-import java.util.List;
import android.content.Context;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
import android.widget.TextView;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.asynctask.DownloadStatus;
import de.danoeh.antennapod.feed.Feed;
-import de.danoeh.antennapod.feed.FeedFile;
import de.danoeh.antennapod.feed.FeedImage;
+import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.util.DownloadError;
/** Displays a list of DownloadStatus entries. */
-public class DownloadLogAdapter extends ArrayAdapter<DownloadStatus> {
+public class DownloadLogAdapter extends BaseAdapter {
- public DownloadLogAdapter(Context context, int textViewResourceId,
- List<DownloadStatus> objects) {
- super(context, textViewResourceId, objects);
+ private Context context;
+ private FeedManager manager = FeedManager.getInstance();
+
+ public DownloadLogAdapter(Context context) {
+ super();
+ this.context = context;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Holder holder;
DownloadStatus status = getItem(position);
- FeedFile feedfile = status.getFeedFile();
if (convertView == null) {
holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
+ LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.downloadlog_item, null);
holder.title = (TextView) convertView.findViewById(R.id.txtvTitle);
@@ -71,7 +72,7 @@ public class DownloadLogAdapter extends ArrayAdapter<DownloadStatus> {
holder.successful.setTextColor(convertView.getResources().getColor(
R.color.download_failed_red));
holder.successful.setText(R.string.download_failed);
- String reasonText = DownloadError.getErrorString(getContext(),
+ String reasonText = DownloadError.getErrorString(context,
status.getReason());
if (status.getReasonDetailed() != null) {
reasonText += ": " + status.getReasonDetailed();
@@ -91,4 +92,19 @@ public class DownloadLogAdapter extends ArrayAdapter<DownloadStatus> {
TextView reason;
}
+ @Override
+ public int getCount() {
+ return manager.getDownloadLogSize();
+ }
+
+ @Override
+ public DownloadStatus getItem(int position) {
+ return manager.getDownloadStatusFromLogAtIndex(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
}
diff --git a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java
index 2670dfa44..db716c66e 100644
--- a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java
@@ -1,7 +1,5 @@
package de.danoeh.antennapod.adapter;
-import java.util.List;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.view.LayoutInflater;
@@ -12,14 +10,13 @@ import android.widget.BaseExpandableListAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.asynctask.FeedImageLoader;
+import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.feed.FeedItem;
+import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.Converter;
-import de.danoeh.antennapod.util.EpisodeFilter;
/**
* Displays unread items and items in the queue in one combined list. The
@@ -32,21 +29,17 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
public static final int GROUP_POS_UNREAD = 1;
private Context context;
-
- private List<FeedItem> unreadItems;
- private List<FeedItem> queueItems;
+ private FeedManager manager = FeedManager.getInstance();
private ActionButtonCallback feedItemActionCallback;
private OnGroupActionClicked groupActionCallback;
public ExternalEpisodesListAdapter(Context context,
- List<FeedItem> unreadItems, List<FeedItem> queueItems,
ActionButtonCallback callback,
OnGroupActionClicked groupActionCallback) {
super();
this.context = context;
- this.unreadItems = unreadItems;
- this.queueItems = queueItems;
+
this.feedItemActionCallback = callback;
this.groupActionCallback = groupActionCallback;
}
@@ -58,22 +51,10 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
@Override
public FeedItem getChild(int groupPosition, int childPosition) {
- final boolean displayOnlyEpisodes = PodcastApp.getInstance()
- .displayOnlyEpisodes();
if (groupPosition == GROUP_POS_QUEUE) {
- if (displayOnlyEpisodes) {
- return EpisodeFilter.accessEpisodeByIndex(queueItems,
- childPosition);
- } else {
- return queueItems.get(childPosition);
- }
+ return manager.getQueueItemAtIndex(childPosition, true);
} else if (groupPosition == GROUP_POS_UNREAD) {
- if (displayOnlyEpisodes) {
- return EpisodeFilter.accessEpisodeByIndex(unreadItems,
- childPosition);
- } else {
- return unreadItems.get(childPosition);
- }
+ return manager.getUnreadItemAtIndex(childPosition, true);
}
return null;
}
@@ -180,8 +161,9 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
holder.lenSize.setVisibility(View.INVISIBLE);
}
- holder.feedImage.setTag(item.getFeed().getImage());
- FeedImageLoader.getInstance().loadThumbnailBitmap(
+ holder.feedImage.setTag((item.getFeed().getImage() != null) ? item
+ .getFeed().getImage().getFile_url() : null);
+ ImageLoader.getInstance().loadThumbnailBitmap(
item.getFeed().getImage(),
holder.feedImage,
(int) convertView.getResources().getDimension(
@@ -213,20 +195,10 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
@Override
public int getChildrenCount(int groupPosition) {
- final boolean displayOnlyEpisodes = PodcastApp.getInstance()
- .displayOnlyEpisodes();
if (groupPosition == GROUP_POS_QUEUE) {
- if (displayOnlyEpisodes) {
- return EpisodeFilter.countItemsWithEpisodes(queueItems);
- } else {
- return queueItems.size();
- }
+ return manager.getQueueSize(true);
} else if (groupPosition == GROUP_POS_UNREAD) {
- if (displayOnlyEpisodes) {
- return EpisodeFilter.countItemsWithEpisodes(unreadItems);
- } else {
- return unreadItems.size();
- }
+ return manager.getUnreadItemsSize(true);
}
return 0;
}
@@ -254,12 +226,12 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
String headerString = null;
if (groupPosition == 0) {
headerString = context.getString(R.string.queue_label);
- if (!queueItems.isEmpty()) {
+ if (manager.getQueueSize(true) > 0) {
headerString += " (" + getChildrenCount(GROUP_POS_QUEUE) + ")";
}
} else {
headerString = context.getString(R.string.new_label);
- if (!unreadItems.isEmpty()) {
+ if (manager.getUnreadItemsSize(true) > 0) {
headerString += " (" + getChildrenCount(GROUP_POS_UNREAD) + ")";
}
}
@@ -277,7 +249,8 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
@Override
public boolean isEmpty() {
- return unreadItems.isEmpty() && queueItems.isEmpty();
+ return manager.getUnreadItemsSize(true) == 0
+ && manager.getQueueSize(true) == 0;
}
@Override
diff --git a/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
index 5941d52ea..0dda5d035 100644
--- a/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/FeedItemlistAdapter.java
@@ -1,11 +1,9 @@
package de.danoeh.antennapod.adapter;
import java.text.DateFormat;
-import java.util.List;
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.Typeface;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -24,16 +22,20 @@ import de.danoeh.antennapod.util.Converter;
import de.danoeh.antennapod.util.ThemeUtils;
public class FeedItemlistAdapter extends AbstractFeedItemlistAdapter {
+
+ private Context context;
+
private ActionButtonCallback callback;
private boolean showFeedtitle;
private int selectedItemIndex;
public static final int SELECTION_NONE = -1;
- public FeedItemlistAdapter(Context context, int textViewResourceId,
- List<FeedItem> objects, ActionButtonCallback callback,
- boolean showFeedtitle) {
- super(context, textViewResourceId, objects);
+ public FeedItemlistAdapter(Context context,
+ AbstractFeedItemlistAdapter.ItemAccess itemAccess,
+ ActionButtonCallback callback, boolean showFeedtitle) {
+ super(itemAccess);
+ this.context = context;
this.callback = callback;
this.showFeedtitle = showFeedtitle;
this.selectedItemIndex = SELECTION_NONE;
@@ -46,7 +48,7 @@ public class FeedItemlistAdapter extends AbstractFeedItemlistAdapter {
if (convertView == null) {
holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
+ LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.feeditemlist_item, null);
holder.title = (TextView) convertView
@@ -161,7 +163,7 @@ public class FeedItemlistAdapter extends AbstractFeedItemlistAdapter {
holder.downloading.setVisibility(View.GONE);
}
- TypedArray typeDrawables = getContext().obtainStyledAttributes(
+ TypedArray typeDrawables = context.obtainStyledAttributes(
new int[] { R.attr.type_audio, R.attr.type_video });
MediaType mediaType = item.getMedia().getMediaType();
if (mediaType == MediaType.AUDIO) {
diff --git a/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java b/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java
index f89f2854a..d7ea0c160 100644
--- a/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/FeedlistAdapter.java
@@ -1,34 +1,37 @@
package de.danoeh.antennapod.adapter;
import java.text.DateFormat;
-import java.util.List;
import android.content.Context;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.asynctask.FeedImageLoader;
+import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.ThemeUtils;
-public class FeedlistAdapter extends ArrayAdapter<Feed> {
+public class FeedlistAdapter extends BaseAdapter {
private static final String TAG = "FeedlistAdapter";
+ private Context context;
+ private FeedManager manager = FeedManager.getInstance();
+
private int selectedItemIndex;
- private FeedImageLoader imageLoader;
+ private ImageLoader imageLoader;
public static final int SELECTION_NONE = -1;
- public FeedlistAdapter(Context context, int textViewResourceId,
- List<Feed> objects) {
- super(context, textViewResourceId, objects);
+ public FeedlistAdapter(Context context) {
+ super();
+ this.context = context;
selectedItemIndex = SELECTION_NONE;
- imageLoader = FeedImageLoader.getInstance();
+ imageLoader = ImageLoader.getInstance();
}
@Override
@@ -39,7 +42,7 @@ public class FeedlistAdapter extends ArrayAdapter<Feed> {
// Inflate Layout
if (convertView == null) {
holder = new Holder();
- LayoutInflater inflater = (LayoutInflater) getContext()
+ LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.feedlist_item, null);
@@ -83,7 +86,7 @@ public class FeedlistAdapter extends ArrayAdapter<Feed> {
.getTime(), System.currentTimeMillis(),
DateFormat.MEDIUM, DateFormat.SHORT));
}
- holder.numberOfEpisodes.setText(feed.getNumOfItems()
+ holder.numberOfEpisodes.setText(feed.getNumOfItems(true)
+ convertView.getResources()
.getString(R.string.episodes_suffix));
@@ -105,8 +108,9 @@ public class FeedlistAdapter extends ArrayAdapter<Feed> {
holder.inProgressEpisodesLabel.setVisibility(View.INVISIBLE);
}
- holder.image.setTag(feed.getImage());
-
+ final String imageUrl = (feed.getImage() != null) ? feed.getImage()
+ .getFile_url() : null;
+ holder.image.setTag(imageUrl);
imageLoader.loadThumbnailBitmap(
feed.getImage(),
holder.image,
@@ -136,4 +140,19 @@ public class FeedlistAdapter extends ArrayAdapter<Feed> {
notifyDataSetChanged();
}
+ @Override
+ public int getCount() {
+ return manager.getFeedsSize();
+ }
+
+ @Override
+ public Feed getItem(int position) {
+ return manager.getFeedAtIndex(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
}
diff --git a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java
index c7f42e7cb..129289d30 100644
--- a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java
+++ b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java
@@ -10,7 +10,7 @@ import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.asynctask.FeedImageLoader;
+import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedComponent;
import de.danoeh.antennapod.feed.FeedItem;
@@ -51,7 +51,7 @@ public class SearchlistAdapter extends ArrayAdapter<SearchResult> {
final Feed feed = (Feed) component;
holder.title.setText(feed.getTitle());
holder.subtitle.setVisibility(View.GONE);
- FeedImageLoader.getInstance().loadThumbnailBitmap(feed.getImage(),
+ ImageLoader.getInstance().loadThumbnailBitmap(feed.getImage(),
holder.cover, (int) convertView.getResources().getDimension(R.dimen.thumbnail_length));
} else if (component.getClass() == FeedItem.class) {
final FeedItem item = (FeedItem) component;
@@ -61,7 +61,7 @@ public class SearchlistAdapter extends ArrayAdapter<SearchResult> {
holder.subtitle.setText(result.getSubtitle());
}
- FeedImageLoader.getInstance().loadThumbnailBitmap(
+ ImageLoader.getInstance().loadThumbnailBitmap(
item.getFeed().getImage(),
holder.cover,
(int) convertView.getResources().getDimension(
diff --git a/src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java b/src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java
index c23c4c66a..810a17165 100644
--- a/src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java
+++ b/src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java
@@ -11,10 +11,10 @@ import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.util.BitmapDecoder;
-public abstract class BitmapDecodeWorkerTask extends Thread {
+public class BitmapDecodeWorkerTask extends Thread {
protected int PREFERRED_LENGTH;
-
+
/** Can be thumbnail or cover */
protected int imageType;
@@ -25,7 +25,7 @@ public abstract class BitmapDecodeWorkerTask extends Thread {
protected String fileUrl;
private Handler handler;
-
+
private final int defaultCoverResource;
public BitmapDecodeWorkerTask(Handler handler, ImageView target,
@@ -36,7 +36,8 @@ public abstract class BitmapDecodeWorkerTask extends Thread {
this.fileUrl = fileUrl;
this.PREFERRED_LENGTH = length;
this.imageType = imageType;
- TypedArray res = target.getContext().obtainStyledAttributes(new int[] {R.attr.default_cover});
+ TypedArray res = target.getContext().obtainStyledAttributes(
+ new int[] { R.attr.default_cover });
this.defaultCoverResource = res.getResourceId(0, 0);
res.recycle();
}
@@ -45,7 +46,9 @@ public abstract class BitmapDecodeWorkerTask extends Thread {
* Should return true if tag of the imageview is still the same it was
* before the bitmap was decoded
*/
- abstract protected boolean tagsMatching(ImageView target);
+ protected boolean tagsMatching(ImageView target) {
+ return target.getTag() == null || target.getTag() == fileUrl;
+ }
protected void onPostExecute() {
// check if imageview is still supposed to display this image
@@ -64,13 +67,15 @@ public abstract class BitmapDecodeWorkerTask extends Thread {
f = new File(fileUrl);
}
if (fileUrl != null && f.exists()) {
- cBitmap = new CachedBitmap(BitmapDecoder.decodeBitmap(PREFERRED_LENGTH, fileUrl), PREFERRED_LENGTH);
+ cBitmap = new CachedBitmap(BitmapDecoder.decodeBitmap(
+ PREFERRED_LENGTH, fileUrl), PREFERRED_LENGTH);
if (cBitmap.getBitmap() != null) {
storeBitmapInCache(cBitmap);
} else {
Log.w(TAG, "Could not load bitmap. Using default image.");
- cBitmap = new CachedBitmap(BitmapFactory.decodeResource(target.getResources(),
- defaultCoverResource), PREFERRED_LENGTH);
+ cBitmap = new CachedBitmap(BitmapFactory.decodeResource(
+ target.getResources(), defaultCoverResource),
+ PREFERRED_LENGTH);
}
if (AppConfig.DEBUG)
Log.d(TAG, "Finished loading bitmaps");
@@ -98,15 +103,15 @@ public abstract class BitmapDecodeWorkerTask extends Thread {
protected void onInvalidFileUrl() {
Log.e(TAG, "FeedImage has no valid file url. Using default image");
- cBitmap = new CachedBitmap(BitmapFactory.decodeResource(target.getResources(),
- defaultCoverResource), PREFERRED_LENGTH);
+ cBitmap = new CachedBitmap(BitmapFactory.decodeResource(
+ target.getResources(), defaultCoverResource), PREFERRED_LENGTH);
}
protected void storeBitmapInCache(CachedBitmap cb) {
- FeedImageLoader loader = FeedImageLoader.getInstance();
- if (imageType == FeedImageLoader.IMAGE_TYPE_COVER) {
+ ImageLoader loader = ImageLoader.getInstance();
+ if (imageType == ImageLoader.IMAGE_TYPE_COVER) {
loader.addBitmapToCoverCache(fileUrl, cb);
- } else if (imageType == FeedImageLoader.IMAGE_TYPE_THUMBNAIL) {
+ } else if (imageType == ImageLoader.IMAGE_TYPE_THUMBNAIL) {
loader.addBitmapToThumbnailCache(fileUrl, cb);
}
}
diff --git a/src/de/danoeh/antennapod/asynctask/FeedImageLoader.java b/src/de/danoeh/antennapod/asynctask/ImageLoader.java
index 5e1994adb..d0f20d621 100644
--- a/src/de/danoeh/antennapod/asynctask/FeedImageLoader.java
+++ b/src/de/danoeh/antennapod/asynctask/ImageLoader.java
@@ -16,13 +16,11 @@ import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.feed.FeedImage;
-import de.danoeh.antennapod.feed.FeedManager;
-import de.danoeh.antennapod.storage.DownloadRequester;
/** Caches and loads FeedImage bitmaps in the background */
-public class FeedImageLoader {
- private static final String TAG = "FeedImageLoader";
- private static FeedImageLoader singleton;
+public class ImageLoader {
+ private static final String TAG = "ImageLoader";
+ private static ImageLoader singleton;
public static final int IMAGE_TYPE_THUMBNAIL = 0;
public static final int IMAGE_TYPE_COVER = 1;
@@ -44,7 +42,7 @@ public class FeedImageLoader {
private LruCache<String, CachedBitmap> coverCache;
private LruCache<String, CachedBitmap> thumbnailCache;
- private FeedImageLoader() {
+ private ImageLoader() {
handler = new Handler();
executor = createExecutor();
@@ -79,9 +77,9 @@ public class FeedImageLoader {
});
}
- public static FeedImageLoader getInstance() {
+ public static ImageLoader getInstance() {
if (singleton == null) {
- singleton = new FeedImageLoader();
+ singleton = new ImageLoader();
}
return singleton;
}
@@ -92,8 +90,18 @@ public class FeedImageLoader {
* ImageView's size has already been set or inside a Runnable which is
* posted to the ImageView's message queue.
*/
+ public void loadCoverBitmap(String fileUrl, ImageView target) {
+ loadCoverBitmap(fileUrl, target, target.getHeight());
+ }
+
public void loadCoverBitmap(FeedImage image, ImageView target) {
- loadCoverBitmap(image, target, target.getHeight());
+ loadCoverBitmap((image != null) ? image.getFile_url() : null, target,
+ target.getHeight());
+ }
+
+ public void loadCoverBitmap(FeedImage image, ImageView target, int length) {
+ loadCoverBitmap((image != null) ? image.getFile_url() : null, target,
+ length);
}
/**
@@ -102,17 +110,18 @@ public class FeedImageLoader {
* ImageView's size has already been set or inside a Runnable which is
* posted to the ImageView's message queue.
*/
- public void loadCoverBitmap(FeedImage image, ImageView target, int length) {
- final int defaultCoverResource = getDefaultCoverResource(target.getContext());
-
- if (image != null && image.getFile_url() != null) {
- CachedBitmap cBitmap = getBitmapFromCoverCache(image.getFile_url());
+ public void loadCoverBitmap(String fileUrl, ImageView target, int length) {
+ final int defaultCoverResource = getDefaultCoverResource(target
+ .getContext());
+
+ if (fileUrl != null) {
+ CachedBitmap cBitmap = getBitmapFromCoverCache(fileUrl);
if (cBitmap != null && cBitmap.getLength() >= length) {
target.setImageBitmap(cBitmap.getBitmap());
} else {
target.setImageResource(defaultCoverResource);
- FeedImageDecodeWorkerTask worker = new FeedImageDecodeWorkerTask(
- handler, target, image, length, IMAGE_TYPE_COVER);
+ BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask(
+ handler, target, fileUrl, length, IMAGE_TYPE_COVER);
executor.submit(worker);
}
} else {
@@ -126,8 +135,19 @@ public class FeedImageLoader {
* called if the ImageView's size has already been set or inside a Runnable
* which is posted to the ImageView's message queue.
*/
+ public void loadThumbnailBitmap(String fileUrl, ImageView target) {
+ loadThumbnailBitmap(fileUrl, target, target.getHeight());
+ }
+
public void loadThumbnailBitmap(FeedImage image, ImageView target) {
- loadThumbnailBitmap(image, target, target.getHeight());
+ loadThumbnailBitmap((image != null) ? image.getFile_url() : null,
+ target, target.getHeight());
+ }
+
+ public void loadThumbnailBitmap(FeedImage image, ImageView target,
+ int length) {
+ loadThumbnailBitmap((image != null) ? image.getFile_url() : null,
+ target, length);
}
/**
@@ -136,18 +156,18 @@ public class FeedImageLoader {
* called if the ImageView's size has already been set or inside a Runnable
* which is posted to the ImageView's message queue.
*/
- public void loadThumbnailBitmap(FeedImage image, ImageView target,
- int length) {
- final int defaultCoverResource = getDefaultCoverResource(target.getContext());
-
- if (image != null && image.getFile_url() != null) {
- CachedBitmap cBitmap = getBitmapFromThumbnailCache(image.getFile_url());
+ public void loadThumbnailBitmap(String fileUrl, ImageView target, int length) {
+ final int defaultCoverResource = getDefaultCoverResource(target
+ .getContext());
+
+ if (fileUrl != null) {
+ CachedBitmap cBitmap = getBitmapFromThumbnailCache(fileUrl);
if (cBitmap != null && cBitmap.getLength() >= length) {
target.setImageBitmap(cBitmap.getBitmap());
} else {
target.setImageResource(defaultCoverResource);
- FeedImageDecodeWorkerTask worker = new FeedImageDecodeWorkerTask(
- handler, target, image, length, IMAGE_TYPE_THUMBNAIL);
+ BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask(
+ handler, target, fileUrl, length, IMAGE_TYPE_THUMBNAIL);
executor.submit(worker);
}
} else {
@@ -168,8 +188,8 @@ public class FeedImageLoader {
thumbnailCache.evictAll();
}
- public boolean isInThumbnailCache(FeedImage image) {
- return thumbnailCache.get(image.getFile_url()) != null;
+ public boolean isInThumbnailCache(String fileUrl) {
+ return thumbnailCache.get(fileUrl) != null;
}
private CachedBitmap getBitmapFromThumbnailCache(String key) {
@@ -180,8 +200,8 @@ public class FeedImageLoader {
thumbnailCache.put(key, bitmap);
}
- public boolean isInCoverCache(FeedImage image) {
- return coverCache.get(image.getFile_url()) != null;
+ public boolean isInCoverCache(String fileUrl) {
+ return coverCache.get(fileUrl) != null;
}
private CachedBitmap getBitmapFromCoverCache(String key) {
@@ -191,43 +211,13 @@ public class FeedImageLoader {
public void addBitmapToCoverCache(String key, CachedBitmap bitmap) {
coverCache.put(key, bitmap);
}
-
+
private int getDefaultCoverResource(Context context) {
- TypedArray res = context.obtainStyledAttributes(new int[] {R.attr.default_cover});
+ TypedArray res = context
+ .obtainStyledAttributes(new int[] { R.attr.default_cover });
final int defaultCoverResource = res.getResourceId(0, 0);
res.recycle();
return defaultCoverResource;
}
- class FeedImageDecodeWorkerTask extends BitmapDecodeWorkerTask {
-
- private static final String TAG = "FeedImageDecodeWorkerTask";
-
- protected FeedImage image;
-
- public FeedImageDecodeWorkerTask(Handler handler, ImageView target,
- FeedImage image, int length, int imageType) {
- super(handler, target, image.getFile_url(), length, imageType);
- this.image = image;
- }
-
- @Override
- protected boolean tagsMatching(ImageView target) {
- return target.getTag() == null || target.getTag() == image;
- }
-
- @Override
- protected void onInvalidFileUrl() {
- super.onInvalidFileUrl();
- if (image.getFile_url() != null
- && !DownloadRequester.getInstance()
- .isDownloadingFile(image)) {
- FeedManager.getInstance().notifyInvalidImageFile(
- PodcastApp.getInstance(), image);
- }
-
- }
-
- }
-
}
diff --git a/src/de/danoeh/antennapod/asynctask/OpmlExportWorker.java b/src/de/danoeh/antennapod/asynctask/OpmlExportWorker.java
index db9ae999c..978f53ac6 100644
--- a/src/de/danoeh/antennapod/asynctask/OpmlExportWorker.java
+++ b/src/de/danoeh/antennapod/asynctask/OpmlExportWorker.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.asynctask;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
+import java.util.Arrays;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
@@ -15,6 +16,7 @@ import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.opml.OpmlWriter;
+import de.danoeh.antennapod.preferences.UserPreferences;
/** Writes an OPML file into the export directory in the background. */
public class OpmlExportWorker extends AsyncTask<Void, Void, Void> {
@@ -40,7 +42,7 @@ public class OpmlExportWorker extends AsyncTask<Void, Void, Void> {
OpmlWriter opmlWriter = new OpmlWriter();
if (output == null) {
output = new File(
- PodcastApp.getDataFolder(context, PodcastApp.EXPORT_DIR),
+ UserPreferences.getDataFolder(context, PodcastApp.EXPORT_DIR),
DEFAULT_OUTPUT_NAME);
if (output.exists()) {
Log.w(TAG, "Overwriting previously exported file.");
@@ -49,7 +51,7 @@ public class OpmlExportWorker extends AsyncTask<Void, Void, Void> {
}
try {
FileWriter writer = new FileWriter(output);
- opmlWriter.writeDocument(FeedManager.getInstance().getFeeds(),
+ opmlWriter.writeDocument(Arrays.asList(FeedManager.getInstance().getFeedsArray()),
writer);
writer.close();
} catch (IOException e) {
diff --git a/src/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java b/src/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
index a3652e05d..4d9c9867e 100644
--- a/src/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
+++ b/src/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java
@@ -7,7 +7,6 @@ import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
import de.danoeh.antennapod.activity.OpmlImportHolder;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.opml.OpmlElement;
diff --git a/src/de/danoeh/antennapod/asynctask/OpmlImportWorker.java b/src/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
index 2c1d30bdb..5af06895f 100644
--- a/src/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
+++ b/src/de/danoeh/antennapod/asynctask/OpmlImportWorker.java
@@ -1,6 +1,7 @@
package de.danoeh.antennapod.asynctask;
-import java.io.*;
+import java.io.IOException;
+import java.io.Reader;
import java.util.ArrayList;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/src/de/danoeh/antennapod/feed/Chapter.java b/src/de/danoeh/antennapod/feed/Chapter.java
index 10575e03d..ebf8ed44f 100644
--- a/src/de/danoeh/antennapod/feed/Chapter.java
+++ b/src/de/danoeh/antennapod/feed/Chapter.java
@@ -5,7 +5,6 @@ public abstract class Chapter extends FeedComponent {
/** Defines starting point in milliseconds. */
protected long start;
protected String title;
- protected FeedItem item;
protected String link;
public Chapter() {
@@ -20,7 +19,6 @@ public abstract class Chapter extends FeedComponent {
super();
this.start = start;
this.title = title;
- this.item = item;
this.link = link;
}
@@ -34,10 +32,6 @@ public abstract class Chapter extends FeedComponent {
return title;
}
- public FeedItem getItem() {
- return item;
- }
-
public String getLink() {
return link;
}
@@ -50,10 +44,6 @@ public abstract class Chapter extends FeedComponent {
this.title = title;
}
- public void setItem(FeedItem item) {
- this.item = item;
- }
-
public void setLink(String link) {
this.link = link;
}
diff --git a/src/de/danoeh/antennapod/feed/EventDistributor.java b/src/de/danoeh/antennapod/feed/EventDistributor.java
new file mode 100644
index 000000000..1fc7e2c35
--- /dev/null
+++ b/src/de/danoeh/antennapod/feed/EventDistributor.java
@@ -0,0 +1,140 @@
+package de.danoeh.antennapod.feed;
+
+import java.util.AbstractQueue;
+import java.util.Observable;
+import java.util.Observer;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import android.os.Handler;
+import android.util.Log;
+import de.danoeh.antennapod.AppConfig;
+
+/**
+ * Notifies its observers about changes in the feed database. Observers can
+ * register by retrieving an instance of this class and registering an
+ * EventListener. When new events arrive, the EventDistributor will process the
+ * event queue in a handler that runs on the main thread. The observers will only
+ * be notified once if the event queue contains multiple elements.
+ *
+ * Events can be sent with the send* methods.
+ */
+public class EventDistributor extends Observable {
+ private static final String TAG = "EventDistributor";
+
+ public static final int FEED_LIST_UPDATE = 1;
+ public static final int UNREAD_ITEMS_UPDATE = 2;
+ public static final int QUEUE_UPDATE = 4;
+ public static final int DOWNLOADLOG_UPDATE = 8;
+ public static final int PLAYBACK_HISTORY_UPDATE = 16;
+ public static final int DOWNLOAD_QUEUED = 32;
+ public static final int DOWNLOAD_HANDLED = 64;
+
+ private Handler handler;
+ private AbstractQueue<Integer> events;
+
+ private static EventDistributor instance;
+
+ private EventDistributor() {
+ this.handler = new Handler();
+ events = new ConcurrentLinkedQueue<Integer>();
+ }
+
+ public static EventDistributor getInstance() {
+ if (instance == null) {
+ instance = new EventDistributor();
+ }
+ return instance;
+ }
+
+ public void register(EventListener el) {
+ addObserver(el);
+ }
+
+ public void unregister(EventListener el) {
+ deleteObserver(el);
+ }
+
+ public void addEvent(Integer i) {
+ events.offer(i);
+ handler.post(new Runnable() {
+
+ @Override
+ public void run() {
+ processEventQueue();
+ }
+ });
+ }
+
+ private void processEventQueue() {
+ Integer result = 0;
+ if (AppConfig.DEBUG)
+ Log.d(TAG,
+ "Processing event queue. Number of events: "
+ + events.size());
+ for (Integer current = events.poll(); current != null; current = events
+ .poll()) {
+ result |= current;
+ }
+ if (result != 0) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Notifying observers. Data: " + result);
+ setChanged();
+ notifyObservers(result);
+ } else {
+ if (AppConfig.DEBUG)
+ Log.d(TAG,
+ "Event queue didn't contain any new events. Observers will not be notified.");
+ }
+ }
+
+ @Override
+ public void addObserver(Observer observer) {
+ super.addObserver(observer);
+ if (!(observer instanceof EventListener)) {
+ throw new IllegalArgumentException(
+ "Observer must be instance of FeedManager.EventListener");
+ }
+ }
+
+ public void sendDownloadQueuedBroadcast() {
+ addEvent(DOWNLOAD_QUEUED);
+ }
+
+ public void sendUnreadItemsUpdateBroadcast() {
+ addEvent(UNREAD_ITEMS_UPDATE);
+ }
+
+ public void sendQueueUpdateBroadcast() {
+ addEvent(QUEUE_UPDATE);
+ }
+
+ public void sendFeedUpdateBroadcast() {
+ addEvent(FEED_LIST_UPDATE);
+ }
+
+ public void sendPlaybackHistoryUpdateBroadcast() {
+ addEvent(PLAYBACK_HISTORY_UPDATE);
+ }
+
+ public void sendDownloadLogUpdateBroadcast() {
+ addEvent(DOWNLOADLOG_UPDATE);
+ }
+
+ public void sendDownloadHandledBroadcast() {
+ addEvent(DOWNLOAD_HANDLED);
+ }
+
+ public static abstract class EventListener implements Observer {
+
+ @Override
+ public void update(Observable observable, Object data) {
+ if (observable instanceof EventDistributor
+ && data instanceof Integer) {
+ update((EventDistributor) observable, (Integer) data);
+ }
+ }
+
+ public abstract void update(EventDistributor eventDistributor,
+ Integer arg);
+ }
+}
diff --git a/src/de/danoeh/antennapod/feed/Feed.java b/src/de/danoeh/antennapod/feed/Feed.java
index 4df9fc43f..6220bde00 100644
--- a/src/de/danoeh/antennapod/feed/Feed.java
+++ b/src/de/danoeh/antennapod/feed/Feed.java
@@ -1,12 +1,12 @@
package de.danoeh.antennapod.feed;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import android.preference.PreferenceManager;
-import de.danoeh.antennapod.PodcastApp;
+import de.danoeh.antennapod.preferences.UserPreferences;
+import de.danoeh.antennapod.util.EpisodeFilter;
/**
* Data Object for a whole feed
@@ -39,7 +39,7 @@ public class Feed extends FeedFile {
public Feed(Date lastUpdate) {
super();
- items = new CopyOnWriteArrayList<FeedItem>();
+ items = Collections.synchronizedList(new ArrayList<FeedItem>());
this.lastUpdate = lastUpdate;
}
@@ -68,13 +68,10 @@ public class Feed extends FeedFile {
* */
public int getNumOfNewItems() {
int count = 0;
- boolean displayOnlyEpisodes = PreferenceManager
- .getDefaultSharedPreferences(PodcastApp.getInstance())
- .getBoolean(PodcastApp.PREF_DISPLAY_ONLY_EPISODES, false);
-
for (FeedItem item : items) {
if (item.getState() == FeedItem.State.NEW) {
- if (!displayOnlyEpisodes || item.getMedia() != null) {
+ if (!UserPreferences.isDisplayOnlyEpisodes()
+ || item.getMedia() != null) {
count++;
}
}
@@ -100,17 +97,18 @@ public class Feed extends FeedFile {
}
/**
- * Returns true if at least one item in the itemlist is unread.If the
- * 'display only episodes' - preference is set to true, this method will
- * only count items with episodes.
+ * Returns true if at least one item in the itemlist is unread.
+ *
+ * @param enableEpisodeFilter
+ * true if this method should only count items with episodes if
+ * the 'display only episodes' - preference is set to true by the
+ * user.
*/
- public boolean hasNewItems() {
- boolean displayOnlyEpisodes = PreferenceManager
- .getDefaultSharedPreferences(PodcastApp.getInstance())
- .getBoolean(PodcastApp.PREF_DISPLAY_ONLY_EPISODES, false);
+ public boolean hasNewItems(boolean enableEpisodeFilter) {
for (FeedItem item : items) {
if (item.getState() == FeedItem.State.NEW) {
- if (!displayOnlyEpisodes || item.getMedia() != null) {
+ if (!(enableEpisodeFilter && UserPreferences
+ .isDisplayOnlyEpisodes()) || item.getMedia() != null) {
return true;
}
}
@@ -119,21 +117,34 @@ public class Feed extends FeedFile {
}
/**
- * Returns the number of FeedItems. If the 'display only episodes' -
- * preference is set to true, this method will only count items with
- * episodes.
+ * Returns the number of FeedItems.
+ *
+ * @param enableEpisodeFilter
+ * true if this method should only count items with episodes if
+ * the 'display only episodes' - preference is set to true by the
+ * user.
* */
- public int getNumOfItems() {
- int count = 0;
- boolean displayOnlyEpisodes = PreferenceManager
- .getDefaultSharedPreferences(PodcastApp.getInstance())
- .getBoolean(PodcastApp.PREF_DISPLAY_ONLY_EPISODES, false);
- for (FeedItem item : items) {
- if (!displayOnlyEpisodes || item.getMedia() != null) {
- count++;
- }
+ public int getNumOfItems(boolean enableEpisodeFilter) {
+ if (enableEpisodeFilter && UserPreferences.isDisplayOnlyEpisodes()) {
+ return EpisodeFilter.countItemsWithEpisodes(items);
+ } else {
+ return items.size();
+ }
+ }
+
+ /**
+ * Returns the item at the specified index.
+ *
+ * @param enableEpisodeFilter
+ * true if this method should ignore items without episdodes if
+ * the episodes filter has been enabled by the user.
+ */
+ public FeedItem getItemAtIndex(boolean enableEpisodeFilter, int position) {
+ if (enableEpisodeFilter && UserPreferences.isDisplayOnlyEpisodes()) {
+ return EpisodeFilter.accessEpisodeByIndex(items, position);
+ } else {
+ return items.get(position);
}
- return count;
}
/**
@@ -273,12 +284,17 @@ public class Feed extends FeedFile {
this.image = image;
}
- public List<FeedItem> getItems() {
+ List<FeedItem> getItems() {
return items;
}
public void setItems(ArrayList<FeedItem> items) {
- this.items = items;
+ this.items = Collections.synchronizedList(items);
+ }
+
+ /** Returns an array that contains all the feeditems of this feed. */
+ public FeedItem[] getItemsArray() {
+ return items.toArray(new FeedItem[items.size()]);
}
public Date getLastUpdate() {
diff --git a/src/de/danoeh/antennapod/feed/FeedItem.java b/src/de/danoeh/antennapod/feed/FeedItem.java
index 06fdc4292..bb176c411 100644
--- a/src/de/danoeh/antennapod/feed/FeedItem.java
+++ b/src/de/danoeh/antennapod/feed/FeedItem.java
@@ -4,7 +4,7 @@ import java.lang.ref.SoftReference;
import java.util.Date;
import java.util.List;
-import de.danoeh.antennapod.PodcastApp;
+import de.danoeh.antennapod.preferences.PlaybackPreferences;
/**
* Data Object for a XML message
@@ -92,27 +92,6 @@ public class FeedItem extends FeedComponent {
contentEncoded = null;
}
- /** Get the chapter that fits the position. */
- public Chapter getCurrentChapter(int position) {
- Chapter current = null;
- if (chapters != null) {
- current = chapters.get(0);
- for (Chapter sc : chapters) {
- if (sc.getStart() > position) {
- break;
- } else {
- current = sc;
- }
- }
- }
- return current;
- }
-
- /** Calls getCurrentChapter with current position. */
- public Chapter getCurrentChapter() {
- return getCurrentChapter(media.getPosition());
- }
-
/**
* Returns the value that uniquely identifies this FeedItem. If the
* itemIdentifier attribute is not null, it will be returned. Else it will
@@ -234,7 +213,7 @@ public class FeedItem extends FeedComponent {
private boolean isPlaying() {
if (media != null) {
- if (PodcastApp.getCurrentlyPlayingMediaId() == media.getId()) {
+ if (PlaybackPreferences.getCurrentlyPlayingFeedMediaId() == media.getId()) {
return true;
}
}
diff --git a/src/de/danoeh/antennapod/feed/FeedManager.java b/src/de/danoeh/antennapod/feed/FeedManager.java
index 6c3471e5c..e984da46a 100644
--- a/src/de/danoeh/antennapod/feed/FeedManager.java
+++ b/src/de/danoeh/antennapod/feed/FeedManager.java
@@ -19,13 +19,15 @@ import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.asynctask.DownloadStatus;
+import de.danoeh.antennapod.preferences.PlaybackPreferences;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.PlaybackService;
import de.danoeh.antennapod.storage.DownloadRequestException;
import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.storage.PodDBAdapter;
import de.danoeh.antennapod.util.DownloadError;
+import de.danoeh.antennapod.util.EpisodeFilter;
import de.danoeh.antennapod.util.FeedtitleComparator;
import de.danoeh.antennapod.util.comparator.DownloadStatusComparator;
import de.danoeh.antennapod.util.comparator.FeedItemPubdateComparator;
@@ -33,21 +35,16 @@ import de.danoeh.antennapod.util.comparator.PlaybackCompletionDateComparator;
import de.danoeh.antennapod.util.exception.MediaFileNotFoundException;
/**
- * Singleton class Manages all feeds, categories and feeditems
- *
+ * Singleton class that - provides access to all Feeds and FeedItems and to
+ * several lists of FeedItems. - provides methods for modifying the
+ * application's data - takes care of updating the information stored in the
+ * database when something is modified
*
+ * An instance of this class can be retrieved via getInstance().
* */
public class FeedManager {
private static final String TAG = "FeedManager";
- public static final String ACTION_FEED_LIST_UPDATE = "de.danoeh.antennapod.action.feed.feedlistUpdate";
- public static final String ACTION_UNREAD_ITEMS_UPDATE = "de.danoeh.antennapod.action.feed.unreadItemsUpdate";
- public static final String ACTION_QUEUE_UPDATE = "de.danoeh.antennapod.action.feed.queueUpdate";
- public static final String ACTION_DOWNLOADLOG_UPDATE = "de.danoeh.antennapod.action.feed.downloadLogUpdate";
- public static final String ACTION_PLAYBACK_HISTORY_UPDATE = "de.danoeh.antennapod.action.feed.playbackHistoryUpdate";
- public static final String EXTRA_FEED_ITEM_ID = "de.danoeh.antennapod.extra.feed.feedItemId";
- public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feed.feedId";
-
/** Number of completed Download status entries to store. */
private static final int DOWNLOAD_LOG_SIZE = 50;
@@ -59,7 +56,7 @@ public class FeedManager {
private List<FeedItem> unreadItems;
/** Contains completed Download status entries */
- private ArrayList<DownloadStatus> downloadLog;
+ private List<DownloadStatus> downloadLog;
/** Contains the queue of items to be played. */
private List<FeedItem> queue;
@@ -70,10 +67,15 @@ public class FeedManager {
/** Maximum number of items in the playback history. */
private static final int PLAYBACK_HISTORY_SIZE = 15;
- private DownloadRequester requester;
+ private DownloadRequester requester = DownloadRequester.getInstance();
+ private EventDistributor eventDist = EventDistributor.getInstance();
- /** Should be used to change the content of the arrays from another thread. */
+ /**
+ * Should be used to change the content of the arrays from another thread to
+ * ensure that arrays are only modified on the main thread.
+ */
private Handler contentChanger;
+
/** Ensures that there are no parallel db operations. */
private Executor dbExec;
@@ -83,7 +85,6 @@ public class FeedManager {
private FeedManager() {
feeds = Collections.synchronizedList(new ArrayList<Feed>());
unreadItems = Collections.synchronizedList(new ArrayList<FeedItem>());
- requester = DownloadRequester.getInstance();
downloadLog = new ArrayList<DownloadStatus>();
queue = Collections.synchronizedList(new ArrayList<FeedItem>());
playbackHistory = Collections
@@ -100,6 +101,7 @@ public class FeedManager {
});
}
+ /** Creates a new instance of this class if necessary and returns it. */
public static FeedManager getInstance() {
if (singleton == null) {
singleton = new FeedManager();
@@ -119,6 +121,8 @@ public class FeedManager {
* if Mediaplayer activity shall be started
* @param startWhenPrepared
* if Mediaplayer shall be started after it has been prepared
+ * @param shouldStream
+ * if Mediaplayer should stream the file
*/
public void playMedia(Context context, FeedMedia media, boolean showPlayer,
boolean startWhenPrepared, boolean shouldStream) {
@@ -132,10 +136,7 @@ public class FeedManager {
}
// Start playback Service
Intent launchIntent = new Intent(context, PlaybackService.class);
- launchIntent
- .putExtra(PlaybackService.EXTRA_MEDIA_ID, media.getId());
- launchIntent.putExtra(PlaybackService.EXTRA_FEED_ID, media
- .getItem().getFeed().getId());
+ launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED,
startWhenPrepared);
launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM,
@@ -150,11 +151,7 @@ public class FeedManager {
}
} catch (MediaFileNotFoundException e) {
e.printStackTrace();
- SharedPreferences prefs = PreferenceManager
- .getDefaultSharedPreferences(context);
- final long lastPlayedId = prefs.getLong(
- PlaybackService.PREF_LAST_PLAYED_ID, -1);
- if (lastPlayedId == media.getId()) {
+ if (PlaybackPreferences.getLastPlayedId() == media.getId()) {
context.sendBroadcast(new Intent(
PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
}
@@ -176,14 +173,12 @@ public class FeedManager {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
- final long lastPlayedId = prefs.getLong(
- PlaybackService.PREF_LAST_PLAYED_ID, -1);
- if (media.getId() == lastPlayedId) {
+ if (media.getId() == PlaybackPreferences.getLastPlayedId()) {
SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(PlaybackService.PREF_LAST_IS_STREAM, true);
+ editor.putBoolean(PlaybackPreferences.PREF_LAST_IS_STREAM, true);
editor.commit();
}
- if (lastPlayedId == media.getId()) {
+ if (PlaybackPreferences.getLastPlayedId() == media.getId()) {
context.sendBroadcast(new Intent(
PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
}
@@ -197,14 +192,12 @@ public class FeedManager {
public void deleteFeed(final Context context, final Feed feed) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context.getApplicationContext());
- long lastPlayedFeed = prefs.getLong(
- PlaybackService.PREF_LAST_PLAYED_FEED_ID, -1);
- if (lastPlayedFeed == feed.getId()) {
+ if (PlaybackPreferences.getLastPlayedFeedId() == feed.getId()) {
context.sendBroadcast(new Intent(
PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
SharedPreferences.Editor editor = prefs.edit();
- editor.putLong(PlaybackService.PREF_LAST_PLAYED_ID, -1);
- editor.putLong(PlaybackService.PREF_LAST_PLAYED_FEED_ID, -1);
+ editor.putLong(PlaybackPreferences.PREF_LAST_PLAYED_ID, -1);
+ editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, -1);
editor.commit();
}
@@ -213,7 +206,7 @@ public class FeedManager {
@Override
public void run() {
feeds.remove(feed);
- sendFeedUpdateBroadcast(context);
+ eventDist.sendFeedUpdateBroadcast();
dbExec.execute(new Runnable() {
@Override
@@ -266,32 +259,6 @@ public class FeedManager {
}
- private void sendUnreadItemsUpdateBroadcast(Context context, FeedItem item) {
- Intent update = new Intent(ACTION_UNREAD_ITEMS_UPDATE);
- if (item != null) {
- update.putExtra(EXTRA_FEED_ID, item.getFeed().getId());
- update.putExtra(EXTRA_FEED_ITEM_ID, item.getId());
- }
- context.sendBroadcast(update);
- }
-
- private void sendQueueUpdateBroadcast(Context context, FeedItem item) {
- Intent update = new Intent(ACTION_QUEUE_UPDATE);
- if (item != null) {
- update.putExtra(EXTRA_FEED_ID, item.getFeed().getId());
- update.putExtra(EXTRA_FEED_ITEM_ID, item.getId());
- }
- context.sendBroadcast(update);
- }
-
- private void sendFeedUpdateBroadcast(Context context) {
- context.sendBroadcast(new Intent(ACTION_FEED_LIST_UPDATE));
- }
-
- private void sendPlaybackHistoryUpdateBroadcast(Context context) {
- context.sendBroadcast(new Intent(ACTION_PLAYBACK_HISTORY_UPDATE));
- }
-
/**
* Makes sure that playback history is sorted and is not larger than
* PLAYBACK_HISTORY_SIZE.
@@ -346,6 +313,7 @@ public class FeedManager {
}
}
+ /** Removes all items from the playback history. */
public void clearPlaybackHistory(final Context context) {
if (!playbackHistory.isEmpty()) {
if (AppConfig.DEBUG)
@@ -353,7 +321,7 @@ public class FeedManager {
final FeedItem[] items = playbackHistory
.toArray(new FeedItem[playbackHistory.size()]);
playbackHistory.clear();
- sendPlaybackHistoryUpdateBroadcast(context);
+ eventDist.sendPlaybackHistoryUpdateBroadcast();
dbExec.execute(new Runnable() {
@Override
@@ -373,6 +341,7 @@ public class FeedManager {
}
}
+ /** Adds a FeedItem to the playback history. */
public void addItemToPlaybackHistory(Context context, FeedItem item) {
if (item.getMedia() != null
&& item.getMedia().getPlaybackCompletionDate() != null) {
@@ -382,13 +351,13 @@ public class FeedManager {
playbackHistory.add(item);
}
cleanupPlaybackHistoryWithDBCleanup(context);
- sendPlaybackHistoryUpdateBroadcast(context);
+ eventDist.sendPlaybackHistoryUpdateBroadcast();
}
}
private void removeItemFromPlaybackHistory(Context context, FeedItem item) {
playbackHistory.remove(item);
- sendPlaybackHistoryUpdateBroadcast(context);
+ eventDist.sendPlaybackHistoryUpdateBroadcast();
}
/**
@@ -420,7 +389,7 @@ public class FeedManager {
Collections.sort(unreadItems,
new FeedItemPubdateComparator());
}
- sendUnreadItemsUpdateBroadcast(context, item);
+ eventDist.sendUnreadItemsUpdateBroadcast();
}
});
@@ -428,8 +397,6 @@ public class FeedManager {
/**
* Sets the 'read' attribute of all FeedItems of a specific feed to true
- *
- * @param context
*/
public void markFeedRead(Context context, Feed feed) {
for (FeedItem item : feed.getItems()) {
@@ -449,7 +416,7 @@ public class FeedManager {
final ArrayList<FeedItem> unreadItemsCopy = new ArrayList<FeedItem>(
unreadItems);
unreadItems.clear();
- sendUnreadItemsUpdateBroadcast(context, null);
+ eventDist.sendUnreadItemsUpdateBroadcast();
dbExec.execute(new Runnable() {
@Override
@@ -467,6 +434,7 @@ public class FeedManager {
}
+ /** Updates all feeds in the feed list. */
@SuppressLint("NewApi")
public void refreshAllFeeds(final Context context) {
if (AppConfig.DEBUG)
@@ -536,15 +504,17 @@ public class FeedManager {
media.setDownloaded(false);
media.setFile_url(null);
setFeedMedia(context, media);
- sendFeedUpdateBroadcast(context);
+ eventDist.sendFeedUpdateBroadcast();
}
+ /** Updates a specific feed. */
public void refreshFeed(Context context, Feed feed)
throws DownloadRequestException {
requester.downloadFeed(context, new Feed(feed.getDownload_url(),
new Date(), feed.getTitle()));
}
+ /** Adds a download status object to the download log. */
public void addDownloadStatus(final Context context,
final DownloadStatus status) {
contentChanger.post(new Runnable() {
@@ -559,7 +529,7 @@ public class FeedManager {
} else {
removedStatus = null;
}
- context.sendBroadcast(new Intent(ACTION_DOWNLOADLOG_UPDATE));
+ eventDist.sendDownloadLogUpdateBroadcast();
dbExec.execute(new Runnable() {
@Override
@@ -578,6 +548,7 @@ public class FeedManager {
}
+ /** Downloads all items in the queue that have not been downloaded yet. */
public void downloadAllItemsInQueue(final Context context) {
if (!queue.isEmpty()) {
try {
@@ -589,11 +560,9 @@ public class FeedManager {
}
}
+ /** Downloads FeedItems if they have not been downloaded yet. */
public void downloadFeedItem(final Context context, FeedItem... items)
throws DownloadRequestException {
- boolean autoQueue = PreferenceManager.getDefaultSharedPreferences(
- context.getApplicationContext()).getBoolean(
- PodcastApp.PREF_AUTO_QUEUE, true);
List<FeedItem> addToQueue = new ArrayList<FeedItem>();
for (FeedItem item : items) {
@@ -618,12 +587,16 @@ public class FeedManager {
addToQueue.add(item);
}
}
- if (autoQueue) {
+ if (UserPreferences.isAutoQueue()) {
addQueueItem(context,
addToQueue.toArray(new FeedItem[addToQueue.size()]));
}
}
+ /**
+ * Enqueues all items that are currently in the unreadItems list and marks
+ * them as 'read'.
+ */
public void enqueueAllNewItems(final Context context) {
if (!unreadItems.isEmpty()) {
addQueueItem(context,
@@ -632,6 +605,7 @@ public class FeedManager {
}
}
+ /** Adds FeedItems to the queue if they are not in the queue yet. */
public void addQueueItem(final Context context, final FeedItem... items) {
if (items.length > 0) {
contentChanger.post(new Runnable() {
@@ -643,7 +617,7 @@ public class FeedManager {
queue.add(item);
}
}
- sendQueueUpdateBroadcast(context, items[0]);
+ eventDist.sendQueueUpdateBroadcast();
dbExec.execute(new Runnable() {
@Override
@@ -679,7 +653,7 @@ public class FeedManager {
if (AppConfig.DEBUG)
Log.d(TAG, "Clearing queue");
queue.clear();
- sendQueueUpdateBroadcast(context, null);
+ eventDist.sendQueueUpdateBroadcast();
dbExec.execute(new Runnable() {
@Override
@@ -693,8 +667,8 @@ public class FeedManager {
}
- /** Uses external adapter. */
- public void removeQueueItem(FeedItem item, PodDBAdapter adapter) {
+ /** Removes a FeedItem from the queue. Uses external PodDBAdapter. */
+ private void removeQueueItem(FeedItem item, PodDBAdapter adapter) {
boolean removed = queue.remove(item);
if (removed) {
adapter.setQueue(queue);
@@ -702,7 +676,7 @@ public class FeedManager {
}
- /** Uses its own adapter. */
+ /** Removes a FeedItem from the queue. */
public void removeQueueItem(final Context context, FeedItem item) {
boolean removed = queue.remove(item);
if (removed) {
@@ -719,7 +693,7 @@ public class FeedManager {
});
}
- sendQueueUpdateBroadcast(context, item);
+ eventDist.sendQueueUpdateBroadcast();
}
/**
@@ -732,25 +706,20 @@ public class FeedManager {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context
.getApplicationContext());
- boolean autoDelete = prefs.getBoolean(PodcastApp.PREF_AUTO_DELETE,
- false);
- if (autoDelete) {
- long lastPlayedId = prefs.getLong(
- PlaybackService.PREF_LAST_PLAYED_ID, -1);
- long autoDeleteId = prefs.getLong(
- PlaybackService.PREF_AUTODELETE_MEDIA_ID, -1);
- boolean playbackCompleted = prefs
- .getBoolean(
- PlaybackService.PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED,
- false);
- if ((media.getId() != lastPlayedId)
- && ((media.getId() != autoDeleteId) || (media.getId() == autoDeleteId && playbackCompleted))) {
+ if (UserPreferences.isAutoDelete()) {
+
+ if ((media.getId() != PlaybackPreferences.getLastPlayedId())
+ && ((media.getId() != PlaybackPreferences
+ .getAutoDeleteMediaId()) || (media.getId() == PlaybackPreferences
+ .getAutoDeleteMediaId() && PlaybackPreferences
+ .isAutoDeleteMediaPlaybackCompleted()))) {
if (AppConfig.DEBUG)
Log.d(TAG, "Performing auto-cleanup");
deleteFeedMedia(context, media);
SharedPreferences.Editor editor = prefs.edit();
- editor.putLong(PlaybackService.PREF_AUTODELETE_MEDIA_ID, -1);
+ editor.putLong(
+ PlaybackPreferences.PREF_AUTODELETE_MEDIA_ID, -1);
editor.commit();
} else {
if (AppConfig.DEBUG)
@@ -797,15 +766,20 @@ public class FeedManager {
}
});
if (broadcastUpdate) {
- sendQueueUpdateBroadcast(context, item);
+ eventDist.sendQueueUpdateBroadcast();
}
}
}
+ /** Returns true if the specified item is in the queue. */
public boolean isInQueue(FeedItem item) {
return queue.contains(item);
}
+ /**
+ * Returns the FeedItem at the beginning of the queue or null if the queue
+ * is empty.
+ */
public FeedItem getFirstQueueItem() {
if (queue.isEmpty()) {
return null;
@@ -821,7 +795,7 @@ public class FeedManager {
public void run() {
feeds.add(feed);
Collections.sort(feeds, new FeedtitleComparator());
- sendFeedUpdateBroadcast(context);
+ eventDist.sendFeedUpdateBroadcast();
}
});
setCompleteFeed(context, feed);
@@ -884,7 +858,7 @@ public class FeedManager {
}
- /** Get a Feed by its link */
+ /** Get a Feed by its identifying value. */
private Feed searchFeedByIdentifyingValue(String identifier) {
for (Feed feed : feeds) {
if (feed.getIdentifyingValue().equals(identifier)) {
@@ -919,7 +893,7 @@ public class FeedManager {
}
/** Updates Information of an existing Feed. Uses external adapter. */
- public void setFeed(Feed feed, PodDBAdapter adapter) {
+ private void setFeed(Feed feed, PodDBAdapter adapter) {
if (adapter != null) {
adapter.setFeed(feed);
feed.cacheDescriptionsOfItems();
@@ -929,7 +903,7 @@ public class FeedManager {
}
/** Updates Information of an existing Feeditem. Uses external adapter. */
- public void setFeedItem(FeedItem item, PodDBAdapter adapter) {
+ private void setFeedItem(FeedItem item, PodDBAdapter adapter) {
if (adapter != null) {
adapter.setSingleFeedItem(item);
} else {
@@ -938,7 +912,7 @@ public class FeedManager {
}
/** Updates Information of an existing Feedimage. Uses external adapter. */
- public void setFeedImage(FeedImage image, PodDBAdapter adapter) {
+ private void setFeedImage(FeedImage image, PodDBAdapter adapter) {
if (adapter != null) {
adapter.setImage(image);
} else {
@@ -950,7 +924,7 @@ public class FeedManager {
* Updates Information of an existing Feedmedia object. Uses external
* adapter.
*/
- public void setFeedImage(FeedMedia media, PodDBAdapter adapter) {
+ private void setFeedImage(FeedMedia media, PodDBAdapter adapter) {
if (adapter != null) {
adapter.setMedia(media);
} else {
@@ -1126,6 +1100,7 @@ public class FeedManager {
return null;
}
+ /** Get a download status object from the download log by its FeedFile. */
public DownloadStatus getDownloadStatus(FeedFile feedFile) {
for (DownloadStatus status : downloadLog) {
if (status.getFeedFile() == feedFile) {
@@ -1137,10 +1112,6 @@ public class FeedManager {
/** Reads the database */
public void loadDBData(Context context) {
- updateArrays(context);
- }
-
- public void updateArrays(Context context) {
feeds.clear();
PodDBAdapter adapter = new PodDBAdapter(context);
adapter.open();
@@ -1445,6 +1416,17 @@ public class FeedManager {
});
}
+ /**
+ * Searches the descriptions of FeedItems of a specific feed for a given
+ * string.
+ *
+ * @param feed
+ * The feed whose items should be searched.
+ * @param query
+ * The search string
+ * @param callback
+ * A callback which will be used to return the search result
+ * */
public void searchFeedItemDescription(final Context context,
final Feed feed, final String query,
FeedManager.QueryTaskCallback callback) {
@@ -1460,6 +1442,17 @@ public class FeedManager {
});
}
+ /**
+ * Searches the 'contentEncoded' field of FeedItems of a specific feed for a
+ * given string.
+ *
+ * @param feed
+ * The feed whose items should be searched.
+ * @param query
+ * The search string
+ * @param callback
+ * A callback which will be used to return the search result
+ * */
public void searchFeedItemContentEncoded(final Context context,
final Feed feed, final String query,
FeedManager.QueryTaskCallback callback) {
@@ -1475,24 +1468,116 @@ public class FeedManager {
});
}
- public List<Feed> getFeeds() {
+ /** Returns the number of feeds that are currently in the feeds list. */
+ public int getFeedsSize() {
+ return feeds.size();
+ }
+
+ /** Returns the feed at the specified index of the feeds list. */
+ public Feed getFeedAtIndex(int index) {
+ return feeds.get(index);
+ }
+
+ /** Returns an array that contains all feeds of the feed manager. */
+ public Feed[] getFeedsArray() {
+ return feeds.toArray(new Feed[feeds.size()]);
+ }
+
+ List<Feed> getFeeds() {
return feeds;
}
- public List<FeedItem> getUnreadItems() {
- return unreadItems;
+ /**
+ * Returns the number of items that are currently in the queue.
+ *
+ * @param enableEpisodeFilter
+ * true if items without episodes should be ignored by this
+ * method if the episode filter was enabled by the user.
+ * */
+ public int getQueueSize(boolean enableEpisodeFilter) {
+ if (UserPreferences.isDisplayOnlyEpisodes() && enableEpisodeFilter) {
+ return EpisodeFilter.countItemsWithEpisodes(queue);
+ } else {
+ return queue.size();
+ }
+ }
+
+ /**
+ * Returns the FeedItem at the specified index of the queue.
+ *
+ * @param enableEpisodeFilter
+ * true if items without episodes should be ignored by this
+ * method if the episode filter was enabled by the user.
+ *
+ * @throws IndexOutOfBoundsException
+ * if index is out of range
+ * */
+ public FeedItem getQueueItemAtIndex(int index, boolean enableEpisodeFilter) {
+ if (UserPreferences.isDisplayOnlyEpisodes() && enableEpisodeFilter) {
+ return EpisodeFilter.accessEpisodeByIndex(queue, index);
+ } else {
+ return queue.get(index);
+ }
+ }
+
+ /**
+ * Returns the number of unread items.
+ *
+ * @param enableEpisodeFilter
+ * true if items without episodes should be ignored by this
+ * method if the episode filter was enabled by the user.
+ * */
+ public int getUnreadItemsSize(boolean enableEpisodeFilter) {
+ if (UserPreferences.isDisplayOnlyEpisodes() && enableEpisodeFilter) {
+ return EpisodeFilter.countItemsWithEpisodes(unreadItems);
+ } else {
+ return unreadItems.size();
+ }
+ }
+
+ /**
+ * Returns the FeedItem at the specified index of the unread items list.
+ *
+ * @param enableEpisodeFilter
+ * true if items without episodes should be ignored by this
+ * method if the episode filter was enabled by the user.
+ *
+ * @throws IndexOutOfBoundsException
+ * if index is out of range
+ * */
+ public FeedItem getUnreadItemAtIndex(int index, boolean enableEpisodeFilter) {
+ if (UserPreferences.isDisplayOnlyEpisodes() && enableEpisodeFilter) {
+ return EpisodeFilter.accessEpisodeByIndex(unreadItems, index);
+ } else {
+ return unreadItems.get(index);
+ }
+ }
+
+ /**
+ * Returns the number of items in the playback history.
+ * */
+ public int getPlaybackHistorySize() {
+ return playbackHistory.size();
}
- public ArrayList<DownloadStatus> getDownloadLog() {
- return downloadLog;
+ /**
+ * Returns the FeedItem at the specified index of the playback history.
+ *
+ * @throws IndexOutOfBoundsException
+ * if index is out of range
+ * */
+ public FeedItem getPlaybackHistoryItemIndex(int index) {
+ return playbackHistory.get(index);
}
- public List<FeedItem> getQueue() {
- return queue;
+ /** Returns the number of items in the download log */
+ public int getDownloadLogSize() {
+ return downloadLog.size();
}
- public List<FeedItem> getPlaybackHistory() {
- return playbackHistory;
+ /** Returns the download status at the specified index of the download log. */
+ public DownloadStatus getDownloadStatusFromLogAtIndex(int index) {
+ return downloadLog.get(index);
}
/** Is called by a FeedManagerTask after completion. */
@@ -1600,4 +1685,4 @@ public class FeedManager {
}
}
-}
+} \ No newline at end of file
diff --git a/src/de/danoeh/antennapod/feed/FeedMedia.java b/src/de/danoeh/antennapod/feed/FeedMedia.java
index a96649a62..de87c63a1 100644
--- a/src/de/danoeh/antennapod/feed/FeedMedia.java
+++ b/src/de/danoeh/antennapod/feed/FeedMedia.java
@@ -1,10 +1,23 @@
package de.danoeh.antennapod.feed;
import java.util.Date;
+import java.util.List;
-public class FeedMedia extends FeedFile {
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.os.Parcel;
+import android.os.Parcelable;
+import de.danoeh.antennapod.PodcastApp;
+import de.danoeh.antennapod.util.ChapterUtils;
+import de.danoeh.antennapod.util.playback.Playable;
+
+public class FeedMedia extends FeedFile implements Playable {
public static final int FEEDFILETYPE_FEEDMEDIA = 2;
+ public static final int PLAYABLE_TYPE_FEEDMEDIA = 1;
+
+ public static final String PREF_MEDIA_ID = "FeedMedia.PrefMediaId";
+ public static final String PREF_FEED_ID = "FeedMedia.PrefFeedId";
private int duration;
private int position; // Current position in file
@@ -146,7 +159,7 @@ public class FeedMedia extends FeedFile {
public boolean isInProgress() {
return (this.position > 0);
}
-
+
public FeedImage getImage() {
if (item != null && item.getFeed() != null) {
return item.getFeed().getImage();
@@ -154,4 +167,160 @@ public class FeedMedia extends FeedFile {
return null;
}
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(item.getFeed().getId());
+ dest.writeLong(item.getId());
+ }
+
+ @Override
+ public void writeToPreferences(Editor prefEditor) {
+ prefEditor.putLong(PREF_FEED_ID, item.getFeed().getId());
+ prefEditor.putLong(PREF_MEDIA_ID, id);
+ }
+
+ @Override
+ public void loadMetadata() throws PlayableException {
+ if (getChapters() == null) {
+ ChapterUtils.loadChaptersFromStreamUrl(this);
+ }
+ }
+
+ @Override
+ public String getEpisodeTitle() {
+ if (getItem().getTitle() != null) {
+ return getItem().getTitle();
+ } else {
+ return getItem().getIdentifyingValue();
+ }
+ }
+
+ @Override
+ public List<Chapter> getChapters() {
+ return getItem().getChapters();
+ }
+
+ @Override
+ public String getWebsiteLink() {
+ return getItem().getLink();
+ }
+
+ @Override
+ public String getFeedTitle() {
+ return getItem().getFeed().getTitle();
+ }
+
+ @Override
+ public String getImageFileUrl() {
+ if (getItem().getFeed().getImage() != null) {
+ return getItem().getFeed().getImage().getFile_url();
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return id;
+ }
+
+ @Override
+ public String getLocalMediaUrl() {
+ return file_url;
+ }
+
+ @Override
+ public String getStreamUrl() {
+ return download_url;
+ }
+
+ @Override
+ public boolean localFileAvailable() {
+ return isDownloaded() && file_url != null;
+ }
+
+ @Override
+ public boolean streamAvailable() {
+ return download_url != null;
+ }
+
+ @Override
+ public void saveCurrentPosition(SharedPreferences pref, int newPosition) {
+ position = newPosition;
+ FeedManager.getInstance().setFeedMedia(PodcastApp.getInstance(), this);
+ }
+
+ @Override
+ public void onPlaybackStart() {
+ if (getItem().isRead() == false) {
+ FeedManager.getInstance().markItemRead(PodcastApp.getInstance(),
+ getItem(), true, false);
+ }
+ }
+
+ @Override
+ public void onPlaybackCompleted() {
+
+ }
+
+ @Override
+ public int getPlayableType() {
+ return PLAYABLE_TYPE_FEEDMEDIA;
+ }
+
+ @Override
+ public void setChapters(List<Chapter> chapters) {
+ getItem().setChapters(chapters);
+ }
+
+ @Override
+ public String getPaymentLink() {
+ return getItem().getPaymentLink();
+ }
+
+ @Override
+ public void loadShownotes(final ShownoteLoaderCallback callback) {
+ String contentEncoded = item.getContentEncoded();
+ if (item.getDescription() == null || contentEncoded == null) {
+ FeedManager.getInstance().loadExtraInformationOfItem(
+ PodcastApp.getInstance(), item,
+ new FeedManager.TaskCallback<String[]>() {
+ @Override
+ public void onCompletion(String[] result) {
+ if (result[1] != null) {
+ callback.onShownotesLoaded(result[1]);
+ } else {
+ callback.onShownotesLoaded(result[0]);
+
+ }
+
+ }
+ });
+ } else {
+ callback.onShownotesLoaded(contentEncoded);
+ }
+ }
+
+ public static final Parcelable.Creator<FeedMedia> CREATOR = new Parcelable.Creator<FeedMedia>() {
+ public FeedMedia createFromParcel(Parcel in) {
+ long feedId = in.readLong();
+ long itemId = in.readLong();
+ FeedItem item = FeedManager.getInstance().getFeedItem(itemId,
+ feedId);
+ if (item != null) {
+ return item.getMedia();
+ } else {
+ return null;
+ }
+ }
+
+ public FeedMedia[] newArray(int size) {
+ return new FeedMedia[size];
+ }
+ };
}
diff --git a/src/de/danoeh/antennapod/fragment/CoverFragment.java b/src/de/danoeh/antennapod/fragment/CoverFragment.java
index f1fde24d8..c477ea2b8 100644
--- a/src/de/danoeh/antennapod/fragment/CoverFragment.java
+++ b/src/de/danoeh/antennapod/fragment/CoverFragment.java
@@ -12,31 +12,26 @@ import com.actionbarsherlock.app.SherlockFragment;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment;
-import de.danoeh.antennapod.asynctask.FeedImageLoader;
-import de.danoeh.antennapod.feed.Feed;
-import de.danoeh.antennapod.feed.FeedItem;
-import de.danoeh.antennapod.feed.FeedManager;
-import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.asynctask.ImageLoader;
+import de.danoeh.antennapod.util.playback.Playable;
/** Displays the cover and the title of a FeedItem. */
public class CoverFragment extends SherlockFragment implements
AudioplayerContentFragment {
private static final String TAG = "CoverFragment";
- private static final String ARG_FEED_ID = "arg.feedId";
- private static final String ARG_FEEDITEM_ID = "arg.feedItem";
+ private static final String ARG_PLAYABLE = "arg.playable";
- private FeedMedia media;
+ private Playable media;
private ImageView imgvCover;
private boolean viewCreated = false;
- public static CoverFragment newInstance(FeedItem item) {
+ public static CoverFragment newInstance(Playable item) {
CoverFragment f = new CoverFragment();
if (item != null) {
Bundle args = new Bundle();
- args.putLong(ARG_FEED_ID, item.getFeed().getId());
- args.putLong(ARG_FEEDITEM_ID, item.getId());
+ args.putParcelable(ARG_PLAYABLE, item);
f.setArguments(args);
}
return f;
@@ -46,21 +41,11 @@ public class CoverFragment extends SherlockFragment implements
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
- FeedManager manager = FeedManager.getInstance();
- FeedItem item = null;
Bundle args = getArguments();
if (args != null) {
- long feedId = args.getLong(ARG_FEED_ID, -1);
- long itemId = args.getLong(ARG_FEEDITEM_ID, -1);
- if (feedId != -1 && itemId != -1) {
- Feed feed = manager.getFeed(feedId);
- item = manager.getFeedItem(itemId, feed);
- if (item != null) {
- media = item.getMedia();
- }
- } else {
- Log.e(TAG, TAG + " was called with invalid arguments");
- }
+ media = args.getParcelable(ARG_PLAYABLE);
+ } else {
+ Log.e(TAG, TAG + " was called with invalid arguments");
}
}
@@ -79,8 +64,8 @@ public class CoverFragment extends SherlockFragment implements
@Override
public void run() {
- FeedImageLoader.getInstance().loadCoverBitmap(
- media.getItem().getFeed().getImage(), imgvCover);
+ ImageLoader.getInstance().loadCoverBitmap(
+ media.getImageFileUrl(), imgvCover);
}
});
} else {
@@ -103,7 +88,7 @@ public class CoverFragment extends SherlockFragment implements
}
@Override
- public void onDataSetChanged(FeedMedia media) {
+ public void onDataSetChanged(Playable media) {
this.media = media;
if (viewCreated) {
loadMediaInfo();
diff --git a/src/de/danoeh/antennapod/fragment/EpisodesFragment.java b/src/de/danoeh/antennapod/fragment/EpisodesFragment.java
index 843cf5af0..ac1fc402e 100644
--- a/src/de/danoeh/antennapod/fragment/EpisodesFragment.java
+++ b/src/de/danoeh/antennapod/fragment/EpisodesFragment.java
@@ -1,9 +1,6 @@
package de.danoeh.antennapod.fragment;
-import android.content.BroadcastReceiver;
-import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
@@ -25,16 +22,21 @@ import de.danoeh.antennapod.activity.OrganizeQueueActivity;
import de.danoeh.antennapod.adapter.ActionButtonCallback;
import de.danoeh.antennapod.adapter.ExternalEpisodesListAdapter;
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedManager;
-import de.danoeh.antennapod.service.download.DownloadService;
import de.danoeh.antennapod.storage.DownloadRequestException;
-import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
public class EpisodesFragment extends SherlockFragment {
private static final String TAG = "EpisodesFragment";
+ private static final int EVENTS = EventDistributor.QUEUE_UPDATE
+ | EventDistributor.UNREAD_ITEMS_UPDATE
+ | EventDistributor.FEED_LIST_UPDATE
+ | EventDistributor.DOWNLOAD_HANDLED
+ | EventDistributor.DOWNLOAD_QUEUED;
+
private ExpandableListView listView;
private ExternalEpisodesListAdapter adapter;
@@ -45,24 +47,14 @@ public class EpisodesFragment extends SherlockFragment {
@Override
public void onDestroy() {
super.onDestroy();
- try {
- getActivity().unregisterReceiver(contentUpdate);
- } catch (IllegalArgumentException e) {
-
- }
+ EventDistributor.getInstance().unregister(contentUpdate);
}
@Override
public void onResume() {
super.onResume();
- IntentFilter filter = new IntentFilter();
- filter.addAction(DownloadRequester.ACTION_DOWNLOAD_QUEUED);
- filter.addAction(DownloadService.ACTION_DOWNLOAD_HANDLED);
- filter.addAction(FeedManager.ACTION_QUEUE_UPDATE);
- filter.addAction(FeedManager.ACTION_UNREAD_ITEMS_UPDATE);
- filter.addAction(FeedManager.ACTION_FEED_LIST_UPDATE);
-
- getActivity().registerReceiver(contentUpdate, filter);
+
+ EventDistributor.getInstance().register(contentUpdate);
if (adapter != null) {
adapter.notifyDataSetChanged();
}
@@ -99,10 +91,8 @@ public class EpisodesFragment extends SherlockFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- FeedManager manager = FeedManager.getInstance();
adapter = new ExternalEpisodesListAdapter(getActivity(),
- manager.getUnreadItems(), manager.getQueue(), adapterCallback,
- groupActionCallback);
+ adapterCallback, groupActionCallback);
listView.setAdapter(adapter);
listView.expandGroup(ExternalEpisodesListAdapter.GROUP_POS_QUEUE);
listView.expandGroup(ExternalEpisodesListAdapter.GROUP_POS_UNREAD);
@@ -130,12 +120,15 @@ public class EpisodesFragment extends SherlockFragment {
registerForContextMenu(listView);
}
- private BroadcastReceiver contentUpdate = new BroadcastReceiver() {
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+
@Override
- public void onReceive(Context context, Intent intent) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Received contentUpdate Intent.");
- adapter.notifyDataSetChanged();
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((EVENTS & arg) != 0) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Received contentUpdate Intent.");
+ adapter.notifyDataSetChanged();
+ }
}
};
diff --git a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
index d79b7de10..94aa2b0fc 100644
--- a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
+++ b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java
@@ -14,11 +14,11 @@ import com.actionbarsherlock.app.SherlockFragment;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.asynctask.FeedImageLoader;
-import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.asynctask.ImageLoader;
import de.danoeh.antennapod.service.PlaybackService;
import de.danoeh.antennapod.util.Converter;
-import de.danoeh.antennapod.util.PlaybackController;
+import de.danoeh.antennapod.util.playback.Playable;
+import de.danoeh.antennapod.util.playback.PlaybackController;
/**
* Fragment which is supposed to be displayed outside of the MediaplayerActivity
@@ -193,11 +193,11 @@ public class ExternalPlayerFragment extends SherlockFragment {
if (AppConfig.DEBUG)
Log.d(TAG, "Loading media info");
if (controller.serviceAvailable()) {
- FeedMedia media = controller.getMedia();
+ Playable media = controller.getMedia();
if (media != null) {
- txtvTitle.setText(media.getItem().getTitle());
- FeedImageLoader.getInstance().loadThumbnailBitmap(
- media.getItem().getFeed().getImage(),
+ txtvTitle.setText(media.getEpisodeTitle());
+ ImageLoader.getInstance().loadThumbnailBitmap(
+ media.getImageFileUrl(),
imgvCover,
(int) getActivity().getResources().getDimension(
R.dimen.external_player_height));
diff --git a/src/de/danoeh/antennapod/fragment/FeedlistFragment.java b/src/de/danoeh/antennapod/fragment/FeedlistFragment.java
index caf6c6a7f..c3034c2af 100644
--- a/src/de/danoeh/antennapod/fragment/FeedlistFragment.java
+++ b/src/de/danoeh/antennapod/fragment/FeedlistFragment.java
@@ -2,11 +2,8 @@ package de.danoeh.antennapod.fragment;
import android.annotation.SuppressLint;
import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
@@ -18,7 +15,6 @@ import android.widget.ListView;
import android.widget.TextView;
import com.actionbarsherlock.app.SherlockFragment;
-import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
@@ -30,22 +26,26 @@ import de.danoeh.antennapod.adapter.FeedlistAdapter;
import de.danoeh.antennapod.asynctask.FeedRemover;
import de.danoeh.antennapod.dialog.ConfirmationDialog;
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedManager;
-import de.danoeh.antennapod.service.download.DownloadService;
import de.danoeh.antennapod.storage.DownloadRequestException;
-import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
public class FeedlistFragment extends SherlockFragment implements
ActionMode.Callback, AdapterView.OnItemClickListener,
AdapterView.OnItemLongClickListener {
private static final String TAG = "FeedlistFragment";
+
+ private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
+ | EventDistributor.DOWNLOAD_QUEUED
+ | EventDistributor.FEED_LIST_UPDATE
+ | EventDistributor.UNREAD_ITEMS_UPDATE;
+
public static final String EXTRA_SELECTED_FEED = "extra.de.danoeh.antennapod.activity.selected_feed";
private FeedManager manager;
private FeedlistAdapter fla;
- private SherlockFragmentActivity pActivity;
private Feed selectedFeed;
private ActionMode mActionMode;
@@ -57,13 +57,11 @@ public class FeedlistFragment extends SherlockFragment implements
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
- pActivity = (SherlockFragmentActivity) activity;
}
@Override
public void onDetach() {
super.onDetach();
- pActivity = null;
}
@Override
@@ -72,7 +70,7 @@ public class FeedlistFragment extends SherlockFragment implements
if (AppConfig.DEBUG)
Log.d(TAG, "Creating");
manager = FeedManager.getInstance();
- fla = new FeedlistAdapter(pActivity, 0, manager.getFeeds());
+ fla = new FeedlistAdapter(getActivity());
}
@@ -113,36 +111,28 @@ public class FeedlistFragment extends SherlockFragment implements
super.onResume();
if (AppConfig.DEBUG)
Log.d(TAG, "Resuming");
- IntentFilter filter = new IntentFilter();
- filter.addAction(DownloadRequester.ACTION_DOWNLOAD_QUEUED);
- filter.addAction(FeedManager.ACTION_UNREAD_ITEMS_UPDATE);
- filter.addAction(FeedManager.ACTION_FEED_LIST_UPDATE);
- filter.addAction(DownloadService.ACTION_DOWNLOAD_HANDLED);
- pActivity.registerReceiver(contentUpdate, filter);
+ EventDistributor.getInstance().register(contentUpdate);
fla.notifyDataSetChanged();
}
@Override
public void onPause() {
super.onPause();
- pActivity.unregisterReceiver(contentUpdate);
+ EventDistributor.getInstance().unregister(contentUpdate);
if (mActionMode != null) {
mActionMode.finish();
}
}
- private BroadcastReceiver contentUpdate = new BroadcastReceiver() {
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+
@Override
- public void onReceive(Context context, final Intent intent) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Received contentUpdate Intent.");
- getActivity().runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- fla.notifyDataSetChanged();
- }
- });
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((EVENTS & arg) != 0) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Received contentUpdate Intent.");
+ fla.notifyDataSetChanged();
+ }
}
};
@@ -211,10 +201,10 @@ public class FeedlistFragment extends SherlockFragment implements
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long id) {
Feed selection = fla.getItem(position);
- Intent showFeed = new Intent(pActivity, FeedItemlistActivity.class);
+ Intent showFeed = new Intent(getActivity(), FeedItemlistActivity.class);
showFeed.putExtra(EXTRA_SELECTED_FEED, selection.getId());
- pActivity.startActivity(showFeed);
+ getActivity().startActivity(showFeed);
}
@Override
diff --git a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
index 8f5350c8e..02b74a4e5 100644
--- a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -23,8 +23,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebSettings.LayoutAlgorithm;
import android.webkit.WebView;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
import android.widget.Toast;
import com.actionbarsherlock.app.SherlockFragment;
@@ -32,34 +30,46 @@ import com.actionbarsherlock.app.SherlockFragment;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedManager;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.util.ShareUtils;
+import de.danoeh.antennapod.util.playback.Playable;
-/** Displays the description of a FeedItem in a Webview. */
+/** Displays the description of a Playable object in a Webview. */
public class ItemDescriptionFragment extends SherlockFragment {
private static final String TAG = "ItemDescriptionFragment";
+ private static final String ARG_PLAYABLE = "arg.playable";
+
private static final String ARG_FEED_ID = "arg.feedId";
- private static final String ARG_FEEDITEM_ID = "arg.feedItemId";
+ private static final String ARG_FEED_ITEM_ID = "arg.feeditemId";
private WebView webvDescription;
+ private Playable media;
+
private FeedItem item;
private AsyncTask<Void, Void, Void> webViewLoader;
- private String descriptionRef;
- private String contentEncodedRef;
+ private String shownotes;
/** URL that was selected via long-press. */
private String selectedURL;
+ public static ItemDescriptionFragment newInstance(Playable media) {
+ ItemDescriptionFragment f = new ItemDescriptionFragment();
+ Bundle args = new Bundle();
+ args.putParcelable(ARG_PLAYABLE, media);
+ f.setArguments(args);
+ return f;
+ }
+
public static ItemDescriptionFragment newInstance(FeedItem item) {
ItemDescriptionFragment f = new ItemDescriptionFragment();
Bundle args = new Bundle();
args.putLong(ARG_FEED_ID, item.getFeed().getId());
- args.putLong(ARG_FEEDITEM_ID, item.getId());
+ args.putLong(ARG_FEED_ITEM_ID, item.getId());
f.setArguments(args);
return f;
}
@@ -72,12 +82,13 @@ public class ItemDescriptionFragment extends SherlockFragment {
Log.d(TAG, "Creating view");
webvDescription = new WebView(getActivity());
- if (PodcastApp.getThemeResourceId() == R.style.Theme_AntennaPod_Dark) {
+ if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) {
if (Build.VERSION.SDK_INT >= 11
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
webvDescription.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
- webvDescription.setBackgroundColor(getResources().getColor(R.color.black));
+ webvDescription.setBackgroundColor(getResources().getColor(
+ R.color.black));
}
webvDescription.getSettings().setUseWideViewPort(false);
webvDescription.getSettings().setLayoutAlgorithm(
@@ -126,50 +137,59 @@ public class ItemDescriptionFragment extends SherlockFragment {
super.onCreate(savedInstanceState);
if (AppConfig.DEBUG)
Log.d(TAG, "Creating fragment");
- FeedManager manager = FeedManager.getInstance();
Bundle args = getArguments();
- long feedId = args.getLong(ARG_FEED_ID, -1);
- long itemId = args.getLong(ARG_FEEDITEM_ID, -1);
- if (feedId != -1 && itemId != -1) {
- Feed feed = manager.getFeed(feedId);
- item = manager.getFeedItem(itemId, feed);
-
- } else {
- Log.e(TAG, TAG + " was called with invalid arguments");
+ if (args.containsKey(ARG_PLAYABLE)) {
+ media = args.getParcelable(ARG_PLAYABLE);
+ } else if (args.containsKey(ARG_FEED_ID)
+ && args.containsKey(ARG_FEED_ITEM_ID)) {
+ long feedId = args.getLong(ARG_FEED_ID);
+ long itemId = args.getLong(ARG_FEED_ITEM_ID);
+ FeedItem f = FeedManager.getInstance().getFeedItem(itemId, feedId);
+ if (f != null) {
+ item = f;
+ }
}
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- if (item != null) {
+ if (media != null) {
+ media.loadShownotes(new Playable.ShownoteLoaderCallback() {
+
+ @Override
+ public void onShownotesLoaded(String shownotes) {
+ ItemDescriptionFragment.this.shownotes = shownotes;
+ if (ItemDescriptionFragment.this.shownotes != null) {
+ startLoader();
+ }
+ }
+ });
+ } else if (item != null) {
if (item.getDescription() == null
|| item.getContentEncoded() == null) {
- Log.i(TAG, "Loading data");
FeedManager.getInstance().loadExtraInformationOfItem(
- getActivity(), item,
+ PodcastApp.getInstance(), item,
new FeedManager.TaskCallback<String[]>() {
@Override
public void onCompletion(String[] result) {
- if (result == null || result.length != 2) {
- Log.e(TAG, "No description found");
+ if (result[1] != null) {
+ shownotes = result[1];
} else {
- descriptionRef = result[0];
- contentEncodedRef = result[1];
+ shownotes = result[0];
+ }
+ if (shownotes != null) {
+ startLoader();
}
- startLoader();
}
});
} else {
- contentEncodedRef = item.getContentEncoded();
- descriptionRef = item.getDescription();
- if (AppConfig.DEBUG)
- Log.d(TAG, "Using cached data");
+ shownotes = item.getContentEncoded();
startLoader();
}
} else {
- Log.e(TAG, "Error in onViewCreated: Item was null");
+ Log.e(TAG, "Error in onViewCreated: Item and media were null");
}
}
@@ -197,8 +217,11 @@ public class ItemDescriptionFragment extends SherlockFragment {
* */
private String applyWebviewStyle(String textColor, String data) {
final String WEBVIEW_STYLE = "<html><head><style type=\"text/css\"> * { color: %s; font-family: Helvetica; line-height: 1.5em; font-size: 11pt; } a { font-style: normal; text-decoration: none; font-weight: normal; color: #00A8DF; } img { display: block; margin: 10 auto; max-width: %s; height: auto; } body { margin: %dpx %dpx %dpx %dpx; }</style></head><body>%s</body></html>";
- final int pageMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, getResources().getDisplayMetrics());
- return String.format(WEBVIEW_STYLE, textColor, "100%", pageMargin, pageMargin, pageMargin, pageMargin, data);
+ final int pageMargin = (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, 8, getResources()
+ .getDisplayMetrics());
+ return String.format(WEBVIEW_STYLE, textColor, "100%", pageMargin,
+ pageMargin, pageMargin, pageMargin, data);
}
private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
@@ -247,7 +270,8 @@ public class ItemDescriptionFragment extends SherlockFragment {
.getSystemService(Context.CLIPBOARD_SERVICE);
cm.setText(selectedURL);
}
- Toast t = Toast.makeText(getActivity(), R.string.copied_url_msg, Toast.LENGTH_SHORT);
+ Toast t = Toast.makeText(getActivity(),
+ R.string.copied_url_msg, Toast.LENGTH_SHORT);
t.show();
break;
default:
@@ -319,11 +343,7 @@ public class ItemDescriptionFragment extends SherlockFragment {
if (AppConfig.DEBUG)
Log.d(TAG, "Loading Webview");
data = "";
- if (contentEncodedRef == null && descriptionRef != null) {
- data = descriptionRef;
- } else {
- data = StringEscapeUtils.unescapeHtml4(contentEncodedRef);
- }
+ data = StringEscapeUtils.unescapeHtml4(shownotes);
Activity activity = getActivity();
if (activity != null) {
TypedArray res = getActivity()
diff --git a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java
index cdccdc338..9e9389838 100644
--- a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java
+++ b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java
@@ -1,11 +1,7 @@
package de.danoeh.antennapod.fragment;
-import java.util.List;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
+import android.annotation.SuppressLint;
import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
@@ -25,6 +21,7 @@ import de.danoeh.antennapod.adapter.AbstractFeedItemlistAdapter;
import de.danoeh.antennapod.adapter.ActionButtonCallback;
import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
+import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedManager;
@@ -34,22 +31,24 @@ import de.danoeh.antennapod.storage.DownloadRequester;
import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
/** Displays a list of FeedItems. */
+@SuppressLint("ValidFragment")
public class ItemlistFragment extends SherlockListFragment {
-
private static final String TAG = "ItemlistFragment";
+
+ private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
+ | EventDistributor.DOWNLOAD_QUEUED
+ | EventDistributor.QUEUE_UPDATE
+ | EventDistributor.UNREAD_ITEMS_UPDATE;
+
public static final String EXTRA_SELECTED_FEEDITEM = "extra.de.danoeh.antennapod.activity.selected_feeditem";
public static final String ARGUMENT_FEED_ID = "argument.de.danoeh.antennapod.feed_id";
protected AbstractFeedItemlistAdapter fila;
- protected FeedManager manager;
- protected DownloadRequester requester;
+ protected FeedManager manager = FeedManager.getInstance();
+ protected DownloadRequester requester = DownloadRequester.getInstance();
- /** The feed which the activity displays */
- protected List<FeedItem> items;
- /**
- * This is only not null if the fragment displays the items of a specific
- * feed
- */
- protected Feed feed;
+ private AbstractFeedItemlistAdapter.ItemAccess itemAccess;
+
+ private Feed feed;
protected FeedItem selectedItem = null;
protected boolean contextMenuClosed = true;
@@ -57,12 +56,11 @@ public class ItemlistFragment extends SherlockListFragment {
/** Argument for FeeditemlistAdapter */
protected boolean showFeedtitle;
- public ItemlistFragment(List<FeedItem> items, boolean showFeedtitle) {
+ public ItemlistFragment(AbstractFeedItemlistAdapter.ItemAccess itemAccess,
+ boolean showFeedtitle) {
super();
- this.items = items;
+ this.itemAccess = itemAccess;
this.showFeedtitle = showFeedtitle;
- manager = FeedManager.getInstance();
- requester = DownloadRequester.getInstance();
}
public ItemlistFragment() {
@@ -94,15 +92,27 @@ public class ItemlistFragment extends SherlockListFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (items == null) {
+ if (itemAccess == null) {
long feedId = getArguments().getLong(ARGUMENT_FEED_ID);
- feed = FeedManager.getInstance().getFeed(feedId);
- items = feed.getItems();
+ final Feed feed = FeedManager.getInstance().getFeed(feedId);
+ this.feed = feed;
+ itemAccess = new AbstractFeedItemlistAdapter.ItemAccess() {
+
+ @Override
+ public FeedItem getItem(int position) {
+ return feed.getItemAtIndex(true, position);
+ }
+
+ @Override
+ public int getCount() {
+ return feed.getNumOfItems(true);
+ }
+ };
}
}
protected AbstractFeedItemlistAdapter createListAdapter() {
- return new FeedItemlistAdapter(getActivity(), 0, items,
+ return new FeedItemlistAdapter(getActivity(), itemAccess,
adapterCallback, showFeedtitle);
}
@@ -114,12 +124,7 @@ public class ItemlistFragment extends SherlockListFragment {
@Override
public void onDestroy() {
super.onDestroy();
- try {
- getActivity().unregisterReceiver(contentUpdate);
- } catch (IllegalArgumentException e) {
- Log.w(TAG,
- "IllegalArgumentException when trying to unregister contentUpdate receiver.");
- }
+ EventDistributor.getInstance().unregister(contentUpdate);
}
@Override
@@ -133,13 +138,7 @@ public class ItemlistFragment extends SherlockListFragment {
}
});
updateProgressBarVisibility();
- IntentFilter filter = new IntentFilter();
- filter.addAction(DownloadRequester.ACTION_DOWNLOAD_QUEUED);
- filter.addAction(DownloadService.ACTION_DOWNLOAD_HANDLED);
- filter.addAction(FeedManager.ACTION_QUEUE_UPDATE);
- filter.addAction(FeedManager.ACTION_UNREAD_ITEMS_UPDATE);
-
- getActivity().registerReceiver(contentUpdate, filter);
+ EventDistributor.getInstance().register(contentUpdate);
}
@Override
@@ -153,17 +152,19 @@ public class ItemlistFragment extends SherlockListFragment {
startActivity(showItem);
}
- private BroadcastReceiver contentUpdate = new BroadcastReceiver() {
+ private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
+
@Override
- public void onReceive(Context context, Intent intent) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Received contentUpdate Intent.");
- if (intent.getAction().equals(
- DownloadRequester.ACTION_DOWNLOAD_QUEUED)) {
- updateProgressBarVisibility();
- } else {
- fila.notifyDataSetChanged();
- updateProgressBarVisibility();
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((EVENTS & arg) != 0) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Received contentUpdate Intent.");
+ if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) {
+ updateProgressBarVisibility();
+ } else {
+ fila.notifyDataSetChanged();
+ updateProgressBarVisibility();
+ }
}
}
};
@@ -178,7 +179,7 @@ public class ItemlistFragment extends SherlockListFragment {
getSherlockActivity()
.setSupportProgressBarIndeterminateVisibility(false);
}
- getSherlockActivity().invalidateOptionsMenu();
+ getSherlockActivity().supportInvalidateOptionsMenu();
}
}
diff --git a/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
index a2826c977..5c4750acd 100644
--- a/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
+++ b/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java
@@ -1,47 +1,55 @@
package de.danoeh.antennapod.fragment;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import de.danoeh.antennapod.AppConfig;
+import de.danoeh.antennapod.adapter.AbstractFeedItemlistAdapter;
+import de.danoeh.antennapod.feed.EventDistributor;
+import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedManager;
public class PlaybackHistoryFragment extends ItemlistFragment {
private static final String TAG = "PlaybackHistoryFragment";
public PlaybackHistoryFragment() {
- super(FeedManager.getInstance().getPlaybackHistory(), true);
+ super(new AbstractFeedItemlistAdapter.ItemAccess() {
+
+ @Override
+ public FeedItem getItem(int position) {
+ return FeedManager.getInstance().getPlaybackHistoryItemIndex(
+ position);
+ }
+
+ @Override
+ public int getCount() {
+ return FeedManager.getInstance().getPlaybackHistorySize();
+ }
+ }, true);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getActivity().registerReceiver(historyUpdate,
- new IntentFilter(FeedManager.ACTION_PLAYBACK_HISTORY_UPDATE));
+ EventDistributor.getInstance().register(historyUpdate);
}
@Override
public void onDestroy() {
super.onDestroy();
- try {
- getActivity().unregisterReceiver(historyUpdate);
- } catch (IllegalArgumentException e) {
- // ignore
- }
+ EventDistributor.getInstance().unregister(historyUpdate);
}
- private BroadcastReceiver historyUpdate = new BroadcastReceiver() {
-
+ private EventDistributor.EventListener historyUpdate = new EventDistributor.EventListener() {
+
@Override
- public void onReceive(Context context, Intent intent) {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Received content update");
- fila.notifyDataSetChanged();
+ public void update(EventDistributor eventDistributor, Integer arg) {
+ if ((EventDistributor.PLAYBACK_HISTORY_UPDATE & arg) != 0) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Received content update");
+ fila.notifyDataSetChanged();
+ }
+
}
-
};
}
diff --git a/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java b/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java
new file mode 100644
index 000000000..b93b2e07c
--- /dev/null
+++ b/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java
@@ -0,0 +1,193 @@
+package de.danoeh.antennapod.preferences;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import de.danoeh.antennapod.AppConfig;
+import de.danoeh.antennapod.feed.FeedManager;
+import de.danoeh.antennapod.feed.FeedMedia;
+
+/**
+ * Provides access to preferences set by the playback service. A private
+ * instance of this class must first be instantiated via createInstance() or
+ * otherwise every public method will throw an Exception when called.
+ */
+public class PlaybackPreferences implements
+ SharedPreferences.OnSharedPreferenceChangeListener {
+ private static final String TAG = "PlaybackPreferences";
+
+ /** Contains the type of the media that was played last. */
+ public static final String PREF_LAST_PLAYED_ID = "de.danoeh.antennapod.preferences.lastPlayedId";
+
+ /**
+ * Contains the feed id of the currently playing item if it is a FeedMedia
+ * object.
+ */
+ public static final String PREF_CURRENTLY_PLAYING_FEED_ID = "de.danoeh.antennapod.preferences.lastPlayedFeedId";
+
+ /**
+ * Contains the id of the currently playing FeedMedia object or
+ * NO_MEDIA_PLAYING if the currently playing media is no FeedMedia object.
+ */
+ public static final String PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID = "de.danoeh.antennapod.preferences.lastPlayedFeedMediaId";
+
+ /**
+ * Type of the media object that is currently being played. This preference
+ * is set to NO_MEDIA_PLAYING after playback has been completed and is set
+ * as soon as the 'play' button is pressed.
+ */
+ public static final String PREF_CURRENTLY_PLAYING_MEDIA = "de.danoeh.antennapod.preferences.currentlyPlayingMedia";
+
+ /** True if last played media was streamed. */
+ public static final String PREF_LAST_IS_STREAM = "de.danoeh.antennapod.preferences.lastIsStream";
+
+ /** True if last played media was a video. */
+ public static final String PREF_LAST_IS_VIDEO = "de.danoeh.antennapod.preferences.lastIsVideo";
+
+ /** True if playback of last played media has been completed. */
+ public static final String PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED = "de.danoeh.antennapod.preferences.lastPlaybackCompleted";
+
+ /**
+ * ID of the last played media which should be auto-deleted as soon as
+ * PREF_LAST_PLAYED_ID changes.
+ */
+ public static final String PREF_AUTODELETE_MEDIA_ID = "de.danoeh.antennapod.preferences.autoDeleteMediaId";
+
+ /** Value of PREF_CURRENTLY_PLAYING_MEDIA if no media is playing. */
+ public static final long NO_MEDIA_PLAYING = -1;
+
+ private long lastPlayedId;
+ private long currentlyPlayingFeedId;
+ private long currentlyPlayingFeedMediaId;
+ private long currentlyPlayingMedia;
+ private boolean lastIsStream;
+ private boolean lastIsVideo;
+ private boolean autoDeleteMediaPlaybackCompleted;
+ private long autoDeleteMediaId;
+
+ private static PlaybackPreferences instance;
+ private Context context;
+
+ private PlaybackPreferences(Context context) {
+ this.context = context;
+ loadPreferences();
+ }
+
+ /**
+ * Sets up the UserPreferences class.
+ *
+ * @throws IllegalArgumentException
+ * if context is null
+ * */
+ public static void createInstance(Context context) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Creating new instance of UserPreferences");
+ if (context == null)
+ throw new IllegalArgumentException("Context must not be null");
+ instance = new PlaybackPreferences(context);
+
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .registerOnSharedPreferenceChangeListener(instance);
+ }
+
+ private void loadPreferences() {
+ SharedPreferences sp = PreferenceManager
+ .getDefaultSharedPreferences(context);
+ lastPlayedId = sp.getLong(PREF_LAST_PLAYED_ID, -1);
+ currentlyPlayingFeedId = sp.getLong(PREF_CURRENTLY_PLAYING_FEED_ID, -1);
+ currentlyPlayingFeedMediaId = sp.getLong(
+ PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING);
+ currentlyPlayingMedia = sp.getLong(PREF_CURRENTLY_PLAYING_MEDIA,
+ NO_MEDIA_PLAYING);
+ lastIsStream = sp.getBoolean(PREF_LAST_IS_STREAM, true);
+ lastIsVideo = sp.getBoolean(PREF_LAST_IS_VIDEO, false);
+ autoDeleteMediaPlaybackCompleted = sp.getBoolean(
+ PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, false);
+ autoDeleteMediaId = sp.getLong(PREF_AUTODELETE_MEDIA_ID, -1);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sp, String key) {
+ if (key.equals(PREF_LAST_PLAYED_ID)) {
+ lastPlayedId = sp.getLong(PREF_LAST_PLAYED_ID, -1);
+ long mediaId = sp.getLong(
+ PlaybackPreferences.PREF_AUTODELETE_MEDIA_ID, -1);
+ if (mediaId != -1) {
+ FeedManager manager = FeedManager.getInstance();
+ FeedMedia media = manager.getFeedMedia(mediaId);
+ if (media != null) {
+ manager.autoDeleteIfPossible(context, media);
+ }
+ }
+ } else if (key.equals(PREF_CURRENTLY_PLAYING_FEED_ID)) {
+ currentlyPlayingFeedId = sp.getLong(PREF_CURRENTLY_PLAYING_FEED_ID,
+ -1);
+
+ } else if (key.equals(PREF_CURRENTLY_PLAYING_MEDIA)) {
+ currentlyPlayingMedia = sp
+ .getLong(PREF_CURRENTLY_PLAYING_MEDIA, -1);
+
+ } else if (key.equals(PREF_LAST_IS_STREAM)) {
+ lastIsStream = sp.getBoolean(PREF_LAST_IS_STREAM, true);
+
+ } else if (key.equals(PREF_LAST_IS_VIDEO)) {
+ lastIsVideo = sp.getBoolean(PREF_LAST_IS_VIDEO, false);
+
+ } else if (key.equals(PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED)) {
+ autoDeleteMediaPlaybackCompleted = sp.getBoolean(
+ PREF_AUTODELETE_MEDIA_ID, false);
+ } else if (key.equals(PREF_AUTODELETE_MEDIA_ID)) {
+ autoDeleteMediaId = sp.getLong(PREF_AUTODELETE_MEDIA_ID, -1);
+ } else if (key.equals(PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID)) {
+ currentlyPlayingFeedMediaId = sp.getLong(
+ PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, NO_MEDIA_PLAYING);
+ }
+ }
+
+ private static void instanceAvailable() {
+ if (instance == null) {
+ throw new IllegalStateException(
+ "UserPreferences was used before being set up");
+ }
+ }
+
+ public static long getLastPlayedId() {
+ instanceAvailable();
+ return instance.lastPlayedId;
+ }
+
+ public static long getAutoDeleteMediaId() {
+ return instance.autoDeleteMediaId;
+ }
+
+ public static long getLastPlayedFeedId() {
+ instanceAvailable();
+ return instance.currentlyPlayingFeedId;
+ }
+
+ public static long getCurrentlyPlayingMedia() {
+ instanceAvailable();
+ return instance.currentlyPlayingMedia;
+ }
+
+ public static long getCurrentlyPlayingFeedMediaId() {
+ return instance.currentlyPlayingFeedMediaId;
+ }
+
+ public static boolean isLastIsStream() {
+ instanceAvailable();
+ return instance.lastIsStream;
+ }
+
+ public static boolean isLastIsVideo() {
+ instanceAvailable();
+ return instance.lastIsVideo;
+ }
+
+ public static boolean isAutoDeleteMediaPlaybackCompleted() {
+ instanceAvailable();
+ return instance.autoDeleteMediaPlaybackCompleted;
+ }
+
+}
diff --git a/src/de/danoeh/antennapod/preferences/UserPreferences.java b/src/de/danoeh/antennapod/preferences/UserPreferences.java
new file mode 100644
index 000000000..f4c0b94b0
--- /dev/null
+++ b/src/de/danoeh/antennapod/preferences/UserPreferences.java
@@ -0,0 +1,320 @@
+package de.danoeh.antennapod.preferences;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+import de.danoeh.antennapod.AppConfig;
+import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.activity.OpmlImportFromPathActivity;
+import de.danoeh.antennapod.receiver.FeedUpdateReceiver;
+
+/**
+ * Provides access to preferences set by the user in the settings screen. A
+ * private instance of this class must first be instantiated via
+ * createInstance() or otherwise every public method will throw an Exception
+ * when called.
+ */
+public class UserPreferences implements
+ SharedPreferences.OnSharedPreferenceChangeListener {
+ private static final String TAG = "UserPreferences";
+
+ public static final String PREF_PAUSE_ON_HEADSET_DISCONNECT = "prefPauseOnHeadsetDisconnect";
+ public static final String PREF_FOLLOW_QUEUE = "prefFollowQueue";
+ public static final String PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY = "prefDownloadMediaOnWifiOnly";
+ public static final String PREF_UPDATE_INTERVAL = "prefAutoUpdateIntervall";
+ public static final String PREF_MOBILE_UPDATE = "prefMobileUpdate";
+ public static final String PREF_AUTO_QUEUE = "prefAutoQueue";
+ public static final String PREF_DISPLAY_ONLY_EPISODES = "prefDisplayOnlyEpisodes";
+ public static final String PREF_AUTO_DELETE = "prefAutoDelete";
+ public static final String PREF_THEME = "prefTheme";
+ public static final String PREF_DATA_FOLDER = "prefDataFolder";
+
+ private static UserPreferences instance;
+ private Context context;
+
+ // Preferences
+ private boolean pauseOnHeadsetDisconnect;
+ private boolean followQueue;
+ private boolean downloadMediaOnWifiOnly;
+ private long updateInterval;
+ private boolean allowMobileUpdate;
+ private boolean autoQueue;
+ private boolean displayOnlyEpisodes;
+ private boolean autoDelete;
+ private int theme;
+
+ private UserPreferences(Context context) {
+ this.context = context;
+ loadPreferences();
+ }
+
+ /**
+ * Sets up the UserPreferences class.
+ *
+ * @throws IllegalArgumentException
+ * if context is null
+ * */
+ public static void createInstance(Context context) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Creating new instance of UserPreferences");
+ if (context == null)
+ throw new IllegalArgumentException("Context must not be null");
+ instance = new UserPreferences(context);
+
+ createImportDirectory();
+ createNoMediaFile();
+ PreferenceManager.getDefaultSharedPreferences(context)
+ .registerOnSharedPreferenceChangeListener(instance);
+ }
+
+ private void loadPreferences() {
+ SharedPreferences sp = PreferenceManager
+ .getDefaultSharedPreferences(context);
+ pauseOnHeadsetDisconnect = sp.getBoolean(
+ PREF_PAUSE_ON_HEADSET_DISCONNECT, true);
+ followQueue = sp.getBoolean(PREF_FOLLOW_QUEUE, false);
+ downloadMediaOnWifiOnly = sp.getBoolean(
+ PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY, true);
+ updateInterval = readUpdateInterval(sp.getString(PREF_UPDATE_INTERVAL,
+ "0"));
+ allowMobileUpdate = sp.getBoolean(PREF_MOBILE_UPDATE, false);
+ autoQueue = sp.getBoolean(PREF_AUTO_QUEUE, true);
+ displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES, false);
+ autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false);
+ theme = readThemeValue(sp.getString(PREF_THEME, "0"));
+ }
+
+ private int readThemeValue(String valueFromPrefs) {
+ switch (Integer.parseInt(valueFromPrefs)) {
+ case 0:
+ return R.style.Theme_AntennaPod_Light;
+ case 1:
+ return R.style.Theme_AntennaPod_Dark;
+ default:
+ return R.style.Theme_AntennaPod_Light;
+ }
+ }
+
+ private long readUpdateInterval(String valueFromPrefs) {
+ int hours = Integer.parseInt(valueFromPrefs);
+ return TimeUnit.HOURS.toMillis(hours);
+ }
+
+ private static void instanceAvailable() {
+ if (instance == null) {
+ throw new IllegalStateException(
+ "UserPreferences was used before being set up");
+ }
+ }
+
+ public static boolean isPauseOnHeadsetDisconnect() {
+ instanceAvailable();
+ return instance.pauseOnHeadsetDisconnect;
+ }
+
+ public static boolean isFollowQueue() {
+ instanceAvailable();
+ return instance.followQueue;
+ }
+
+ public static boolean isDownloadMediaOnWifiOnly() {
+ instanceAvailable();
+ return instance.downloadMediaOnWifiOnly;
+ }
+
+ public static long getUpdateInterval() {
+ instanceAvailable();
+ return instance.updateInterval;
+ }
+
+ public static boolean isAllowMobileUpdate() {
+ instanceAvailable();
+ return instance.allowMobileUpdate;
+ }
+
+ public static boolean isAutoQueue() {
+ instanceAvailable();
+ return instance.autoQueue;
+ }
+
+ public static boolean isDisplayOnlyEpisodes() {
+ instanceAvailable();
+ return instance.displayOnlyEpisodes;
+ }
+
+ public static boolean isAutoDelete() {
+ instanceAvailable();
+ return instance.autoDelete;
+ }
+
+ public static int getTheme() {
+ instanceAvailable();
+ return instance.theme;
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sp, String key) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Registered change of user preferences. Key: " + key);
+
+ if (key.equals(PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY)) {
+ downloadMediaOnWifiOnly = sp.getBoolean(
+ PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY, true);
+
+ } else if (key.equals(PREF_MOBILE_UPDATE)) {
+ allowMobileUpdate = sp.getBoolean(PREF_MOBILE_UPDATE, false);
+
+ } else if (key.equals(PREF_FOLLOW_QUEUE)) {
+ followQueue = sp.getBoolean(PREF_FOLLOW_QUEUE, false);
+
+ } else if (key.equals(PREF_UPDATE_INTERVAL)) {
+ AlarmManager alarmManager = (AlarmManager) context
+ .getSystemService(Context.ALARM_SERVICE);
+ updateInterval = readUpdateInterval(sp.getString(
+ PREF_UPDATE_INTERVAL, "0"));
+ PendingIntent updateIntent = PendingIntent.getBroadcast(context, 0,
+ new Intent(FeedUpdateReceiver.ACTION_REFRESH_FEEDS), 0);
+ alarmManager.cancel(updateIntent);
+ if (updateInterval != 0) {
+ alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
+ updateInterval, updateInterval, updateIntent);
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Changed alarm to new intervall");
+ } else {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Automatic update was deactivated");
+ }
+
+ } else if (key.equals(PREF_AUTO_DELETE)) {
+ autoDelete = sp.getBoolean(PREF_AUTO_DELETE, false);
+
+ } else if (key.equals(PREF_AUTO_QUEUE)) {
+ autoQueue = sp.getBoolean(PREF_AUTO_QUEUE, true);
+
+ } else if (key.equals(PREF_DISPLAY_ONLY_EPISODES)) {
+ displayOnlyEpisodes = sp.getBoolean(PREF_DISPLAY_ONLY_EPISODES,
+ false);
+ } else if (key.equals(PREF_THEME)) {
+ theme = readThemeValue(sp.getString(PREF_THEME, ""));
+ }
+ }
+
+ /**
+ * Return the folder where the app stores all of its data. This method will
+ * return the standard data folder if none has been set by the user.
+ *
+ * @param type
+ * The name of the folder inside the data folder. May be null
+ * when accessing the root of the data folder.
+ * @return The data folder that has been requested or null if the folder
+ * could not be created.
+ */
+ public static File getDataFolder(Context context, String type) {
+ instanceAvailable();
+ SharedPreferences prefs = PreferenceManager
+ .getDefaultSharedPreferences(context.getApplicationContext());
+ String strDir = prefs.getString(PREF_DATA_FOLDER, null);
+ if (strDir == null) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Using default data folder");
+ return context.getExternalFilesDir(type);
+ } else {
+ File dataDir = new File(strDir);
+ if (!dataDir.exists()) {
+ if (!dataDir.mkdir()) {
+ Log.w(TAG, "Could not create data folder");
+ return null;
+ }
+ }
+
+ if (type == null) {
+ return dataDir;
+ } else {
+ // handle path separators
+ String[] dirs = type.split("/");
+ for (int i = 0; i < dirs.length; i++) {
+ if (dirs.length > 0) {
+ if (i < dirs.length - 1) {
+ dataDir = getDataFolder(context, dirs[i]);
+ if (dataDir == null) {
+ return null;
+ }
+ }
+ type = dirs[i];
+ }
+ }
+ File typeDir = new File(dataDir, type);
+ if (!typeDir.exists()) {
+ if (dataDir.canWrite()) {
+ if (!typeDir.mkdir()) {
+ Log.e(TAG, "Could not create data folder named "
+ + type);
+ return null;
+ }
+ }
+ }
+ return typeDir;
+ }
+
+ }
+ }
+
+ public static void setDataFolder(String dir) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Result from DirectoryChooser: " + dir);
+ instanceAvailable();
+ SharedPreferences prefs = PreferenceManager
+ .getDefaultSharedPreferences(instance.context);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(PREF_DATA_FOLDER, dir);
+ editor.commit();
+ createImportDirectory();
+ }
+
+ /** Create a .nomedia file to prevent scanning by the media scanner. */
+ private static void createNoMediaFile() {
+ File f = new File(instance.context.getExternalFilesDir(null),
+ ".nomedia");
+ if (!f.exists()) {
+ try {
+ f.createNewFile();
+ } catch (IOException e) {
+ Log.e(TAG, "Could not create .nomedia file");
+ e.printStackTrace();
+ }
+ if (AppConfig.DEBUG)
+ Log.d(TAG, ".nomedia file created");
+ }
+ }
+
+ /**
+ * Creates the import directory if it doesn't exist and if storage is
+ * available
+ */
+ private static void createImportDirectory() {
+ File importDir = getDataFolder(instance.context,
+ OpmlImportFromPathActivity.IMPORT_DIR);
+ if (importDir != null) {
+ if (importDir.exists()) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Import directory already exists");
+ } else {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Creating import directory");
+ importDir.mkdir();
+ }
+ } else {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Could not access external storage.");
+ }
+ }
+
+}
diff --git a/src/de/danoeh/antennapod/receiver/FeedUpdateReceiver.java b/src/de/danoeh/antennapod/receiver/FeedUpdateReceiver.java
index ed6672ccb..651a62aed 100644
--- a/src/de/danoeh/antennapod/receiver/FeedUpdateReceiver.java
+++ b/src/de/danoeh/antennapod/receiver/FeedUpdateReceiver.java
@@ -5,11 +5,10 @@ import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.preference.PreferenceManager;
import android.util.Log;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.feed.FeedManager;
+import de.danoeh.antennapod.preferences.UserPreferences;
/** Refreshes all feeds when it receives an intent */
public class FeedUpdateReceiver extends BroadcastReceiver {
@@ -20,10 +19,7 @@ public class FeedUpdateReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_REFRESH_FEEDS)) {
if (AppConfig.DEBUG) Log.d(TAG, "Received intent");
- boolean mobileUpdate = PreferenceManager
- .getDefaultSharedPreferences(
- context.getApplicationContext()).getBoolean(
- PodcastApp.PREF_MOBILE_UPDATE, false);
+ boolean mobileUpdate = UserPreferences.isAllowMobileUpdate();
if (mobileUpdate || connectedToWifi(context)) {
FeedManager.getInstance().refreshAllFeeds(context);
} else {
diff --git a/src/de/danoeh/antennapod/service/PlaybackService.java b/src/de/danoeh/antennapod/service/PlaybackService.java
index 62370ff6d..450f7f65d 100644
--- a/src/de/danoeh/antennapod/service/PlaybackService.java
+++ b/src/de/danoeh/antennapod/service/PlaybackService.java
@@ -28,6 +28,7 @@ import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.media.RemoteControlClient;
import android.media.RemoteControlClient.MetadataEditor;
+import android.os.AsyncTask;
import android.os.Binder;
import android.os.IBinder;
import android.preference.PreferenceManager;
@@ -36,52 +37,32 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.AudioplayerActivity;
import de.danoeh.antennapod.activity.VideoplayerActivity;
import de.danoeh.antennapod.feed.Chapter;
import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.feed.FeedComponent;
import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.feed.MediaType;
+import de.danoeh.antennapod.preferences.PlaybackPreferences;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.receiver.MediaButtonReceiver;
import de.danoeh.antennapod.receiver.PlayerWidget;
import de.danoeh.antennapod.util.BitmapDecoder;
-import de.danoeh.antennapod.util.ChapterUtils;
+import de.danoeh.antennapod.util.flattr.FlattrUtils;
+import de.danoeh.antennapod.util.playback.Playable;
+import de.danoeh.antennapod.util.playback.Playable.PlayableException;
/** Controls the MediaPlayer that plays a FeedMedia-file */
public class PlaybackService extends Service {
/** Logging tag */
private static final String TAG = "PlaybackService";
- /** Contains the id of the media that was played last. */
- public static final String PREF_LAST_PLAYED_ID = "de.danoeh.antennapod.preferences.lastPlayedId";
- /** Contains the feed id of the last played item. */
- public static final String PREF_LAST_PLAYED_FEED_ID = "de.danoeh.antennapod.preferences.lastPlayedFeedId";
- /**
- * ID of the media object that is currently being played. This preference is
- * set to NO_MEDIA_PLAYING after playback has been completed and is set as
- * soon as the 'play' button is pressed.
- */
- public static final String PREF_CURRENTLY_PLAYING_MEDIA = "de.danoeh.antennapod.preferences.currentlyPlayingMedia";
- /** True if last played media was streamed. */
- public static final String PREF_LAST_IS_STREAM = "de.danoeh.antennapod.preferences.lastIsStream";
- /** True if last played media was a video. */
- public static final String PREF_LAST_IS_VIDEO = "de.danoeh.antennapod.preferences.lastIsVideo";
- /** True if playback of last played media has been completed. */
- public static final String PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED = "de.danoeh.antennapod.preferences.lastPlaybackCompleted";
- /**
- * ID of the last played media which should be auto-deleted as soon as
- * PREF_LAST_PLAYED_ID changes.
- */
- public static final String PREF_AUTODELETE_MEDIA_ID = "de.danoeh.antennapod.preferences.autoDeleteMediaId";
-
- /** Contains the id of the FeedMedia object. */
- public static final String EXTRA_MEDIA_ID = "extra.de.danoeh.antennapod.service.mediaId";
- /** Contains the id of the Feed object of the FeedMedia. */
- public static final String EXTRA_FEED_ID = "extra.de.danoeh.antennapod.service.feedId";
+ /** Parcelable of type Playable. */
+ public static final String EXTRA_PLAYABLE = "PlaybackService.PlayableExtra";
/** True if media should be streamed. */
public static final String EXTRA_SHOULD_STREAM = "extra.de.danoeh.antennapod.service.shouldStream";
/**
@@ -134,8 +115,8 @@ public class PlaybackService extends Service {
private MediaPlayer player;
private RemoteControlClient remoteControlClient;
- private FeedMedia media;
- private Feed feed;
+ private Playable media;
+
/** True if media should be streamed (Extracted from Intent Extra) . */
private boolean shouldStream;
@@ -154,8 +135,6 @@ public class PlaybackService extends Service {
private SleepTimer sleepTimer;
private Future sleepTimerFuture;
- private Thread chapterLoader;
-
private static final int SCHED_EX_POOL_SIZE = 3;
private ScheduledThreadPoolExecutor schedExecutor;
@@ -166,9 +145,6 @@ public class PlaybackService extends Service {
/** True if mediaplayer was paused because it lost audio focus temporarily */
private boolean pausedBecauseOfTransientAudiofocusLoss;
- /** Value of PREF_CURRENTLY_PLAYING_MEDIA if no media is playing. */
- public static final long NO_MEDIA_PLAYING = -1;
-
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
@@ -197,11 +173,7 @@ public class PlaybackService extends Service {
return new Intent(context, AudioplayerActivity.class);
}
} else {
- SharedPreferences pref = PreferenceManager
- .getDefaultSharedPreferences(context
- .getApplicationContext());
- boolean isVideo = pref.getBoolean(PREF_LAST_IS_VIDEO, false);
- if (isVideo) {
+ if (PlaybackPreferences.isLastIsVideo()) {
return new Intent(context, VideoplayerActivity.class);
} else {
return new Intent(context, AudioplayerActivity.class);
@@ -213,8 +185,7 @@ public class PlaybackService extends Service {
* Same as getPlayerActivityIntent(context), but here the type of activity
* depends on the FeedMedia that is provided as an argument.
*/
- public static Intent getPlayerActivityIntent(Context context,
- FeedMedia media) {
+ public static Intent getPlayerActivityIntent(Context context, Playable media) {
MediaType mt = media.getMediaType();
if (mt == MediaType.VIDEO) {
return new Intent(context, VideoplayerActivity.class);
@@ -227,9 +198,8 @@ public class PlaybackService extends Service {
public static FeedMedia getLastPlayedMediaFromPreferences(Context context) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context.getApplicationContext());
- long mediaId = prefs.getLong(PlaybackService.PREF_LAST_PLAYED_ID, -1);
- long feedId = prefs.getLong(PlaybackService.PREF_LAST_PLAYED_FEED_ID,
- -1);
+ long mediaId = PlaybackPreferences.getLastPlayedId();
+ long feedId = PlaybackPreferences.getLastPlayedFeedId();
FeedManager manager = FeedManager.getInstance();
if (mediaId != -1 && feedId != -1) {
Feed feed = manager.getFeed(feedId);
@@ -243,12 +213,13 @@ public class PlaybackService extends Service {
private void setLastPlayedMediaId(long mediaId) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
- long autoDeleteId = prefs.getLong(PREF_AUTODELETE_MEDIA_ID, -1);
+ long autoDeleteId = PlaybackPreferences.getAutoDeleteMediaId();
SharedPreferences.Editor editor = prefs.edit();
if (mediaId == autoDeleteId) {
- editor.putBoolean(PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, false);
+ editor.putBoolean(
+ PlaybackPreferences.PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED,
+ false);
}
- editor.putLong(PREF_LAST_PLAYED_ID, mediaId);
editor.commit();
}
@@ -350,7 +321,7 @@ public class PlaybackService extends Service {
case AudioManager.AUDIOFOCUS_LOSS:
if (AppConfig.DEBUG)
Log.d(TAG, "Lost audio focus");
- pause(true, true);
+ pause(true, false);
stopSelf();
break;
case AudioManager.AUDIOFOCUS_GAIN:
@@ -393,26 +364,24 @@ public class PlaybackService extends Service {
handleKeycode(keycode);
} else {
- long mediaId = intent.getLongExtra(EXTRA_MEDIA_ID, -1);
- long feedId = intent.getLongExtra(EXTRA_FEED_ID, -1);
+ Playable playable = intent.getParcelableExtra(EXTRA_PLAYABLE);
boolean playbackType = intent.getBooleanExtra(EXTRA_SHOULD_STREAM,
true);
- if (mediaId == -1 || feedId == -1) {
- Log.e(TAG,
- "Media ID or Feed ID wasn't provided to the Service.");
- if (media == null || feed == null) {
+ if (playable == null) {
+ Log.e(TAG, "Playable extra wasn't sent to the service");
+ if (media == null) {
stopSelf();
}
// Intent values appear to be valid
// check if already playing and playbackType is the same
- } else if (media == null || mediaId != media.getId()
+ } else if (media == null || playable != media
|| playbackType != shouldStream) {
pause(true, false);
player.reset();
sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, 0);
- if (media == null || mediaId != media.getId()) {
- feed = manager.getFeed(feedId);
- media = manager.getFeedMedia(mediaId, feed);
+ if (media == null
+ || playable.getIdentifier() != media.getIdentifier()) {
+ media = playable;
}
if (media != null) {
@@ -487,23 +456,45 @@ public class PlaybackService extends Service {
if (status == PlayerStatus.STOPPED
|| status == PlayerStatus.AWAITING_VIDEO_SURFACE) {
try {
- if (shouldStream) {
- player.setDataSource(media.getDownload_url());
- setStatus(PlayerStatus.PREPARING);
- player.prepareAsync();
- } else {
- player.setDataSource(media.getFile_url());
- setStatus(PlayerStatus.PREPARING);
- player.prepare();
- }
+ InitTask initTask = new InitTask() {
+
+ @Override
+ protected void onPostExecute(Playable result) {
+ if (result != null) {
+ try {
+ if (shouldStream) {
+ player.setDataSource(media.getStreamUrl());
+ setStatus(PlayerStatus.PREPARING);
+ player.prepareAsync();
+ } else {
+ player.setDataSource(media
+ .getLocalMediaUrl());
+ setStatus(PlayerStatus.PREPARING);
+ player.prepareAsync();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ } else {
+ setStatus(PlayerStatus.ERROR);
+ sendBroadcast(new Intent(
+ ACTION_SHUTDOWN_PLAYBACK_SERVICE));
+ }
+ }
+
+ @Override
+ protected void onPreExecute() {
+ setStatus(PlayerStatus.INITIALIZING);
+ }
+
+ };
+ initTask.executeAsync(media);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
}
}
@@ -535,18 +526,50 @@ public class PlaybackService extends Service {
if (mediaType == MediaType.AUDIO) {
if (AppConfig.DEBUG)
Log.d(TAG, "Mime type is audio");
- playingVideo = false;
- if (shouldStream) {
- player.setDataSource(media.getDownload_url());
- } else if (media.getFile_url() != null) {
- player.setDataSource(media.getFile_url());
- }
- if (prepareImmediately) {
- setStatus(PlayerStatus.PREPARING);
- player.prepareAsync();
- } else {
- setStatus(PlayerStatus.INITIALIZED);
- }
+
+ InitTask initTask = new InitTask() {
+
+ @Override
+ protected void onPostExecute(Playable result) {
+ if (result != null) {
+ playingVideo = false;
+ try {
+ if (shouldStream) {
+ player.setDataSource(media.getStreamUrl());
+ } else if (media.localFileAvailable()) {
+ player.setDataSource(media
+ .getLocalMediaUrl());
+ }
+
+ if (prepareImmediately) {
+ setStatus(PlayerStatus.PREPARING);
+ player.prepareAsync();
+ } else {
+ setStatus(PlayerStatus.INITIALIZED);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ media = null;
+ setStatus(PlayerStatus.ERROR);
+ sendBroadcast(new Intent(
+ ACTION_SHUTDOWN_PLAYBACK_SERVICE));
+ }
+ } else {
+ Log.e(TAG, "InitTask could not load metadata");
+ media = null;
+ setStatus(PlayerStatus.ERROR);
+ sendBroadcast(new Intent(
+ ACTION_SHUTDOWN_PLAYBACK_SERVICE));
+ }
+ }
+
+ @Override
+ protected void onPreExecute() {
+ setStatus(PlayerStatus.INITIALIZING);
+ }
+
+ };
+ initTask.executeAsync(media);
} else if (mediaType == MediaType.VIDEO) {
if (AppConfig.DEBUG)
Log.d(TAG, "Mime type is video");
@@ -561,8 +584,6 @@ public class PlaybackService extends Service {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
}
}
@@ -601,39 +622,6 @@ public class PlaybackService extends Service {
if (startWhenPrepared) {
play();
}
- if (shouldStream && media.getItem().getChapters() == null) {
- // load chapters if available
- if (chapterLoader != null) {
- chapterLoader.interrupt();
- }
- chapterLoader = new Thread() {
-
- @Override
- public void run() {
- if (AppConfig.DEBUG)
- Log.d(TAG, "Starting chapterLoader thread");
- ChapterUtils
- .readID3ChaptersFromFeedMediaDownloadUrl(media
- .getItem());
- if (media.getItem().getChapters() == null) {
- ChapterUtils
- .readOggChaptersFromMediaDownloadUrl(media
- .getItem());
- }
- if (media.getItem().getChapters() != null
- && !interrupted()) {
- sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD,
- 0);
- manager.setFeedItem(PlaybackService.this,
- media.getItem());
- }
- if (AppConfig.DEBUG)
- Log.d(TAG, "ChapterLoaderThread has finished");
- }
-
- };
- chapterLoader.start();
- }
}
};
@@ -675,7 +663,7 @@ public class PlaybackService extends Service {
pause(true, true);
}
sendNotificationBroadcast(NOTIFICATION_TYPE_ERROR, what);
- setCurrentlyPlayingMedia(NO_MEDIA_PLAYING);
+ setCurrentlyPlayingMedia(PlaybackPreferences.NO_MEDIA_PLAYING);
stopSelf();
return true;
}
@@ -690,42 +678,53 @@ public class PlaybackService extends Service {
audioManager.abandonAudioFocus(audioFocusChangeListener);
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
+ SharedPreferences.Editor editor = prefs.edit();
+
// Save state
cancelPositionSaver();
- media.setPlaybackCompletionDate(new Date());
- manager.markItemRead(PlaybackService.this, media.getItem(), true,
- true);
- FeedItem nextItem = manager
- .getQueueSuccessorOfItem(media.getItem());
- boolean isInQueue = manager.isInQueue(media.getItem());
- if (isInQueue) {
- manager.removeQueueItem(PlaybackService.this, media.getItem());
- }
- manager.addItemToPlaybackHistory(PlaybackService.this,
- media.getItem());
- manager.setFeedMedia(PlaybackService.this, media);
-
- long autoDeleteMediaId = media.getId();
- if (shouldStream) {
- autoDeleteMediaId = -1;
+ boolean isInQueue = false;
+ FeedItem nextItem = null;
+
+ if (media instanceof FeedMedia) {
+ FeedItem item = ((FeedMedia) media).getItem();
+ ((FeedMedia) media).setPlaybackCompletionDate(new Date());
+ manager.markItemRead(PlaybackService.this, item, true, true);
+ nextItem = manager.getQueueSuccessorOfItem(item);
+ isInQueue = media instanceof FeedMedia
+ && manager.isInQueue(((FeedMedia) media).getItem());
+ if (isInQueue) {
+ manager.removeQueueItem(PlaybackService.this, item);
+ }
+ manager.addItemToPlaybackHistory(PlaybackService.this, item);
+ manager.setFeedMedia(PlaybackService.this, (FeedMedia) media);
+ long autoDeleteMediaId = ((FeedComponent) media).getId();
+ if (shouldStream) {
+ autoDeleteMediaId = -1;
+ }
+ editor.putLong(PlaybackPreferences.PREF_AUTODELETE_MEDIA_ID,
+ autoDeleteMediaId);
}
- SharedPreferences.Editor editor = prefs.edit();
- editor.putLong(PREF_CURRENTLY_PLAYING_MEDIA, NO_MEDIA_PLAYING);
- editor.putLong(PREF_AUTODELETE_MEDIA_ID, autoDeleteMediaId);
- editor.putBoolean(PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED, true);
+ editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA,
+ PlaybackPreferences.NO_MEDIA_PLAYING);
+ editor.putBoolean(
+ PlaybackPreferences.PREF_AUTO_DELETE_MEDIA_PLAYBACK_COMPLETED,
+ true);
+ editor.putLong(
+ PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID,
+ PlaybackPreferences.NO_MEDIA_PLAYING);
+ editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID,
+ PlaybackPreferences.NO_MEDIA_PLAYING);
editor.commit();
// Prepare for playing next item
- boolean followQueue = prefs.getBoolean(
- PodcastApp.PREF_FOLLOW_QUEUE, false);
- boolean playNextItem = isInQueue && followQueue && nextItem != null;
+ boolean playNextItem = isInQueue && UserPreferences.isFollowQueue()
+ && nextItem != null;
if (playNextItem) {
if (AppConfig.DEBUG)
Log.d(TAG, "Loading next item in queue");
media = nextItem.getMedia();
- feed = nextItem.getFeed();
- shouldStream = !media.isDownloaded();
+ shouldStream = !media.localFileAvailable();
prepareImmediately = startWhenPrepared = true;
} else {
if (AppConfig.DEBUG)
@@ -814,8 +813,12 @@ public class PlaybackService extends Service {
public void stop() {
if (AppConfig.DEBUG)
Log.d(TAG, "Stopping playback");
- player.stop();
- setCurrentlyPlayingMedia(NO_MEDIA_PLAYING);
+ if (status == PlayerStatus.PREPARED || status == PlayerStatus.PAUSED
+ || status == PlayerStatus.STOPPED
+ || status == PlayerStatus.PLAYING) {
+ player.stop();
+ }
+ setCurrentlyPlayingMedia(PlaybackPreferences.NO_MEDIA_PLAYING);
stopSelf();
}
@@ -856,12 +859,37 @@ public class PlaybackService extends Service {
SharedPreferences.Editor editor = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext())
.edit();
- editor.putLong(PREF_CURRENTLY_PLAYING_MEDIA, media.getId());
- editor.putLong(PREF_LAST_PLAYED_FEED_ID, feed.getId());
- editor.putBoolean(PREF_LAST_IS_STREAM, shouldStream);
- editor.putBoolean(PREF_LAST_IS_VIDEO, playingVideo);
+ editor.putLong(
+ PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA,
+ media.getPlayableType());
+ editor.putBoolean(PlaybackPreferences.PREF_LAST_IS_STREAM,
+ shouldStream);
+ editor.putBoolean(PlaybackPreferences.PREF_LAST_IS_VIDEO,
+ playingVideo);
+ editor.putLong(PlaybackPreferences.PREF_LAST_PLAYED_ID,
+ media.getPlayableType());
+ if (media instanceof FeedMedia) {
+ FeedMedia fMedia = (FeedMedia) media;
+ editor.putLong(
+ PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID,
+ fMedia.getItem().getFeed().getId());
+ editor.putLong(
+ PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID,
+ fMedia.getId());
+ } else {
+ editor.putLong(
+ PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID,
+ PlaybackPreferences.NO_MEDIA_PLAYING);
+ editor.putLong(
+ PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID,
+ PlaybackPreferences.NO_MEDIA_PLAYING);
+ }
+ media.writeToPreferences(editor);
+
editor.commit();
- setLastPlayedMediaId(media.getId());
+ if (media instanceof FeedMedia) {
+ setLastPlayedMediaId(((FeedMedia) media).getId());
+ }
player.start();
if (status != PlayerStatus.PAUSED) {
player.seekTo((int) media.getPosition());
@@ -877,9 +905,7 @@ public class PlaybackService extends Service {
}
audioManager
.registerMediaButtonEventReceiver(mediaButtonReceiver);
- if (media.getItem().isRead() == false) {
- manager.markItemRead(this, media.getItem(), true, false);
- }
+ media.onPlaybackStart();
} else {
if (AppConfig.DEBUG)
Log.d(TAG, "Failed to request Audiofocus");
@@ -917,12 +943,11 @@ public class PlaybackService extends Service {
Bitmap icon = null;
if (android.os.Build.VERSION.SDK_INT >= 11) {
- if (media != null && media.getImage() != null
- && media.getImage().getFile_url() != null) {
+ if (media != null && media.getImageFileUrl() != null) {
int iconSize = getResources().getDimensionPixelSize(
android.R.dimen.notification_large_icon_width);
- icon = BitmapDecoder.decodeBitmap(iconSize, media.getImage()
- .getFile_url());
+ icon = BitmapDecoder.decodeBitmap(iconSize,
+ media.getImageFileUrl());
}
}
if (icon == null) {
@@ -930,15 +955,16 @@ public class PlaybackService extends Service {
R.drawable.ic_stat_antenna);
}
- String contentText = media.getItem().getFeed().getTitle();
- String contentTitle = media.getItem().getTitle();
+ String contentText = media.getFeedTitle();
+ String contentTitle = media.getEpisodeTitle();
Notification notification = null;
if (android.os.Build.VERSION.SDK_INT >= 16) {
Intent pauseButtonIntent = new Intent(this, PlaybackService.class);
pauseButtonIntent.putExtra(MediaButtonReceiver.EXTRA_KEYCODE,
KeyEvent.KEYCODE_MEDIA_PAUSE);
- PendingIntent pauseButtonPendingIntent = PendingIntent
- .getService(this, 0, pauseButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent pauseButtonPendingIntent = PendingIntent.getService(
+ this, 0, pauseButtonIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder notificationBuilder = new Notification.Builder(
this)
.setContentTitle(contentTitle)
@@ -1006,8 +1032,9 @@ public class PlaybackService extends Service {
if (position != INVALID_TIME) {
if (AppConfig.DEBUG)
Log.d(TAG, "Saving current position to " + position);
- media.setPosition(position);
- manager.setFeedMedia(this, media);
+ media.saveCurrentPosition(PreferenceManager
+ .getDefaultSharedPreferences(getApplicationContext()),
+ position);
}
}
@@ -1101,10 +1128,10 @@ public class PlaybackService extends Service {
MetadataEditor editor = remoteControlClient
.editMetadata(false);
editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE,
- media.getItem().getTitle());
+ media.getEpisodeTitle());
editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM,
- media.getItem().getFeed().getTitle());
+ media.getFeedTitle());
editor.apply();
}
@@ -1155,10 +1182,8 @@ public class PlaybackService extends Service {
/** Pauses playback if PREF_PAUSE_ON_HEADSET_DISCONNECT was set to true. */
private void pauseIfPauseOnDisconnect() {
- boolean pauseOnDisconnect = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext())
- .getBoolean(PodcastApp.PREF_PAUSE_ON_HEADSET_DISCONNECT, false);
- if (pauseOnDisconnect && status == PlayerStatus.PLAYING) {
+ if (UserPreferences.isPauseOnHeadsetDisconnect()
+ && status == PlayerStatus.PLAYING) {
pause(true, true);
}
}
@@ -1169,12 +1194,8 @@ public class PlaybackService extends Service {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_SHUTDOWN_PLAYBACK_SERVICE)) {
schedExecutor.shutdownNow();
- if (chapterLoader != null) {
- chapterLoader.interrupt();
- }
stop();
media = null;
- feed = null;
}
}
@@ -1276,7 +1297,7 @@ public class PlaybackService extends Service {
return status;
}
- public FeedMedia getMedia() {
+ public Playable getMedia() {
return media;
}
@@ -1343,7 +1364,40 @@ public class PlaybackService extends Service {
private void setCurrentlyPlayingMedia(long id) {
SharedPreferences.Editor editor = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext()).edit();
- editor.putLong(PREF_CURRENTLY_PLAYING_MEDIA, id);
+ editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA, id);
editor.commit();
}
+
+ private static class InitTask extends AsyncTask<Playable, Void, Playable> {
+ private Playable playable;
+ public PlayableException exception;
+
+ @Override
+ protected Playable doInBackground(Playable... params) {
+ if (params[0] == null) {
+ throw new IllegalArgumentException("Playable must not be null");
+ }
+ playable = params[0];
+
+ try {
+ playable.loadMetadata();
+ } catch (PlayableException e) {
+ e.printStackTrace();
+ exception = e;
+ return null;
+ }
+ return playable;
+ }
+
+ @SuppressLint("NewApi")
+ public void executeAsync(Playable playable) {
+ FlattrUtils.hasToken();
+ if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
+ executeOnExecutor(THREAD_POOL_EXECUTOR, playable);
+ } else {
+ execute(playable);
+ }
+ }
+
+ }
}
diff --git a/src/de/danoeh/antennapod/service/PlayerStatus.java b/src/de/danoeh/antennapod/service/PlayerStatus.java
index 17e42f847..fbf5b1505 100644
--- a/src/de/danoeh/antennapod/service/PlayerStatus.java
+++ b/src/de/danoeh/antennapod/service/PlayerStatus.java
@@ -9,5 +9,6 @@ public enum PlayerStatus {
PREPARED,
SEEKING,
AWAITING_VIDEO_SURFACE, // player has been initialized and the media type to be played is a video.
+ INITIALIZING, // playback service is loading the Playable's metadata
INITIALIZED // playback service was started, data source of media player was set.
}
diff --git a/src/de/danoeh/antennapod/service/PlayerWidgetService.java b/src/de/danoeh/antennapod/service/PlayerWidgetService.java
index dd4598e9c..475af9655 100644
--- a/src/de/danoeh/antennapod/service/PlayerWidgetService.java
+++ b/src/de/danoeh/antennapod/service/PlayerWidgetService.java
@@ -13,10 +13,10 @@ import android.view.View;
import android.widget.RemoteViews;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.R;
-import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.receiver.MediaButtonReceiver;
import de.danoeh.antennapod.receiver.PlayerWidget;
import de.danoeh.antennapod.util.Converter;
+import de.danoeh.antennapod.util.playback.Playable;
/** Updates the state of the player widget */
public class PlayerWidgetService extends Service {
@@ -83,11 +83,11 @@ public class PlayerWidgetService extends Service {
PlaybackService.getPlayerActivityIntent(this), 0);
views.setOnClickPendingIntent(R.id.layout_left, startMediaplayer);
- if (playbackService != null) {
- FeedMedia media = playbackService.getMedia();
+ if (playbackService != null && playbackService.getMedia() != null) {
+ Playable media = playbackService.getMedia();
PlayerStatus status = playbackService.getStatus();
- views.setTextViewText(R.id.txtvTitle, media.getItem().getTitle());
+ views.setTextViewText(R.id.txtvTitle, media.getEpisodeTitle());
if (status == PlayerStatus.PLAYING) {
String progressString = getProgressString(playbackService);
diff --git a/src/de/danoeh/antennapod/service/download/DownloadService.java b/src/de/danoeh/antennapod/service/download/DownloadService.java
index 59f0a5b97..986491fb5 100644
--- a/src/de/danoeh/antennapod/service/download/DownloadService.java
+++ b/src/de/danoeh/antennapod/service/download/DownloadService.java
@@ -30,7 +30,6 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
-import android.app.Notification.Builder;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -52,6 +51,7 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.activity.DownloadActivity;
import de.danoeh.antennapod.activity.DownloadLogActivity;
import de.danoeh.antennapod.asynctask.DownloadStatus;
+import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedFile;
import de.danoeh.antennapod.feed.FeedImage;
@@ -78,7 +78,6 @@ public class DownloadService extends Service {
/** Extra for ACTION_CANCEL_DOWNLOAD */
public static final String EXTRA_DOWNLOAD_URL = "downloadUrl";
- public static final String ACTION_DOWNLOAD_HANDLED = "action.de.danoeh.antennapod.service.download_handled";
/**
* Sent by the DownloadService when the content of the downloads list
* changes.
@@ -90,12 +89,6 @@ public class DownloadService extends Service {
/** Extra for ACTION_ENQUEUE_DOWNLOAD intent. */
public static final String EXTRA_REQUEST = "request";
- // Download types for ACTION_DOWNLOAD_HANDLED
- public static final String EXTRA_DOWNLOAD_TYPE = "extra.de.danoeh.antennapod.service.downloadType";
- public static final int DOWNLOAD_TYPE_FEED = 1;
- public static final int DOWNLOAD_TYPE_MEDIA = 2;
- public static final int DOWNLOAD_TYPE_IMAGE = 3;
-
private CopyOnWriteArrayList<DownloadStatus> completedDownloads;
private ExecutorService syncExecutor;
@@ -463,7 +456,7 @@ public class DownloadService extends Service {
Log.e(TAG, "Download failed");
saveDownloadStatus(status);
}
- sendDownloadHandledIntent(getDownloadType(download));
+ sendDownloadHandledIntent();
downloadsBeingHandled -= 1;
}
}
@@ -505,24 +498,8 @@ public class DownloadService extends Service {
manager.addDownloadStatus(this, status);
}
- /** Returns correct value for EXTRA_DOWNLOAD_TYPE. */
- private int getDownloadType(FeedFile f) {
- if (f.getClass() == Feed.class) {
- return DOWNLOAD_TYPE_FEED;
- } else if (f.getClass() == FeedImage.class) {
- return DOWNLOAD_TYPE_IMAGE;
- } else if (f.getClass() == FeedMedia.class) {
- return DOWNLOAD_TYPE_MEDIA;
- } else {
- return 0;
- }
- }
-
- private void sendDownloadHandledIntent(int type) {
- Intent intent = new Intent(ACTION_DOWNLOAD_HANDLED);
- intent.putExtra(EXTRA_DOWNLOAD_TYPE, type);
-
- sendBroadcast(intent);
+ private void sendDownloadHandledIntent() {
+ EventDistributor.getInstance().sendDownloadHandledBroadcast();
}
/**
@@ -727,7 +704,7 @@ public class DownloadService extends Service {
saveDownloadStatus(new DownloadStatus(savedFeed,
savedFeed.getHumanReadableIdentifier(), reason, successful,
reasonDetailed));
- sendDownloadHandledIntent(DOWNLOAD_TYPE_FEED);
+ sendDownloadHandledIntent();
downloadsBeingHandled -= 1;
handler.post(new Runnable() {
@@ -756,7 +733,7 @@ public class DownloadService extends Service {
}
private boolean hasValidFeedItems(Feed feed) {
- for (FeedItem item : feed.getItems()) {
+ for (FeedItem item : feed.getItemsArray()) {
if (item.getTitle() == null) {
Log.e(TAG, "Item has no title");
return false;
@@ -804,7 +781,7 @@ public class DownloadService extends Service {
image.setDownloaded(true);
saveDownloadStatus(status);
- sendDownloadHandledIntent(DOWNLOAD_TYPE_IMAGE);
+ sendDownloadHandledIntent();
manager.setFeedImage(DownloadService.this, image);
if (image.getFeed() != null) {
manager.setFeed(DownloadService.this, image.getFeed());
@@ -854,21 +831,16 @@ public class DownloadService extends Service {
} finally {
mediaplayer.release();
}
-
+
if (media.getItem().getChapters() == null) {
- ChapterUtils.readID3ChaptersFromFeedMediaFileUrl(media
- .getItem());
- if (media.getItem().getChapters() == null) {
- ChapterUtils.readOggChaptersFromMediaFileUrl(media
- .getItem());
- }
+ ChapterUtils.loadChaptersFromFileUrl(media);
if (media.getItem().getChapters() != null) {
chaptersRead = true;
}
}
saveDownloadStatus(status);
- sendDownloadHandledIntent(DOWNLOAD_TYPE_MEDIA);
+ sendDownloadHandledIntent();
if (chaptersRead) {
manager.setFeedItem(DownloadService.this, media.getItem());
} else {
diff --git a/src/de/danoeh/antennapod/storage/DownloadRequester.java b/src/de/danoeh/antennapod/storage/DownloadRequester.java
index 38b143a7f..bebffe8f9 100644
--- a/src/de/danoeh/antennapod/storage/DownloadRequester.java
+++ b/src/de/danoeh/antennapod/storage/DownloadRequester.java
@@ -11,11 +11,12 @@ import android.content.Intent;
import android.util.Log;
import android.webkit.URLUtil;
import de.danoeh.antennapod.AppConfig;
-import de.danoeh.antennapod.PodcastApp;
+import de.danoeh.antennapod.feed.EventDistributor;
import de.danoeh.antennapod.feed.Feed;
import de.danoeh.antennapod.feed.FeedFile;
import de.danoeh.antennapod.feed.FeedImage;
import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.preferences.UserPreferences;
import de.danoeh.antennapod.service.download.DownloadService;
import de.danoeh.antennapod.util.FileNameGenerator;
import de.danoeh.antennapod.util.URLChecker;
@@ -23,11 +24,6 @@ import de.danoeh.antennapod.util.URLChecker;
public class DownloadRequester {
private static final String TAG = "DownloadRequester";
- public static String EXTRA_DOWNLOAD_ID = "extra.de.danoeh.antennapod.storage.download_id";
- public static String EXTRA_ITEM_ID = "extra.de.danoeh.antennapod.storage.item_id";
-
- public static String ACTION_DOWNLOAD_QUEUED = "action.de.danoeh.antennapod.storage.downloadQueued";
-
public static String IMAGE_DOWNLOADPATH = "images/";
public static String FEED_DOWNLOADPATH = "cache/";
public static String MEDIA_DOWNLOADPATH = "media/";
@@ -70,7 +66,8 @@ public class DownloadRequester {
if (AppConfig.DEBUG)
Log.d(TAG, "Testing filename " + newName);
newDest = new File(dest.getParent(), newName);
- if (!newDest.exists() && isFilenameAvailable(newDest.toString())) {
+ if (!newDest.exists()
+ && isFilenameAvailable(newDest.toString())) {
if (AppConfig.DEBUG)
Log.d(TAG, "File doesn't exist yet. Using "
+ newName);
@@ -102,7 +99,7 @@ public class DownloadRequester {
queueIntent.putExtra(DownloadService.EXTRA_REQUEST, request);
context.sendBroadcast(queueIntent);
}
- context.sendBroadcast(new Intent(ACTION_DOWNLOAD_QUEUED));
+ EventDistributor.getInstance().sendDownloadQueuedBroadcast();
} else {
Log.e(TAG, "URL " + item.getDownload_url()
+ " is already being downloaded");
@@ -123,7 +120,8 @@ public class DownloadRequester {
return false;
}
}
- if (AppConfig.DEBUG) Log.d(TAG, path + " is available as a download destination");
+ if (AppConfig.DEBUG)
+ Log.d(TAG, path + " is available as a download destination");
return true;
}
@@ -282,7 +280,7 @@ public class DownloadRequester {
private File getExternalFilesDirOrThrowException(Context context,
String type) throws DownloadRequestException {
- File result = PodcastApp.getDataFolder(context, type);
+ File result = UserPreferences.getDataFolder(context, type);
if (result == null) {
throw new DownloadRequestException(
"Failed to access external storage");
diff --git a/src/de/danoeh/antennapod/storage/PodDBAdapter.java b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
index 4045f8664..f1842800b 100644
--- a/src/de/danoeh/antennapod/storage/PodDBAdapter.java
+++ b/src/de/danoeh/antennapod/storage/PodDBAdapter.java
@@ -334,7 +334,7 @@ public class PodDBAdapter {
public void setCompleteFeed(Feed feed) {
db.beginTransaction();
setFeed(feed);
- for (FeedItem item : feed.getItems()) {
+ for (FeedItem item : feed.getItemsArray()) {
setFeedItem(item);
}
db.setTransactionSuccessful();
@@ -485,7 +485,7 @@ public class PodDBAdapter {
if (feed.getImage() != null) {
removeFeedImage(feed.getImage());
}
- for (FeedItem item : feed.getItems()) {
+ for (FeedItem item : feed.getItemsArray()) {
removeFeedItem(item);
}
db.delete(TABLE_NAME_FEEDS, KEY_ID + "=?",
diff --git a/src/de/danoeh/antennapod/syndication/handler/HandlerState.java b/src/de/danoeh/antennapod/syndication/handler/HandlerState.java
index 6c206b8f3..e8687858b 100644
--- a/src/de/danoeh/antennapod/syndication/handler/HandlerState.java
+++ b/src/de/danoeh/antennapod/syndication/handler/HandlerState.java
@@ -1,5 +1,6 @@
package de.danoeh.antennapod.syndication.handler;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
@@ -8,11 +9,15 @@ import de.danoeh.antennapod.feed.FeedItem;
import de.danoeh.antennapod.syndication.namespace.Namespace;
import de.danoeh.antennapod.syndication.namespace.SyndElement;
-/** Contains all relevant information to describe the current state of a SyndHandler.*/
+/**
+ * Contains all relevant information to describe the current state of a
+ * SyndHandler.
+ */
public class HandlerState {
-
+
/** Feed that the Handler is currently processing. */
protected Feed feed;
+ protected ArrayList<FeedItem> items;
protected FeedItem currentItem;
protected Stack<SyndElement> tagstack;
/** Namespaces that have been defined so far. */
@@ -20,43 +25,49 @@ public class HandlerState {
protected Stack<Namespace> defaultNamespaces;
/** Buffer for saving characters. */
protected StringBuffer contentBuf;
-
+
public HandlerState(Feed feed) {
this.feed = feed;
+ items = new ArrayList<FeedItem>();
tagstack = new Stack<SyndElement>();
namespaces = new HashMap<String, Namespace>();
defaultNamespaces = new Stack<Namespace>();
}
-
-
+
public Feed getFeed() {
return feed;
}
+
+ public ArrayList<FeedItem> getItems() {
+ return items;
+ }
+
public FeedItem getCurrentItem() {
return currentItem;
}
+
public Stack<SyndElement> getTagstack() {
return tagstack;
}
-
public void setFeed(Feed feed) {
this.feed = feed;
}
-
public void setCurrentItem(FeedItem currentItem) {
this.currentItem = currentItem;
}
- /** Returns the SyndElement that comes after the top element of the tagstack. */
+ /**
+ * Returns the SyndElement that comes after the top element of the tagstack.
+ */
public SyndElement getSecondTag() {
SyndElement top = tagstack.pop();
SyndElement second = tagstack.peek();
tagstack.push(top);
return second;
}
-
+
public SyndElement getThirdTag() {
SyndElement top = tagstack.pop();
SyndElement second = tagstack.pop();
@@ -65,13 +76,9 @@ public class HandlerState {
tagstack.push(top);
return third;
}
-
+
public StringBuffer getContentBuf() {
return contentBuf;
}
-
-
-
-
}
diff --git a/src/de/danoeh/antennapod/syndication/handler/SyndHandler.java b/src/de/danoeh/antennapod/syndication/handler/SyndHandler.java
index f830f0933..c51d054d4 100644
--- a/src/de/danoeh/antennapod/syndication/handler/SyndHandler.java
+++ b/src/de/danoeh/antennapod/syndication/handler/SyndHandler.java
@@ -120,6 +120,12 @@ public class SyndHandler extends DefaultHandler {
return handler;
}
+ @Override
+ public void endDocument() throws SAXException {
+ super.endDocument();
+ state.getFeed().setItems(state.getItems());
+ }
+
public HandlerState getState() {
return state;
}
diff --git a/src/de/danoeh/antennapod/syndication/namespace/NSRSS20.java b/src/de/danoeh/antennapod/syndication/namespace/NSRSS20.java
index a8c43800c..4d0b42132 100644
--- a/src/de/danoeh/antennapod/syndication/namespace/NSRSS20.java
+++ b/src/de/danoeh/antennapod/syndication/namespace/NSRSS20.java
@@ -43,7 +43,7 @@ public class NSRSS20 extends Namespace {
Attributes attributes) {
if (localName.equals(ITEM)) {
state.setCurrentItem(new FeedItem());
- state.getFeed().getItems().add(state.getCurrentItem());
+ state.getItems().add(state.getCurrentItem());
state.getCurrentItem().setFeed(state.getFeed());
} else if (localName.equals(ENCLOSURE)) {
diff --git a/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java b/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java
index e3cdce534..522b16efe 100644
--- a/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java
+++ b/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java
@@ -55,7 +55,7 @@ public class NSAtom extends Namespace {
Attributes attributes) {
if (localName.equals(ENTRY)) {
state.setCurrentItem(new FeedItem());
- state.getFeed().getItems().add(state.getCurrentItem());
+ state.getItems().add(state.getCurrentItem());
state.getCurrentItem().setFeed(state.getFeed());
} else if (localName.matches(isText)) {
String type = attributes.getValue(TEXT_TYPE);
diff --git a/src/de/danoeh/antennapod/util/BitmapDecoder.java b/src/de/danoeh/antennapod/util/BitmapDecoder.java
index 8dd4953c6..e9ef2ad01 100644
--- a/src/de/danoeh/antennapod/util/BitmapDecoder.java
+++ b/src/de/danoeh/antennapod/util/BitmapDecoder.java
@@ -2,9 +2,6 @@ package de.danoeh.antennapod.util;
import java.io.File;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.FilenameUtils;
-
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
diff --git a/src/de/danoeh/antennapod/util/ChapterUtils.java b/src/de/danoeh/antennapod/util/ChapterUtils.java
index 3131b9e9a..ac8149119 100644
--- a/src/de/danoeh/antennapod/util/ChapterUtils.java
+++ b/src/de/danoeh/antennapod/util/ChapterUtils.java
@@ -16,11 +16,10 @@ import org.apache.commons.io.IOUtils;
import android.util.Log;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.feed.Chapter;
-import de.danoeh.antennapod.feed.FeedItem;
-import de.danoeh.antennapod.feed.FeedMedia;
import de.danoeh.antennapod.util.comparator.ChapterStartTimeComparator;
import de.danoeh.antennapod.util.id3reader.ChapterReader;
import de.danoeh.antennapod.util.id3reader.ID3ReaderException;
+import de.danoeh.antennapod.util.playback.Playable;
import de.danoeh.antennapod.util.vorbiscommentreader.VorbisCommentChapterReader;
import de.danoeh.antennapod.util.vorbiscommentreader.VorbisCommentReaderException;
@@ -35,14 +34,13 @@ public class ChapterUtils {
* Uses the download URL of a media object of a feeditem to read its ID3
* chapters.
*/
- public static void readID3ChaptersFromFeedMediaDownloadUrl(FeedItem item) {
+ public static void readID3ChaptersFromPlayableStreamUrl(Playable p) {
if (AppConfig.DEBUG)
- Log.d(TAG, "Reading id3 chapters from item " + item.getTitle());
- final FeedMedia media = item.getMedia();
- if (media != null && media.getDownload_url() != null) {
+ Log.d(TAG, "Reading id3 chapters from item " + p.getEpisodeTitle());
+ if (p != null && p.getStreamUrl() != null) {
InputStream in = null;
try {
- URL url = new URL(media.getDownload_url());
+ URL url = new URL(p.getStreamUrl());
ChapterReader reader = new ChapterReader();
in = url.openStream();
@@ -52,9 +50,9 @@ public class ChapterUtils {
if (chapters != null) {
Collections
.sort(chapters, new ChapterStartTimeComparator());
- processChapters(chapters, item);
+ processChapters(chapters, p);
if (chaptersValid(chapters)) {
- item.setChapters(chapters);
+ p.setChapters(chapters);
Log.i(TAG, "Chapters loaded");
} else {
Log.e(TAG, "Chapter data was invalid");
@@ -87,13 +85,11 @@ public class ChapterUtils {
* Uses the file URL of a media object of a feeditem to read its ID3
* chapters.
*/
- public static void readID3ChaptersFromFeedMediaFileUrl(FeedItem item) {
+ public static void readID3ChaptersFromPlayableFileUrl(Playable p) {
if (AppConfig.DEBUG)
- Log.d(TAG, "Reading id3 chapters from item " + item.getTitle());
- final FeedMedia media = item.getMedia();
- if (media != null && media.isDownloaded()
- && media.getFile_url() != null) {
- File source = new File(media.getFile_url());
+ Log.d(TAG, "Reading id3 chapters from item " + p.getEpisodeTitle());
+ if (p != null && p.localFileAvailable() && p.getLocalMediaUrl() != null) {
+ File source = new File(p.getLocalMediaUrl());
if (source.exists()) {
ChapterReader reader = new ChapterReader();
InputStream in = null;
@@ -106,9 +102,9 @@ public class ChapterUtils {
if (chapters != null) {
Collections.sort(chapters,
new ChapterStartTimeComparator());
- processChapters(chapters, item);
+ processChapters(chapters, p);
if (chaptersValid(chapters)) {
- item.setChapters(chapters);
+ p.setChapters(chapters);
Log.i(TAG, "Chapters loaded");
} else {
Log.e(TAG, "Chapter data was invalid");
@@ -136,15 +132,14 @@ public class ChapterUtils {
}
}
- public static void readOggChaptersFromMediaDownloadUrl(FeedItem item) {
- final FeedMedia media = item.getMedia();
- if (media != null && media.getDownload_url() != null) {
+ public static void readOggChaptersFromPlayableStreamUrl(Playable media) {
+ if (media != null && media.streamAvailable()) {
InputStream input = null;
try {
- URL url = new URL(media.getDownload_url());
+ URL url = new URL(media.getStreamUrl());
input = url.openStream();
if (input != null) {
- readOggChaptersFromInputStream(item, input);
+ readOggChaptersFromInputStream(media, input);
}
} catch (MalformedURLException e) {
e.printStackTrace();
@@ -156,15 +151,14 @@ public class ChapterUtils {
}
}
- public static void readOggChaptersFromMediaFileUrl(FeedItem item) {
- final FeedMedia media = item.getMedia();
- if (media != null && media.getFile_url() != null) {
- File source = new File(media.getFile_url());
+ public static void readOggChaptersFromPlayableFileUrl(Playable media) {
+ if (media != null && media.getLocalMediaUrl() != null) {
+ File source = new File(media.getLocalMediaUrl());
if (source.exists()) {
InputStream input = null;
try {
input = new BufferedInputStream(new FileInputStream(source));
- readOggChaptersFromInputStream(item, input);
+ readOggChaptersFromInputStream(media, input);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
@@ -174,21 +168,21 @@ public class ChapterUtils {
}
}
- private static void readOggChaptersFromInputStream(FeedItem item,
+ private static void readOggChaptersFromInputStream(Playable p,
InputStream input) {
if (AppConfig.DEBUG)
Log.d(TAG,
"Trying to read chapters from item with title "
- + item.getTitle());
+ + p.getEpisodeTitle());
try {
VorbisCommentChapterReader reader = new VorbisCommentChapterReader();
reader.readInputStream(input);
List<Chapter> chapters = reader.getChapters();
if (chapters != null) {
Collections.sort(chapters, new ChapterStartTimeComparator());
- processChapters(chapters, item);
+ processChapters(chapters, p);
if (chaptersValid(chapters)) {
- item.setChapters(chapters);
+ p.setChapters(chapters);
Log.i(TAG, "Chapters loaded");
} else {
Log.e(TAG, "Chapter data was invalid");
@@ -203,13 +197,12 @@ public class ChapterUtils {
}
/** Makes sure that chapter does a title and an item attribute. */
- private static void processChapters(List<Chapter> chapters, FeedItem item) {
+ private static void processChapters(List<Chapter> chapters, Playable p) {
for (int i = 0; i < chapters.size(); i++) {
Chapter c = chapters.get(i);
if (c.getTitle() == null) {
c.setTitle(Integer.toString(i));
}
- c.setItem(item);
}
}
@@ -228,4 +221,47 @@ public class ChapterUtils {
return true;
}
+ /** Calls getCurrentChapter with current position. */
+ public static Chapter getCurrentChapter(Playable media) {
+ if (media.getChapters() != null) {
+ List<Chapter> chapters = media.getChapters();
+ Chapter current = null;
+ if (chapters != null) {
+ current = chapters.get(0);
+ for (Chapter sc : chapters) {
+ if (sc.getStart() > media.getPosition()) {
+ break;
+ } else {
+ current = sc;
+ }
+ }
+ }
+ return current;
+ } else {
+ return null;
+ }
+ }
+
+ public static void loadChaptersFromStreamUrl(Playable media) {
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "Starting chapterLoader thread");
+ ChapterUtils.readID3ChaptersFromPlayableStreamUrl(media);
+ if (media.getChapters() == null) {
+ ChapterUtils.readOggChaptersFromPlayableStreamUrl(media);
+ }
+
+ if (AppConfig.DEBUG)
+ Log.d(TAG, "ChapterLoaderThread has finished");
+ }
+
+ public static void loadChaptersFromFileUrl(Playable media) {
+ if (media.localFileAvailable()) {
+ ChapterUtils.readID3ChaptersFromPlayableFileUrl(media);
+ if (media.getChapters() == null) {
+ ChapterUtils.readOggChaptersFromPlayableFileUrl(media);
+ }
+ } else {
+ Log.e(TAG, "Could not load chapters from file url: local file not available");
+ }
+ }
}
diff --git a/src/de/danoeh/antennapod/util/StorageUtils.java b/src/de/danoeh/antennapod/util/StorageUtils.java
index cc0ba7136..9003ee907 100644
--- a/src/de/danoeh/antennapod/util/StorageUtils.java
+++ b/src/de/danoeh/antennapod/util/StorageUtils.java
@@ -10,13 +10,14 @@ import android.util.Log;
import de.danoeh.antennapod.AppConfig;
import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.activity.StorageErrorActivity;
+import de.danoeh.antennapod.preferences.UserPreferences;
/** Utility functions for handling storage errors */
public class StorageUtils {
private static final String TAG = "StorageUtils";
public static boolean storageAvailable(Context context) {
- File dir = PodcastApp.getDataFolder(context, null);
+ File dir = UserPreferences.getDataFolder(context, null);
if (dir != null) {
return dir.exists() && dir.canRead() && dir.canWrite();
} else {
@@ -48,7 +49,7 @@ public class StorageUtils {
/** Get the number of free bytes that are available on the external storage. */
public static long getFreeSpaceAvailable() {
- StatFs stat = new StatFs(PodcastApp.getDataFolder(
+ StatFs stat = new StatFs(UserPreferences.getDataFolder(
PodcastApp.getInstance(), null).getAbsolutePath());
long availableBlocks = stat.getAvailableBlocks();
long blockSize = stat.getBlockSize();
diff --git a/src/de/danoeh/antennapod/util/ThemeUtils.java b/src/de/danoeh/antennapod/util/ThemeUtils.java
index ec47ed48e..8e593f3fb 100644
--- a/src/de/danoeh/antennapod/util/ThemeUtils.java
+++ b/src/de/danoeh/antennapod/util/ThemeUtils.java
@@ -1,14 +1,14 @@
package de.danoeh.antennapod.util;
import android.util.Log;
-import de.danoeh.antennapod.PodcastApp;
import de.danoeh.antennapod.R;
+import de.danoeh.antennapod.preferences.UserPreferences;
public class ThemeUtils {
private static final String TAG = "ThemeUtils";
public static int getSelectionBackgroundColor() {
- switch (PodcastApp.getThemeResourceId()) {
+ switch (UserPreferences.getTheme()) {
case R.style.Theme_AntennaPod_Dark:
return R.color.selection_background_color_dark;
case R.style.Theme_AntennaPod_Light:
diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
index 37f5fd0d3..af8538e83 100644
--- a/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
+++ b/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java
@@ -33,7 +33,7 @@ public class FeedMenuHandler {
if (AppConfig.DEBUG)
Log.d(TAG, "Preparing options menu");
menu.findItem(R.id.mark_all_read_item).setVisible(
- selectedFeed.hasNewItems());
+ selectedFeed.hasNewItems(true));
if (selectedFeed.getPaymentLink() != null) {
menu.findItem(R.id.support_item).setVisible(true);
}
diff --git a/src/de/danoeh/antennapod/util/playback/ExternalMedia.java b/src/de/danoeh/antennapod/util/playback/ExternalMedia.java
new file mode 100644
index 000000000..4574f088e
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/playback/ExternalMedia.java
@@ -0,0 +1,238 @@
+package de.danoeh.antennapod.util.playback;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.media.MediaMetadataRetriever;
+import android.os.Parcel;
+import android.os.Parcelable;
+import de.danoeh.antennapod.PodcastApp;
+import de.danoeh.antennapod.feed.Chapter;
+import de.danoeh.antennapod.feed.MediaType;
+import de.danoeh.antennapod.util.ChapterUtils;
+import de.danoeh.antennapod.util.FileNameGenerator;
+
+/** Represents a media file that is stored on the local storage device. */
+public class ExternalMedia implements Playable {
+
+ public static final int PLAYABLE_TYPE_EXTERNAL_MEDIA = 2;
+ public static final String PREF_SOURCE_URL = "ExternalMedia.PrefSourceUrl";
+ public static final String PREF_POSITION = "ExternalMedia.PrefPosition";
+ public static final String PREF_MEDIA_TYPE = "ExternalMedia.PrefMediaType";
+
+ private String source;
+
+ private String episodeTitle;
+ private String feedTitle;
+ private String shownotes;
+ private MediaType mediaType = MediaType.AUDIO;
+ private List<Chapter> chapters;
+ private String imageUrl;
+ private int duration;
+ private int position;
+
+ public ExternalMedia(String source, MediaType mediaType) {
+ super();
+ this.source = source;
+ this.mediaType = mediaType;
+ }
+
+ public ExternalMedia(String source, MediaType mediaType, int position) {
+ this(source, mediaType);
+ this.position = position;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(source);
+ dest.writeString(mediaType.toString());
+ dest.writeInt(position);
+ }
+
+ @Override
+ public void writeToPreferences(Editor prefEditor) {
+ prefEditor.putString(PREF_SOURCE_URL, source);
+ prefEditor.putString(PREF_MEDIA_TYPE, mediaType.toString());
+ prefEditor.putInt(PREF_POSITION, position);
+ }
+
+ @Override
+ public void loadMetadata() throws PlayableException {
+ MediaMetadataRetriever mmr = new MediaMetadataRetriever();
+ try {
+ mmr.setDataSource(source);
+ } catch (IllegalArgumentException e) {
+ e.printStackTrace();
+ throw new PlayableException("IllegalArgumentException when setting up MediaMetadataReceiver");
+ }
+ episodeTitle = mmr
+ .extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
+ feedTitle = mmr
+ .extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
+ duration = Integer.parseInt(mmr
+ .extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION));
+ ChapterUtils.loadChaptersFromFileUrl(this);
+ byte[] imgData = mmr.getEmbeddedPicture();
+ File cacheDir = PodcastApp.getInstance().getExternalCacheDir();
+ if (cacheDir != null) {
+ OutputStream out = null;
+ try {
+ File tmpFile = File.createTempFile(
+ FileNameGenerator.generateFileName(source) + "-img",
+ null, cacheDir);
+ out = new BufferedOutputStream(new FileOutputStream(tmpFile));
+ IOUtils.write(imgData, out);
+ imageUrl = tmpFile.getAbsolutePath();
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new PlayableException("IOException during loadMetadata()");
+ } finally {
+ IOUtils.closeQuietly(out);
+ }
+ }
+ }
+
+ @Override
+ public String getEpisodeTitle() {
+ return episodeTitle;
+ }
+
+ @Override
+ public void loadShownotes(ShownoteLoaderCallback callback) {
+ callback.onShownotesLoaded(null);
+ }
+
+ @Override
+ public List<Chapter> getChapters() {
+ return chapters;
+ }
+
+ @Override
+ public String getWebsiteLink() {
+ return null;
+ }
+
+ @Override
+ public String getPaymentLink() {
+ return null;
+ }
+
+ @Override
+ public String getFeedTitle() {
+ return feedTitle;
+ }
+
+ @Override
+ public String getImageFileUrl() {
+ return imageUrl;
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return source;
+ }
+
+ @Override
+ public int getDuration() {
+ return duration;
+ }
+
+ @Override
+ public int getPosition() {
+ return position;
+ }
+
+ @Override
+ public MediaType getMediaType() {
+ return mediaType;
+ }
+
+ @Override
+ public String getLocalMediaUrl() {
+ return source;
+ }
+
+ @Override
+ public String getStreamUrl() {
+ return null;
+ }
+
+ @Override
+ public boolean localFileAvailable() {
+ return true;
+ }
+
+ @Override
+ public boolean streamAvailable() {
+ return false;
+ }
+
+ @Override
+ public void saveCurrentPosition(SharedPreferences pref, int newPosition) {
+ SharedPreferences.Editor editor = pref.edit();
+ editor.putInt(PREF_POSITION, newPosition);
+ position = newPosition;
+ editor.commit();
+ }
+
+ @Override
+ public void setPosition(int newPosition) {
+ position = newPosition;
+ }
+
+ @Override
+ public void setDuration(int newDuration) {
+ duration = newDuration;
+ }
+
+ @Override
+ public void onPlaybackStart() {
+
+ }
+
+ @Override
+ public void onPlaybackCompleted() {
+
+ }
+
+ @Override
+ public int getPlayableType() {
+ return PLAYABLE_TYPE_EXTERNAL_MEDIA;
+ }
+
+ @Override
+ public void setChapters(List<Chapter> chapters) {
+ this.chapters = chapters;
+ }
+
+ public static final Parcelable.Creator<ExternalMedia> CREATOR = new Parcelable.Creator<ExternalMedia>() {
+ public ExternalMedia createFromParcel(Parcel in) {
+ String source = in.readString();
+ MediaType type = MediaType.valueOf(in.readString());
+ int position = 0;
+ if (in.dataAvail() > 0) {
+ position = in.readInt();
+ }
+ ExternalMedia extMedia = new ExternalMedia(source, type, position);
+ return extMedia;
+ }
+
+ public ExternalMedia[] newArray(int size) {
+ return new ExternalMedia[size];
+ }
+ };
+
+}
diff --git a/src/de/danoeh/antennapod/util/MediaPlayerError.java b/src/de/danoeh/antennapod/util/playback/MediaPlayerError.java
index 93922c747..23ead581f 100644
--- a/src/de/danoeh/antennapod/util/MediaPlayerError.java
+++ b/src/de/danoeh/antennapod/util/playback/MediaPlayerError.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.util;
+package de.danoeh.antennapod.util.playback;
import android.content.Context;
import android.media.MediaPlayer;
diff --git a/src/de/danoeh/antennapod/util/playback/Playable.java b/src/de/danoeh/antennapod/util/playback/Playable.java
new file mode 100644
index 000000000..bf38b9518
--- /dev/null
+++ b/src/de/danoeh/antennapod/util/playback/Playable.java
@@ -0,0 +1,197 @@
+package de.danoeh.antennapod.util.playback;
+
+import java.util.List;
+
+import android.content.SharedPreferences;
+import android.os.Parcelable;
+import android.util.Log;
+import de.danoeh.antennapod.feed.Chapter;
+import de.danoeh.antennapod.feed.Feed;
+import de.danoeh.antennapod.feed.FeedManager;
+import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.feed.MediaType;
+
+/** Interface for objects that can be played by the PlaybackService. */
+public interface Playable extends Parcelable {
+
+ /**
+ * Save information about the playable in a preference so that it can be
+ * restored later via PlayableUtils.createInstanceFromPreferences.
+ * Implementations must NOT call commit() after they have written the values
+ * to the preferences file.
+ */
+ public void writeToPreferences(SharedPreferences.Editor prefEditor);
+
+ /**
+ * This method is called from a separate thread by the PlaybackService.
+ * Playable objects should load their metadata in this method (for example:
+ * chapter marks).
+ */
+ public void loadMetadata() throws PlayableException;
+
+ /** Returns the title of the episode that this playable represents */
+ public String getEpisodeTitle();
+
+ /**
+ * Loads shownotes. If the shownotes have to be loaded from a file or from a
+ * database, it should be done in a separate thread. After the shownotes
+ * have been loaded, callback.onShownotesLoaded should be called.
+ */
+ public void loadShownotes(ShownoteLoaderCallback callback);
+
+ /**
+ * Returns a list of chapter marks or null if this Playable has no chapters.
+ */
+ public List<Chapter> getChapters();
+
+ /** Returns a link to a website that is meant to be shown in a browser */
+ public String getWebsiteLink();
+
+ public String getPaymentLink();
+
+ /** Returns the title of the feed this Playable belongs to. */
+ public String getFeedTitle();
+
+ /** Returns a file url to an image or null if no such image exists. */
+ public String getImageFileUrl();
+
+ /**
+ * Returns a unique identifier, for example a file url or an ID from a
+ * database.
+ */
+ public Object getIdentifier();
+
+ /** Return duration of object or 0 if duration is unknown. */
+ public int getDuration();
+
+ /** Return position of object or 0 if position is unknown. */
+ public int getPosition();
+
+ /**
+ * Returns the type of media. This method should return the correct value
+ * BEFORE loadMetadata() is called.
+ */
+ public MediaType getMediaType();
+
+ /**
+ * Returns an url to a local file that can be played or null if this file
+ * does not exist.
+ */
+ public String getLocalMediaUrl();
+
+ /**
+ * Returns an url to a file that can be streamed by the player or null if
+ * this url is not known.
+ */
+ public String getStreamUrl();
+
+ /**
+ * Returns true if a local file that can be played is available. getFileUrl
+ * MUST return a non-null string if this method returns true.
+ */
+ public boolean localFileAvailable();
+
+ /**
+ * Returns true if a streamable file is available. getStreamUrl MUST return
+ * a non-null string if this method returns true.
+ */
+ public boolean streamAvailable();
+
+ /**
+ * Saves the current position of this object. Implementations can use the
+ * provided SharedPreference to save this information and retrieve it later
+ * via PlayableUtils.createInstanceFromPreferences.
+ */
+ public void saveCurrentPosition(SharedPreferences pref, int newPosition);
+
+ public void setPosition(int newPosition);
+
+ public void setDuration(int newDuration);
+
+ /** Is called by the PlaybackService when playback starts. */
+ public void onPlaybackStart();
+
+ /** Is called by the PlaybackService when playback is completed. */
+ public void onPlaybackCompleted();
+
+ /**
+ * Returns an integer that must be unique among all Playable classes. The
+ * return value is later used by PlayableUtils to determine the type of the
+ * Playable object that is restored.
+ */
+ public int getPlayableType();
+
+ public void setChapters(List<Chapter> chapters);
+
+ /** Provides utility methods for Playable objects. */
+ public static class PlayableUtils {
+ private static final String TAG = "PlayableUtils";
+
+ /**
+ * Restores a playable object from a sharedPreferences file.
+ *
+ * @param type
+ * An integer that represents the type of the Playable object
+ * that is restored.
+ * @param pref
+ * The SharedPreferences file from which the Playable object
+ * is restored
+ * @return The restored Playable object
+ */
+ public static Playable createInstanceFromPreferences(int type,
+ SharedPreferences pref) {
+ // ADD new Playable types here:
+ switch (type) {
+ case FeedMedia.PLAYABLE_TYPE_FEEDMEDIA:
+ long feedId = pref.getLong(FeedMedia.PREF_FEED_ID, -1);
+ long mediaId = pref.getLong(FeedMedia.PREF_MEDIA_ID, -1);
+ if (feedId != -1 && mediaId != -1) {
+ Feed feed = FeedManager.getInstance().getFeed(feedId);
+ if (feed != null) {
+ return FeedManager.getInstance().getFeedMedia(mediaId,
+ feed);
+ }
+ }
+ break;
+ case ExternalMedia.PLAYABLE_TYPE_EXTERNAL_MEDIA:
+ String source = pref.getString(ExternalMedia.PREF_SOURCE_URL,
+ null);
+ String mediaType = pref.getString(
+ ExternalMedia.PREF_MEDIA_TYPE, null);
+ if (source != null && mediaType != null) {
+ int position = pref.getInt(ExternalMedia.PREF_POSITION, 0);
+ return new ExternalMedia(source,
+ MediaType.valueOf(mediaType), position);
+ }
+ break;
+ }
+ Log.e(TAG, "Could not restore Playable object from preferences");
+ return null;
+ }
+ }
+
+ public static class PlayableException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public PlayableException() {
+ super();
+ }
+
+ public PlayableException(String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
+ }
+
+ public PlayableException(String detailMessage) {
+ super(detailMessage);
+ }
+
+ public PlayableException(Throwable throwable) {
+ super(throwable);
+ }
+
+ }
+
+ public static interface ShownoteLoaderCallback {
+ void onShownotesLoaded(String shownotes);
+ }
+}
diff --git a/src/de/danoeh/antennapod/util/PlaybackController.java b/src/de/danoeh/antennapod/util/playback/PlaybackController.java
index 1a61555ff..699ff6699 100644
--- a/src/de/danoeh/antennapod/util/PlaybackController.java
+++ b/src/de/danoeh/antennapod/util/playback/PlaybackController.java
@@ -1,4 +1,4 @@
-package de.danoeh.antennapod.util;
+package de.danoeh.antennapod.util.playback;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledFuture;
@@ -30,8 +30,11 @@ import de.danoeh.antennapod.R;
import de.danoeh.antennapod.feed.Chapter;
import de.danoeh.antennapod.feed.FeedManager;
import de.danoeh.antennapod.feed.FeedMedia;
+import de.danoeh.antennapod.preferences.PlaybackPreferences;
import de.danoeh.antennapod.service.PlaybackService;
import de.danoeh.antennapod.service.PlayerStatus;
+import de.danoeh.antennapod.util.Converter;
+import de.danoeh.antennapod.util.playback.Playable.PlayableUtils;
/**
* Communicates with the playback service. GUI classes should use this class to
@@ -46,7 +49,7 @@ public abstract class PlaybackController {
private Activity activity;
private PlaybackService playbackService;
- private FeedMedia media;
+ private Playable media;
private PlayerStatus status;
private ScheduledThreadPoolExecutor schedExecutor;
@@ -185,26 +188,22 @@ public abstract class PlaybackController {
Log.d(TAG, "Trying to restore last played media");
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(activity.getApplicationContext());
- long mediaId = prefs.getLong(PlaybackService.PREF_LAST_PLAYED_ID, -1);
- long feedId = prefs.getLong(PlaybackService.PREF_LAST_PLAYED_FEED_ID,
- -1);
- if (mediaId != -1 && feedId != -1) {
- FeedMedia media = FeedManager.getInstance().getFeedMedia(mediaId);
+ long lastPlayedId = PlaybackPreferences.getLastPlayedId();
+ if (lastPlayedId != PlaybackPreferences.NO_MEDIA_PLAYING) {
+ Playable media = PlayableUtils.createInstanceFromPreferences((int) lastPlayedId, prefs);
if (media != null) {
Intent serviceIntent = new Intent(activity,
PlaybackService.class);
- serviceIntent.putExtra(PlaybackService.EXTRA_FEED_ID, feedId);
- serviceIntent.putExtra(PlaybackService.EXTRA_MEDIA_ID, mediaId);
+ serviceIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
serviceIntent.putExtra(
PlaybackService.EXTRA_START_WHEN_PREPARED, false);
serviceIntent.putExtra(
PlaybackService.EXTRA_PREPARE_IMMEDIATELY, false);
- boolean fileExists = media.fileExists();
- boolean lastIsStream = prefs.getBoolean(
- PlaybackService.PREF_LAST_IS_STREAM, true);
- if (!fileExists && !lastIsStream) {
+ boolean fileExists = media.localFileAvailable();
+ boolean lastIsStream = PlaybackPreferences.isLastIsStream();
+ if (!fileExists && !lastIsStream && media instanceof FeedMedia) {
FeedManager.getInstance().notifyMissingFeedMediaFile(
- activity, media);
+ activity, (FeedMedia) media);
}
serviceIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM,
lastIsStream || !fileExists);
@@ -586,7 +585,7 @@ public abstract class PlaybackController {
}
}
- public FeedMedia getMedia() {
+ public Playable getMedia() {
return media;
}