Merge branch 'feedmanager_removal' into develop
Conflicts: src/de/danoeh/antennapod/activity/DownloadLogActivity.java src/de/danoeh/antennapod/activity/FeedItemlistActivity.java src/de/danoeh/antennapod/activity/ItemviewActivity.java src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java src/de/danoeh/antennapod/activity/PreferenceActivity.java src/de/danoeh/antennapod/fragment/EpisodesFragment.java src/de/danoeh/antennapod/fragment/FeedlistFragment.java src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java src/de/danoeh/antennapod/fragment/ItemlistFragment.java
This commit is contained in:
commit
8e16ad08c8
@ -19,7 +19,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:text="@string/no_feeds_label" />
|
||||
android:gravity="center"/>
|
||||
|
||||
</LinearLayout>
|
@ -16,7 +16,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:text="@string/no_items_label" />
|
||||
android:gravity="center"/>
|
||||
|
||||
</LinearLayout>
|
@ -15,7 +15,5 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/no_feeds_label" />
|
||||
|
||||
android:layout_gravity="center"/>
|
||||
</LinearLayout>
|
@ -5,7 +5,6 @@ import android.content.res.Configuration;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.asynctask.ImageLoader;
|
||||
import de.danoeh.antennapod.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.preferences.UserPreferences;
|
||||
|
||||
@ -32,8 +31,6 @@ public class PodcastApp extends Application {
|
||||
UserPreferences.createInstance(this);
|
||||
PlaybackPreferences.createInstance(this);
|
||||
EventDistributor.getInstance();
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
manager.loadDBData(getApplicationContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -11,6 +11,7 @@ import android.content.res.TypedArray;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.support.v7.view.ActionMode;
|
||||
import android.util.Log;
|
||||
@ -25,8 +26,8 @@ import android.widget.ListView;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
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.DownloadRequest;
|
||||
import de.danoeh.antennapod.service.download.DownloadService;
|
||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
|
||||
@ -35,226 +36,227 @@ import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
* objects created by a DownloadObserver.
|
||||
*/
|
||||
public class DownloadActivity extends ActionBarActivity implements
|
||||
ActionMode.Callback {
|
||||
ActionMode.Callback {
|
||||
|
||||
private static final String TAG = "DownloadActivity";
|
||||
private static final int MENU_SHOW_LOG = 0;
|
||||
private static final int MENU_CANCEL_ALL_DOWNLOADS = 1;
|
||||
private DownloadlistAdapter dla;
|
||||
private DownloadRequester requester;
|
||||
private static final String TAG = "DownloadActivity";
|
||||
private static final int MENU_SHOW_LOG = 0;
|
||||
private static final int MENU_CANCEL_ALL_DOWNLOADS = 1;
|
||||
private DownloadlistAdapter dla;
|
||||
private DownloadRequester requester;
|
||||
|
||||
private ActionMode mActionMode;
|
||||
private DownloadStatus selectedDownload;
|
||||
private ActionMode mActionMode;
|
||||
private DownloadRequest selectedDownload;
|
||||
|
||||
private DownloadService downloadService = null;
|
||||
boolean mIsBound;
|
||||
private DownloadService downloadService = null;
|
||||
boolean mIsBound;
|
||||
|
||||
private AsyncTask<Void, Void, Void> contentRefresher;
|
||||
private AsyncTask<Void, Void, Void> contentRefresher;
|
||||
|
||||
private ListView listview;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.listview_activity);
|
||||
|
||||
listview = (ListView) findViewById(R.id.listview);
|
||||
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Creating Activity");
|
||||
requester = DownloadRequester.getInstance();
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Creating Activity");
|
||||
requester = DownloadRequester.getInstance();
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
unbindService(mConnection);
|
||||
unregisterReceiver(contentChanged);
|
||||
}
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
unbindService(mConnection);
|
||||
unregisterReceiver(contentChanged);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
registerReceiver(contentChanged, new IntentFilter(
|
||||
DownloadService.ACTION_DOWNLOADS_CONTENT_CHANGED));
|
||||
bindService(new Intent(this, DownloadService.class), mConnection, 0);
|
||||
startContentRefresher();
|
||||
if (dla != null) {
|
||||
dla.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
registerReceiver(contentChanged, new IntentFilter(
|
||||
DownloadService.ACTION_DOWNLOADS_CONTENT_CHANGED));
|
||||
bindService(new Intent(this, DownloadService.class), mConnection, 0);
|
||||
startContentRefresher();
|
||||
if (dla != null) {
|
||||
dla.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Stopping Activity");
|
||||
stopContentRefresher();
|
||||
}
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Stopping Activity");
|
||||
stopContentRefresher();
|
||||
}
|
||||
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
downloadService = null;
|
||||
mIsBound = false;
|
||||
Log.i(TAG, "Closed connection with DownloadService.");
|
||||
}
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
downloadService = null;
|
||||
mIsBound = false;
|
||||
Log.i(TAG, "Closed connection with DownloadService.");
|
||||
}
|
||||
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
downloadService = ((DownloadService.LocalBinder) service)
|
||||
.getService();
|
||||
mIsBound = true;
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Connection to service established");
|
||||
dla = new DownloadlistAdapter(DownloadActivity.this, 0,
|
||||
downloadService.getDownloads());
|
||||
listview.setAdapter(dla);
|
||||
dla.notifyDataSetChanged();
|
||||
}
|
||||
};
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
downloadService = ((DownloadService.LocalBinder) service)
|
||||
.getService();
|
||||
mIsBound = true;
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Connection to service established");
|
||||
dla = new DownloadlistAdapter(DownloadActivity.this, 0,
|
||||
downloadService.getDownloads());
|
||||
listview.setAdapter(dla);
|
||||
dla.notifyDataSetChanged();
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private void startContentRefresher() {
|
||||
if (contentRefresher != null) {
|
||||
contentRefresher.cancel(true);
|
||||
}
|
||||
contentRefresher = new AsyncTask<Void, Void, Void>() {
|
||||
private final int WAITING_INTERVALL = 1000;
|
||||
@SuppressLint("NewApi")
|
||||
private void startContentRefresher() {
|
||||
if (contentRefresher != null) {
|
||||
contentRefresher.cancel(true);
|
||||
}
|
||||
contentRefresher = new AsyncTask<Void, Void, Void>() {
|
||||
private final int WAITING_INTERVALL = 1000;
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Void... values) {
|
||||
super.onProgressUpdate(values);
|
||||
if (dla != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Refreshing content automatically");
|
||||
dla.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onProgressUpdate(Void... values) {
|
||||
super.onProgressUpdate(values);
|
||||
if (dla != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Refreshing content automatically");
|
||||
dla.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
while (!isCancelled()) {
|
||||
try {
|
||||
Thread.sleep(WAITING_INTERVALL);
|
||||
publishProgress();
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
contentRefresher.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
contentRefresher.execute();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
while (!isCancelled()) {
|
||||
try {
|
||||
Thread.sleep(WAITING_INTERVALL);
|
||||
publishProgress();
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
contentRefresher.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
contentRefresher.execute();
|
||||
}
|
||||
}
|
||||
|
||||
private void stopContentRefresher() {
|
||||
if (contentRefresher != null) {
|
||||
contentRefresher.cancel(true);
|
||||
}
|
||||
}
|
||||
private void stopContentRefresher() {
|
||||
if (contentRefresher != null) {
|
||||
contentRefresher.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
listview.setOnItemLongClickListener(new OnItemLongClickListener() {
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
listview.setOnItemLongClickListener(new OnItemLongClickListener() {
|
||||
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> arg0, View view,
|
||||
int position, long id) {
|
||||
DownloadStatus selection = dla.getItem(position).getStatus();
|
||||
if (selection != null && mActionMode != null) {
|
||||
mActionMode.finish();
|
||||
}
|
||||
dla.setSelectedItemIndex(position);
|
||||
selectedDownload = selection;
|
||||
mActionMode = startSupportActionMode(DownloadActivity.this);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> arg0, View view,
|
||||
int position, long id) {
|
||||
DownloadRequest selection = dla.getItem(position)
|
||||
.getDownloadRequest();
|
||||
if (selection != null && mActionMode != null) {
|
||||
mActionMode.finish();
|
||||
}
|
||||
dla.setSelectedItemIndex(position);
|
||||
selectedDownload = selection;
|
||||
mActionMode = startSupportActionMode(DownloadActivity.this);
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(Menu.NONE, MENU_SHOW_LOG, Menu.NONE,
|
||||
R.string.show_download_log).setShowAsAction(
|
||||
MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
|
||||
menu.add(Menu.NONE, MENU_CANCEL_ALL_DOWNLOADS, Menu.NONE,
|
||||
R.string.cancel_all_downloads_label).setShowAsAction(
|
||||
MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, MENU_SHOW_LOG, Menu.NONE,
|
||||
R.string.show_download_log),
|
||||
MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
|
||||
MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, MENU_CANCEL_ALL_DOWNLOADS, Menu.NONE,
|
||||
R.string.cancel_all_downloads_label),
|
||||
MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
| Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
break;
|
||||
case MENU_SHOW_LOG:
|
||||
startActivity(new Intent(this, DownloadLogActivity.class));
|
||||
break;
|
||||
case MENU_CANCEL_ALL_DOWNLOADS:
|
||||
requester.cancelAllDownloads(this);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
| Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
break;
|
||||
case MENU_SHOW_LOG:
|
||||
startActivity(new Intent(this, DownloadLogActivity.class));
|
||||
break;
|
||||
case MENU_CANCEL_ALL_DOWNLOADS:
|
||||
requester.cancelAllDownloads(this);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
if (!selectedDownload.isDone()) {
|
||||
TypedArray drawables = obtainStyledAttributes(new int[] { R.attr.navigation_cancel });
|
||||
menu.add(Menu.NONE, R.id.cancel_download_item, Menu.NONE,
|
||||
R.string.cancel_download_label).setIcon(
|
||||
drawables.getDrawable(0));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
if (selectedDownload != null) {
|
||||
TypedArray drawables = obtainStyledAttributes(new int[]{R.attr.navigation_cancel});
|
||||
menu.add(Menu.NONE, R.id.cancel_download_item, Menu.NONE,
|
||||
R.string.cancel_download_label).setIcon(
|
||||
drawables.getDrawable(0));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
boolean handled = false;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.cancel_download_item:
|
||||
requester.cancelDownload(this, selectedDownload.getFeedFile());
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
mActionMode.finish();
|
||||
return handled;
|
||||
}
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
boolean handled = false;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.cancel_download_item:
|
||||
requester.cancelDownload(this, selectedDownload.getSource());
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
mActionMode.finish();
|
||||
return handled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
mActionMode = null;
|
||||
selectedDownload = null;
|
||||
dla.setSelectedItemIndex(DownloadlistAdapter.SELECTION_NONE);
|
||||
}
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
mActionMode = null;
|
||||
selectedDownload = null;
|
||||
dla.setSelectedItemIndex(DownloadlistAdapter.SELECTION_NONE);
|
||||
}
|
||||
|
||||
private BroadcastReceiver contentChanged = new BroadcastReceiver() {
|
||||
private BroadcastReceiver contentChanged = new BroadcastReceiver() {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (dla != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Refreshing content");
|
||||
dla.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (dla != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Refreshing content");
|
||||
dla.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,27 +1,31 @@
|
||||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.ListView;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.adapter.DownloadLogAdapter;
|
||||
import de.danoeh.antennapod.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.storage.DBReader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Displays completed and failed downloads in a list. The data comes from the
|
||||
* FeedManager.
|
||||
* Displays completed and failed downloads in a list.
|
||||
*/
|
||||
public class DownloadLogActivity extends ActionBarActivity {
|
||||
private static final String TAG = "DownloadLogActivity";
|
||||
|
||||
DownloadLogAdapter dla;
|
||||
FeedManager manager;
|
||||
private List<DownloadStatus> downloadLog;
|
||||
private DownloadLogAdapter dla;
|
||||
|
||||
private ListView listview;
|
||||
|
||||
@ -30,13 +34,14 @@ public class DownloadLogActivity extends ActionBarActivity {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.listview_activity);
|
||||
manager = FeedManager.getInstance();
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
|
||||
listview = (ListView) findViewById(R.layout.listview_activity);
|
||||
|
||||
dla = new DownloadLogAdapter(this);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
dla = new DownloadLogAdapter(this, itemAccess);
|
||||
listview.setAdapter(dla);
|
||||
loadData();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -69,12 +74,48 @@ public class DownloadLogActivity extends ActionBarActivity {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
AsyncTask<Void, Void, List<DownloadStatus>> loadTask = new AsyncTask<Void, Void, List<DownloadStatus>>() {
|
||||
@Override
|
||||
protected List<DownloadStatus> doInBackground(Void... voids) {
|
||||
return DBReader.getDownloadLog(DownloadLogActivity.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<DownloadStatus> downloadStatuses) {
|
||||
super.onPostExecute(downloadStatuses);
|
||||
if (downloadStatuses != null) {
|
||||
downloadLog = downloadStatuses;
|
||||
if (dla != null) {
|
||||
dla.notifyDataSetChanged();
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Could not load download log");
|
||||
}
|
||||
}
|
||||
};
|
||||
loadTask.execute();
|
||||
}
|
||||
|
||||
private DownloadLogAdapter.ItemAccess itemAccess = new DownloadLogAdapter.ItemAccess() {
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return (downloadLog != null) ? downloadLog.size() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadStatus getItem(int position) {
|
||||
return (downloadLog != null) ? downloadLog.get(position) : null;
|
||||
}
|
||||
};
|
||||
|
||||
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
|
||||
|
||||
@Override
|
||||
public void update(EventDistributor eventDistributor, Integer arg) {
|
||||
if ((arg & EventDistributor.DOWNLOADLOG_UPDATE) != 0) {
|
||||
dla.notifyDataSetChanged();
|
||||
loadData();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.util.Log;
|
||||
@ -14,8 +15,8 @@ import de.danoeh.antennapod.R;
|
||||
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.DBReader;
|
||||
import de.danoeh.antennapod.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.util.LangUtils;
|
||||
import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
|
||||
@ -41,47 +42,66 @@ public class FeedInfoActivity extends ActionBarActivity {
|
||||
setContentView(R.layout.feedinfo);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
long feedId = getIntent().getLongExtra(EXTRA_FEED_ID, -1);
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
feed = manager.getFeed(feedId);
|
||||
if (feed != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Language is " + feed.getLanguage());
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Author is " + feed.getAuthor());
|
||||
imgvCover = (ImageView) findViewById(R.id.imgvCover);
|
||||
txtvTitle = (TextView) findViewById(R.id.txtvTitle);
|
||||
txtvDescription = (TextView) findViewById(R.id.txtvDescription);
|
||||
txtvLanguage = (TextView) findViewById(R.id.txtvLanguage);
|
||||
txtvAuthor = (TextView) findViewById(R.id.txtvAuthor);
|
||||
imgvCover.post(new Runnable() {
|
||||
|
||||
AsyncTask<Long, Void, Feed> loadTask = new AsyncTask<Long, Void, Feed>() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ImageLoader.getInstance().loadThumbnailBitmap(
|
||||
feed.getImage(), imgvCover);
|
||||
@Override
|
||||
protected Feed doInBackground(Long... params) {
|
||||
return DBReader.getFeed(FeedInfoActivity.this, params[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Feed result) {
|
||||
super.onPostExecute(result);
|
||||
if (result != null) {
|
||||
feed = result;
|
||||
if (feed != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Language is " + feed.getLanguage());
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Author is " + feed.getAuthor());
|
||||
imgvCover = (ImageView) findViewById(R.id.imgvCover);
|
||||
txtvTitle = (TextView) findViewById(R.id.txtvTitle);
|
||||
txtvDescription = (TextView) findViewById(R.id.txtvDescription);
|
||||
txtvLanguage = (TextView) findViewById(R.id.txtvLanguage);
|
||||
txtvAuthor = (TextView) findViewById(R.id.txtvAuthor);
|
||||
imgvCover.post(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ImageLoader.getInstance().loadThumbnailBitmap(
|
||||
feed.getImage(), imgvCover);
|
||||
}
|
||||
});
|
||||
|
||||
txtvTitle.setText(feed.getTitle());
|
||||
txtvDescription.setText(feed.getDescription());
|
||||
if (feed.getAuthor() != null) {
|
||||
txtvAuthor.setText(feed.getAuthor());
|
||||
}
|
||||
if (feed.getLanguage() != null) {
|
||||
txtvLanguage.setText(LangUtils
|
||||
.getLanguageString(feed.getLanguage()));
|
||||
}
|
||||
supportInvalidateOptionsMenu();
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Activity was started with invalid arguments");
|
||||
}
|
||||
});
|
||||
|
||||
txtvTitle.setText(feed.getTitle());
|
||||
txtvDescription.setText(feed.getDescription());
|
||||
if (feed.getAuthor() != null) {
|
||||
txtvAuthor.setText(feed.getAuthor());
|
||||
}
|
||||
if (feed.getLanguage() != null) {
|
||||
txtvLanguage.setText(LangUtils.getLanguageString(feed
|
||||
.getLanguage()));
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Activity was started with invalid arguments");
|
||||
}
|
||||
|
||||
};
|
||||
loadTask.execute(feedId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = new MenuInflater(this);
|
||||
inflater.inflate(R.menu.feedinfo, menu);
|
||||
return true;
|
||||
if (feed != null) {
|
||||
MenuInflater inflater = new MenuInflater(this);
|
||||
inflater.inflate(R.menu.feedinfo, menu);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -104,7 +124,8 @@ public class FeedInfoActivity extends ActionBarActivity {
|
||||
return FeedMenuHandler.onOptionsItemClicked(this, item, feed);
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
DownloadRequestErrorDialogCreator.newRequestErrorDialog(this, e.getMessage());
|
||||
DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
|
||||
e.getMessage());
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
@ -4,9 +4,11 @@ import android.annotation.SuppressLint;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.util.Log;
|
||||
|
||||
@ -14,137 +16,173 @@ import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.Window;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.asynctask.FeedRemover;
|
||||
import de.danoeh.antennapod.dialog.ConfirmationDialog;
|
||||
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
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.DBReader;
|
||||
import de.danoeh.antennapod.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.util.StorageUtils;
|
||||
import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
|
||||
|
||||
/** Displays a List of FeedItems */
|
||||
/**
|
||||
* Displays a List of FeedItems
|
||||
*/
|
||||
public class FeedItemlistActivity extends ActionBarActivity {
|
||||
private static final String TAG = "FeedItemlistActivity";
|
||||
private static final String TAG = "FeedItemlistActivity";
|
||||
|
||||
private FeedManager manager;
|
||||
/**
|
||||
* The feed which the activity displays
|
||||
*/
|
||||
private Feed feed;
|
||||
private ItemlistFragment filf;
|
||||
private ExternalPlayerFragment externalPlayerFragment;
|
||||
|
||||
/** The feed which the activity displays */
|
||||
private Feed feed;
|
||||
private ItemlistFragment filf;
|
||||
private ExternalPlayerFragment externalPlayerFragment;
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.feeditemlist_activity);
|
||||
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.feeditemlist_activity);
|
||||
long feedId = getIntent().getLongExtra(
|
||||
FeedlistFragment.EXTRA_SELECTED_FEED, -1);
|
||||
if (feedId == -1) {
|
||||
Log.e(TAG, "Received invalid feed selection.");
|
||||
} else {
|
||||
loadData(feedId);
|
||||
}
|
||||
|
||||
manager = FeedManager.getInstance();
|
||||
long feedId = getIntent().getLongExtra(
|
||||
FeedlistFragment.EXTRA_SELECTED_FEED, -1);
|
||||
if (feedId == -1)
|
||||
Log.e(TAG, "Received invalid feed selection.");
|
||||
}
|
||||
|
||||
feed = manager.getFeed(feedId);
|
||||
setTitle(feed.getTitle());
|
||||
private void loadData(long id) {
|
||||
AsyncTask<Long, Void, Feed> loadTask = new AsyncTask<Long, Void, Feed>() {
|
||||
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
FragmentTransaction fT = fragmentManager.beginTransaction();
|
||||
@Override
|
||||
protected Feed doInBackground(Long... longs) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Loading feed data in background");
|
||||
return DBReader.getFeed(FeedItemlistActivity.this, longs[0]);
|
||||
}
|
||||
|
||||
filf = ItemlistFragment.newInstance(feed.getId());
|
||||
fT.replace(R.id.feeditemlistFragment, filf);
|
||||
@Override
|
||||
protected void onPostExecute(Feed result) {
|
||||
super.onPostExecute(result);
|
||||
if (result != null) {
|
||||
if (AppConfig.DEBUG) Log.d(TAG, "Finished loading feed data");
|
||||
feed = result;
|
||||
setTitle(feed.getTitle());
|
||||
|
||||
externalPlayerFragment = new ExternalPlayerFragment();
|
||||
fT.replace(R.id.playerFragment, externalPlayerFragment);
|
||||
fT.commit();
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
FragmentTransaction fT = fragmentManager.beginTransaction();
|
||||
|
||||
}
|
||||
filf = ItemlistFragment.newInstance(feed.getId());
|
||||
fT.replace(R.id.feeditemlistFragment, filf);
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
}
|
||||
externalPlayerFragment = new ExternalPlayerFragment();
|
||||
fT.replace(R.id.playerFragment, externalPlayerFragment);
|
||||
fT.commit();
|
||||
supportInvalidateOptionsMenu();
|
||||
} else {
|
||||
Log.e(TAG, "Error: Feed was null");
|
||||
}
|
||||
}
|
||||
};
|
||||
loadTask.execute(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
TypedArray drawables = obtainStyledAttributes(new int[] { R.attr.action_search });
|
||||
menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
|
||||
.setIcon(drawables.getDrawable(0))
|
||||
.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
|
||||
return FeedMenuHandler
|
||||
.onCreateOptionsMenu(new MenuInflater(this), menu);
|
||||
}
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return FeedMenuHandler.onPrepareOptionsMenu(menu, feed);
|
||||
}
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
if (feed != null) {
|
||||
TypedArray drawables = obtainStyledAttributes(new int[]{R.attr.action_search});
|
||||
MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
|
||||
.setIcon(drawables.getDrawable(0)),
|
||||
MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
|
||||
return FeedMenuHandler
|
||||
.onCreateOptionsMenu(new MenuInflater(this), menu);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
try {
|
||||
if (FeedMenuHandler.onOptionsItemClicked(this, item, feed)) {
|
||||
filf.getListAdapter().notifyDataSetChanged();
|
||||
} else {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.remove_item:
|
||||
final FeedRemover remover = new FeedRemover(
|
||||
FeedItemlistActivity.this, feed) {
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
super.onPostExecute(result);
|
||||
finish();
|
||||
}
|
||||
};
|
||||
ConfirmationDialog conDialog = new ConfirmationDialog(this,
|
||||
R.string.remove_feed_label,
|
||||
R.string.feed_delete_confirmation_msg) {
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return FeedMenuHandler.onPrepareOptionsMenu(menu, feed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfirmButtonPressed(
|
||||
DialogInterface dialog) {
|
||||
dialog.dismiss();
|
||||
remover.executeAsync();
|
||||
}
|
||||
};
|
||||
conDialog.createNewDialog().show();
|
||||
break;
|
||||
case R.id.search_item:
|
||||
onSearchRequested();
|
||||
break;
|
||||
case android.R.id.home:
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(intent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
|
||||
e.getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
try {
|
||||
if (FeedMenuHandler.onOptionsItemClicked(this, item, feed)) {
|
||||
filf.getListAdapter().notifyDataSetChanged();
|
||||
} else {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.remove_item:
|
||||
final FeedRemover remover = new FeedRemover(
|
||||
FeedItemlistActivity.this, feed) {
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
super.onPostExecute(result);
|
||||
finish();
|
||||
}
|
||||
};
|
||||
ConfirmationDialog conDialog = new ConfirmationDialog(this,
|
||||
R.string.remove_feed_label,
|
||||
R.string.feed_delete_confirmation_msg) {
|
||||
|
||||
@Override
|
||||
public boolean onSearchRequested() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putLong(SearchActivity.EXTRA_FEED_ID, feed.getId());
|
||||
startSearch(null, false, bundle, false);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public void onConfirmButtonPressed(
|
||||
DialogInterface dialog) {
|
||||
dialog.dismiss();
|
||||
remover.executeAsync();
|
||||
}
|
||||
};
|
||||
conDialog.createNewDialog().show();
|
||||
break;
|
||||
case R.id.search_item:
|
||||
onSearchRequested();
|
||||
break;
|
||||
case android.R.id.home:
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(intent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
|
||||
e.getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSearchRequested() {
|
||||
if (feed != null) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putLong(SearchActivity.EXTRA_FEED_ID, feed.getId());
|
||||
startSearch(null, false, bundle, false);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import java.text.DateFormat;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
@ -17,38 +16,43 @@ import android.widget.TextView;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
import de.danoeh.antennapod.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.feed.FeedItem;
|
||||
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.DBReader;
|
||||
import de.danoeh.antennapod.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.util.QueueAccess;
|
||||
import de.danoeh.antennapod.util.StorageUtils;
|
||||
import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
|
||||
|
||||
import java.text.DateFormat;
|
||||
|
||||
/** Displays a single FeedItem and provides various actions */
|
||||
public class ItemviewActivity extends ActionBarActivity {
|
||||
private static final String TAG = "ItemviewActivity";
|
||||
|
||||
private FeedManager manager;
|
||||
private FeedItem item;
|
||||
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED | EventDistributor.DOWNLOAD_QUEUED;
|
||||
|
||||
// Widgets
|
||||
private TextView txtvTitle;
|
||||
private TextView txtvPublished;
|
||||
private FeedItem item;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
manager = FeedManager.getInstance();
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
getSupportActionBar().setDisplayShowTitleEnabled(false);
|
||||
extractFeeditem();
|
||||
populateUI();
|
||||
EventDistributor.getInstance().register(contentUpdate);
|
||||
|
||||
long itemId = getIntent().getLongExtra(
|
||||
ItemlistFragment.EXTRA_SELECTED_FEEDITEM, -1);
|
||||
if (itemId == -1) {
|
||||
Log.e(TAG, "Received invalid selection of either feeditem or feed.");
|
||||
} else {
|
||||
loadData(itemId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,28 +69,38 @@ public class ItemviewActivity extends ActionBarActivity {
|
||||
Log.d(TAG, "Stopping Activity");
|
||||
}
|
||||
|
||||
/** Extracts FeedItem object the activity is supposed to display */
|
||||
private void extractFeeditem() {
|
||||
long itemId = getIntent().getLongExtra(
|
||||
ItemlistFragment.EXTRA_SELECTED_FEEDITEM, -1);
|
||||
long feedId = getIntent().getLongExtra(
|
||||
FeedlistFragment.EXTRA_SELECTED_FEED, -1);
|
||||
if (itemId == -1 || feedId == -1) {
|
||||
Log.e(TAG, "Received invalid selection of either feeditem or feed.");
|
||||
}
|
||||
Feed feed = manager.getFeed(feedId);
|
||||
item = manager.getFeedItem(itemId, feed);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Title of item is " + item.getTitle());
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Title of feed is " + item.getFeed().getTitle());
|
||||
}
|
||||
private void loadData(long itemId) {
|
||||
AsyncTask<Long, Void, FeedItem> loadTask = new AsyncTask<Long, Void, FeedItem>() {
|
||||
|
||||
@Override
|
||||
protected FeedItem doInBackground(Long... longs) {
|
||||
return DBReader.getFeedItem(ItemviewActivity.this, longs[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(FeedItem feedItem) {
|
||||
super.onPostExecute(feedItem);
|
||||
if (feedItem != null && feedItem.getFeed() != null) {
|
||||
item = feedItem;
|
||||
populateUI();
|
||||
supportInvalidateOptionsMenu();
|
||||
} else {
|
||||
if (feedItem == null) {
|
||||
Log.e(TAG, "Error: FeedItem was null");
|
||||
} else if (feedItem.getFeed() == null) {
|
||||
Log.e(TAG, "Error: Feed was null");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
loadTask.execute(itemId);
|
||||
}
|
||||
|
||||
private void populateUI() {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.feeditemview);
|
||||
txtvTitle = (TextView) findViewById(R.id.txtvItemname);
|
||||
txtvPublished = (TextView) findViewById(R.id.txtvPublished);
|
||||
TextView txtvTitle = (TextView) findViewById(R.id.txtvItemname);
|
||||
TextView txtvPublished = (TextView) findViewById(R.id.txtvPublished);
|
||||
setTitle(item.getFeed().getTitle());
|
||||
|
||||
txtvPublished.setText(DateUtils.formatSameDayTime(item.getPubDate()
|
||||
@ -105,9 +119,13 @@ public class ItemviewActivity extends ActionBarActivity {
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.feeditem, menu);
|
||||
return true;
|
||||
if (item != null) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.feeditem, menu);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -133,13 +151,28 @@ public class ItemviewActivity extends ActionBarActivity {
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(final Menu menu) {
|
||||
return FeedItemMenuHandler.onPrepareMenu(
|
||||
new FeedItemMenuHandler.MenuInterface() {
|
||||
new FeedItemMenuHandler.MenuInterface() {
|
||||
|
||||
@Override
|
||||
public void setItemVisibility(int id, boolean visible) {
|
||||
menu.findItem(id).setVisible(visible);
|
||||
}
|
||||
}, item, true);
|
||||
@Override
|
||||
public void setItemVisibility(int id, boolean visible) {
|
||||
menu.findItem(id).setVisible(visible);
|
||||
}
|
||||
}, item, true, QueueAccess.NotInQueueAccess());
|
||||
}
|
||||
|
||||
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
|
||||
|
||||
@Override
|
||||
public void update(EventDistributor eventDistributor, Integer arg) {
|
||||
if ((EVENTS & arg) != 0) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Received contentUpdate Intent.");
|
||||
if (item != null) {
|
||||
loadData(item.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
@ -20,13 +20,14 @@ import android.view.Window;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
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.DBReader;
|
||||
import de.danoeh.antennapod.storage.DBTasks;
|
||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.util.StorageUtils;
|
||||
|
||||
@ -37,7 +38,6 @@ public class MainActivity extends ActionBarActivity {
|
||||
private static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
|
||||
| EventDistributor.DOWNLOAD_QUEUED;
|
||||
|
||||
private FeedManager manager;
|
||||
private ViewPager viewpager;
|
||||
private TabsAdapter pagerAdapter;
|
||||
private ExternalPlayerFragment externalPlayerFragment;
|
||||
@ -49,7 +49,6 @@ public class MainActivity extends ActionBarActivity {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
manager = FeedManager.getInstance();
|
||||
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
@ -78,7 +77,7 @@ public class MainActivity extends ActionBarActivity {
|
||||
if (!appLaunched && getIntent().getAction() != null
|
||||
&& getIntent().getAction().equals(Intent.ACTION_MAIN)) {
|
||||
appLaunched = true;
|
||||
if (manager.getUnreadItemsSize(true) > 0) {
|
||||
if (DBReader.getNumberOfUnreadItems(this) > 0) {
|
||||
// select 'episodes' tab
|
||||
getSupportActionBar().setSelectedNavigationItem(1);
|
||||
}
|
||||
@ -140,7 +139,7 @@ public class MainActivity extends ActionBarActivity {
|
||||
startActivity(new Intent(this, AddFeedActivity.class));
|
||||
return true;
|
||||
case R.id.all_feed_refresh:
|
||||
manager.refreshAllFeeds(this);
|
||||
DBTasks.refreshAllFeeds(this, null);
|
||||
return true;
|
||||
case R.id.show_downloads:
|
||||
startActivity(new Intent(this, DownloadActivity.class));
|
||||
@ -171,9 +170,6 @@ public class MainActivity extends ActionBarActivity {
|
||||
} else {
|
||||
refreshAll.setVisible(true);
|
||||
}
|
||||
|
||||
boolean hasFeeds = manager.getFeedsSize() > 0;
|
||||
menu.findItem(R.id.all_feed_refresh).setVisible(hasFeeds);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@ import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.asynctask.FlattrClickWorker;
|
||||
import de.danoeh.antennapod.dialog.TimeDialog;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.service.PlaybackService;
|
||||
import de.danoeh.antennapod.util.Converter;
|
||||
@ -38,8 +37,6 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||
implements OnSeekBarChangeListener {
|
||||
private static final String TAG = "MediaplayerActivity";
|
||||
|
||||
protected FeedManager manager;
|
||||
|
||||
protected PlaybackController controller;
|
||||
|
||||
protected TextView txtvPosition;
|
||||
@ -148,7 +145,6 @@ public abstract class MediaplayerActivity extends ActionBarActivity
|
||||
StorageUtils.checkStorageAvailability(this);
|
||||
|
||||
orientation = getResources().getConfiguration().orientation;
|
||||
manager = FeedManager.getInstance();
|
||||
getWindow().setFormat(PixelFormat.TRANSPARENT);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
@ -24,11 +25,11 @@ import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.adapter.MiroGuideItemlistAdapter;
|
||||
import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
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.DBReader;
|
||||
import de.danoeh.antennapod.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
|
||||
@ -39,144 +40,161 @@ import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
public class MiroGuideChannelViewActivity extends ActionBarActivity {
|
||||
private static final String TAG = "MiroGuideChannelViewActivity";
|
||||
|
||||
public static final String EXTRA_CHANNEL_ID = "id";
|
||||
public static final String EXTRA_CHANNEL_URL = "url";
|
||||
public static final String EXTRA_CHANNEL_ID = "id";
|
||||
public static final String EXTRA_CHANNEL_URL = "url";
|
||||
|
||||
private RelativeLayout layoutContent;
|
||||
private ProgressBar progLoading;
|
||||
private TextView txtvTitle;
|
||||
private TextView txtVDescription;
|
||||
private ListView listEntries;
|
||||
private RelativeLayout layoutContent;
|
||||
private ProgressBar progLoading;
|
||||
private TextView txtvTitle;
|
||||
private TextView txtVDescription;
|
||||
private ListView listEntries;
|
||||
|
||||
private long channelId;
|
||||
private String channelUrl;
|
||||
private MiroGuideChannel channel;
|
||||
private long channelId;
|
||||
private String channelUrl;
|
||||
private MiroGuideChannel channel;
|
||||
private volatile List<Feed> feeds;
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
channelLoader.cancel(true);
|
||||
}
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
channelLoader.cancel(true);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.miroguide_channelview);
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.miroguide_channelview);
|
||||
|
||||
layoutContent = (RelativeLayout) findViewById(R.id.layout_content);
|
||||
progLoading = (ProgressBar) findViewById(R.id.progLoading);
|
||||
txtvTitle = (TextView) findViewById(R.id.txtvTitle);
|
||||
txtVDescription = (TextView) findViewById(R.id.txtvDescription);
|
||||
listEntries = (ListView) findViewById(R.id.itemlist);
|
||||
layoutContent = (RelativeLayout) findViewById(R.id.layout_content);
|
||||
progLoading = (ProgressBar) findViewById(R.id.progLoading);
|
||||
txtvTitle = (TextView) findViewById(R.id.txtvTitle);
|
||||
txtVDescription = (TextView) findViewById(R.id.txtvDescription);
|
||||
listEntries = (ListView) findViewById(R.id.itemlist);
|
||||
|
||||
channelId = getIntent().getLongExtra(EXTRA_CHANNEL_ID, -1);
|
||||
channelUrl = getIntent().getStringExtra(EXTRA_CHANNEL_URL);
|
||||
channelId = getIntent().getLongExtra(EXTRA_CHANNEL_ID, -1);
|
||||
channelUrl = getIntent().getStringExtra(EXTRA_CHANNEL_URL);
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
channelLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
channelLoader.execute();
|
||||
}
|
||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
channelLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
channelLoader.execute();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** Is used to load channel information asynchronously. */
|
||||
private AsyncTask<Void, Void, Void> channelLoader = new AsyncTask<Void, Void, Void>() {
|
||||
private static final String TAG = "ChannelLoader";
|
||||
private Exception exception;
|
||||
/**
|
||||
* Is used to load channel information asynchronously.
|
||||
*/
|
||||
private AsyncTask<Void, Void, Void> channelLoader = new AsyncTask<Void, Void, Void>() {
|
||||
private static final String TAG = "ChannelLoader";
|
||||
private Exception exception;
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Starting background task");
|
||||
MiroGuideService service = new MiroGuideService();
|
||||
try {
|
||||
channel = service.getChannel(channelId);
|
||||
} catch (MiroGuideException e) {
|
||||
e.printStackTrace();
|
||||
exception = e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Starting background task");
|
||||
feeds = DBReader.getFeedList(MiroGuideChannelViewActivity.this);
|
||||
MiroGuideService service = new MiroGuideService();
|
||||
try {
|
||||
channel = service.getChannel(channelId);
|
||||
} catch (MiroGuideException e) {
|
||||
e.printStackTrace();
|
||||
exception = e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Loading finished");
|
||||
if (exception == null) {
|
||||
txtvTitle.setText(channel.getName());
|
||||
txtVDescription.setText(channel.getDescription());
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Loading finished");
|
||||
if (exception == null) {
|
||||
txtvTitle.setText(channel.getName());
|
||||
txtVDescription.setText(channel.getDescription());
|
||||
|
||||
MiroGuideItemlistAdapter listAdapter = new MiroGuideItemlistAdapter(
|
||||
MiroGuideChannelViewActivity.this, 0,
|
||||
channel.getItems());
|
||||
listEntries.setAdapter(listAdapter);
|
||||
progLoading.setVisibility(View.GONE);
|
||||
layoutContent.setVisibility(View.VISIBLE);
|
||||
supportInvalidateOptionsMenu();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
MiroGuideItemlistAdapter listAdapter = new MiroGuideItemlistAdapter(
|
||||
MiroGuideChannelViewActivity.this, 0,
|
||||
channel.getItems());
|
||||
listEntries.setAdapter(listAdapter);
|
||||
progLoading.setVisibility(View.GONE);
|
||||
layoutContent.setVisibility(View.VISIBLE);
|
||||
supportInvalidateOptionsMenu();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = new MenuInflater(this);
|
||||
inflater.inflate(R.menu.channelview, menu);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = new MenuInflater(this);
|
||||
inflater.inflate(R.menu.channelview, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
boolean channelLoaded = channel != null;
|
||||
boolean beingDownloaded = channelLoaded
|
||||
&& DownloadRequester.getInstance().isDownloadingFile(
|
||||
channel.getDownloadUrl());
|
||||
boolean notAdded = channelLoaded
|
||||
&& !((FeedManager.getInstance().feedExists(
|
||||
channel.getDownloadUrl()) || beingDownloaded));
|
||||
menu.findItem(R.id.add_feed).setVisible(notAdded);
|
||||
menu.findItem(R.id.visit_website_item).setVisible(
|
||||
channelLoaded && channel.getWebsiteUrl() != null);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
boolean channelLoaded = channel != null;
|
||||
boolean beingDownloaded = channelLoaded
|
||||
&& DownloadRequester.getInstance().isDownloadingFile(
|
||||
channel.getDownloadUrl());
|
||||
boolean notAdded = channelLoaded
|
||||
&& !((feedExists(
|
||||
channel.getDownloadUrl()) || beingDownloaded));
|
||||
menu.findItem(R.id.add_feed).setVisible(notAdded);
|
||||
menu.findItem(R.id.visit_website_item).setVisible(
|
||||
channelLoaded && channel.getWebsiteUrl() != null);
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.visit_website_item:
|
||||
Uri uri = Uri.parse(channel.getWebsiteUrl());
|
||||
startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
||||
return true;
|
||||
case R.id.add_feed:
|
||||
try {
|
||||
DownloadRequester.getInstance().downloadFeed(
|
||||
this,
|
||||
new Feed(channel.getDownloadUrl(), new Date(), channel
|
||||
.getName()));
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
|
||||
e.getMessage());
|
||||
}
|
||||
Toast toast = Toast.makeText(this, R.string.miro_feed_added,
|
||||
Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
supportInvalidateOptionsMenu();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.visit_website_item:
|
||||
Uri uri = Uri.parse(channel.getWebsiteUrl());
|
||||
startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
||||
return true;
|
||||
case R.id.add_feed:
|
||||
try {
|
||||
DownloadRequester.getInstance().downloadFeed(
|
||||
this,
|
||||
new Feed(channel.getDownloadUrl(), new Date(), channel
|
||||
.getName()));
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
DownloadRequestErrorDialogCreator.newRequestErrorDialog(this,
|
||||
e.getMessage());
|
||||
}
|
||||
Toast toast = Toast.makeText(this, R.string.miro_feed_added,
|
||||
Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
supportInvalidateOptionsMenu();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean feedExists(String downloadUrl) {
|
||||
if (feeds == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Feed feed : feeds) {
|
||||
if (feed.getDownload_url().equals(downloadUrl)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
@ -24,126 +25,126 @@ import de.danoeh.antennapod.preferences.UserPreferences;
|
||||
* Shows a list of available categories and offers a search button. If the user
|
||||
* selects a category, the MiroGuideCategoryActivity is started.
|
||||
*/
|
||||
public class MiroGuideMainActivity extends ActionBarActivity implements AdapterView.OnItemClickListener{
|
||||
private static final String TAG = "MiroGuideMainActivity";
|
||||
public class MiroGuideMainActivity extends ActionBarActivity implements AdapterView.OnItemClickListener {
|
||||
private static final String TAG = "MiroGuideMainActivity";
|
||||
|
||||
private static String[] categories;
|
||||
private ArrayAdapter<String> listAdapter;
|
||||
private static String[] categories;
|
||||
private ArrayAdapter<String> listAdapter;
|
||||
|
||||
private TextView txtvStatus;
|
||||
private TextView txtvStatus;
|
||||
private ListView listView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.miroguide_categorylist);
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.miroguide_categorylist);
|
||||
|
||||
txtvStatus = (TextView) findViewById(android.R.id.empty);
|
||||
txtvStatus = (TextView) findViewById(android.R.id.empty);
|
||||
listView = (ListView) findViewById(android.R.id.list);
|
||||
listView.setOnItemClickListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
}
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (categories != null) {
|
||||
createAdapter();
|
||||
} else {
|
||||
loadCategories();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (categories != null) {
|
||||
createAdapter();
|
||||
} else {
|
||||
loadCategories();
|
||||
}
|
||||
}
|
||||
|
||||
private void createAdapter() {
|
||||
if (categories != null) {
|
||||
listAdapter = new ArrayAdapter<String>(this,
|
||||
android.R.layout.simple_list_item_1, categories);
|
||||
txtvStatus.setText(R.string.no_items_label);
|
||||
listView.setAdapter(listAdapter);
|
||||
}
|
||||
}
|
||||
private void createAdapter() {
|
||||
if (categories != null) {
|
||||
listAdapter = new ArrayAdapter<String>(this,
|
||||
android.R.layout.simple_list_item_1, categories);
|
||||
txtvStatus.setText(R.string.no_items_label);
|
||||
listView.setAdapter(listAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches an AsyncTask to load the available categories in the background.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private void loadCategories() {
|
||||
AsyncTask<Void, Void, Void> listLoader = new AsyncTask<Void, Void, Void>() {
|
||||
/**
|
||||
* Launches an AsyncTask to load the available categories in the background.
|
||||
*/
|
||||
@SuppressLint("NewApi")
|
||||
private void loadCategories() {
|
||||
AsyncTask<Void, Void, Void> listLoader = new AsyncTask<Void, Void, Void>() {
|
||||
|
||||
private String[] c;
|
||||
private MiroGuideException exception;
|
||||
private String[] c;
|
||||
private MiroGuideException exception;
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (exception == null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Successfully loaded categories");
|
||||
categories = c;
|
||||
createAdapter();
|
||||
} else {
|
||||
Log.e(TAG, "Error happened while trying to load categories");
|
||||
txtvStatus.setText(exception.getMessage());
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
if (exception == null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Successfully loaded categories");
|
||||
categories = c;
|
||||
createAdapter();
|
||||
} else {
|
||||
Log.e(TAG, "Error happened while trying to load categories");
|
||||
txtvStatus.setText(exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
txtvStatus.setText(R.string.loading_categories_label);
|
||||
}
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
txtvStatus.setText(R.string.loading_categories_label);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
MiroGuideService service = new MiroGuideService();
|
||||
try {
|
||||
c = service.getCategories();
|
||||
} catch (MiroGuideException e) {
|
||||
e.printStackTrace();
|
||||
exception = e;
|
||||
} finally {
|
||||
service.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
MiroGuideService service = new MiroGuideService();
|
||||
try {
|
||||
c = service.getCategories();
|
||||
} catch (MiroGuideException e) {
|
||||
e.printStackTrace();
|
||||
exception = e;
|
||||
} finally {
|
||||
service.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
listLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
listLoader.execute();
|
||||
}
|
||||
}
|
||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
listLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
listLoader.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
|
||||
.setIcon(
|
||||
obtainStyledAttributes(
|
||||
new int[] { R.attr.action_search })
|
||||
.getDrawable(0))
|
||||
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
|
||||
.setIcon(
|
||||
obtainStyledAttributes(
|
||||
new int[]{R.attr.action_search})
|
||||
.getDrawable(0)),
|
||||
MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.search_item:
|
||||
onSearchRequested();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.search_item:
|
||||
onSearchRequested();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
|
||||
|
@ -4,6 +4,7 @@ import android.app.SearchManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.util.Log;
|
||||
|
||||
@ -19,71 +20,71 @@ import de.danoeh.antennapod.preferences.UserPreferences;
|
||||
* uses a MiroGuideChannelListFragment to display the results.
|
||||
*/
|
||||
public class MiroGuideSearchActivity extends ActionBarActivity {
|
||||
private static final String TAG = "MiroGuideSearchActivity";
|
||||
private static final String TAG = "MiroGuideSearchActivity";
|
||||
|
||||
private MiroGuideChannellistFragment listFragment;
|
||||
private MiroGuideChannellistFragment listFragment;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle arg0) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(arg0);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.miroguidesearch);
|
||||
}
|
||||
@Override
|
||||
protected void onCreate(Bundle arg0) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(arg0);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.miroguidesearch);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
Intent intent = getIntent();
|
||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||
String query = intent.getStringExtra(SearchManager.QUERY);
|
||||
getSupportActionBar()
|
||||
.setSubtitle(
|
||||
getString(R.string.search_term_label) + "\""
|
||||
+ query + "\"");
|
||||
handleSearchRequest(query);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
Intent intent = getIntent();
|
||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||
String query = intent.getStringExtra(SearchManager.QUERY);
|
||||
getSupportActionBar()
|
||||
.setSubtitle(
|
||||
getString(R.string.search_term_label) + "\""
|
||||
+ query + "\"");
|
||||
handleSearchRequest(query);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSearchRequest(String query) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Performing search");
|
||||
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
||||
listFragment = MiroGuideChannellistFragment.newInstance("name", query,
|
||||
"name");
|
||||
ft.replace(R.id.channellistFragment, listFragment);
|
||||
ft.commit();
|
||||
}
|
||||
private void handleSearchRequest(String query) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Performing search");
|
||||
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
|
||||
listFragment = MiroGuideChannellistFragment.newInstance("name", query,
|
||||
"name");
|
||||
ft.replace(R.id.channellistFragment, listFragment);
|
||||
ft.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
setIntent(intent);
|
||||
}
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
setIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
|
||||
.setIcon(
|
||||
obtainStyledAttributes(
|
||||
new int[] { R.attr.action_search })
|
||||
.getDrawable(0))
|
||||
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
|
||||
.setIcon(
|
||||
obtainStyledAttributes(
|
||||
new int[]{R.attr.action_search})
|
||||
.getDrawable(0)),
|
||||
MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.search_item:
|
||||
onSearchRequested();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.search_item:
|
||||
onSearchRequested();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,9 +20,10 @@ import android.widget.ProgressBar;
|
||||
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
import de.danoeh.antennapod.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.service.download.DownloadRequest;
|
||||
import de.danoeh.antennapod.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.service.download.Downloader;
|
||||
import de.danoeh.antennapod.service.download.DownloaderCallback;
|
||||
import de.danoeh.antennapod.service.download.HttpDownloader;
|
||||
@ -44,7 +45,7 @@ import de.danoeh.antennapod.util.URLChecker;
|
||||
public abstract class OnlineFeedViewActivity extends ActionBarActivity {
|
||||
private static final String TAG = "OnlineFeedViewActivity";
|
||||
private static final String ARG_FEEDURL = "arg.feedurl";
|
||||
|
||||
|
||||
public static final int RESULT_ERROR = 2;
|
||||
|
||||
private Feed feed;
|
||||
@ -69,7 +70,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
if (downloader != null && downloader.getStatus().isDone() == false) {
|
||||
if (downloader != null && !downloader.isFinished()) {
|
||||
downloader.cancel();
|
||||
}
|
||||
}
|
||||
@ -81,7 +82,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
DownloadStatus status = downloader.getStatus();
|
||||
DownloadStatus status = downloader.getResult();
|
||||
if (status != null) {
|
||||
if (!status.isCancelled()) {
|
||||
if (status.isSuccessful()) {
|
||||
@ -117,10 +118,13 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
|
||||
FileNameGenerator.generateFileName(feed.getDownload_url()))
|
||||
.toString();
|
||||
feed.setFile_url(fileUrl);
|
||||
DownloadStatus status = new DownloadStatus(feed, "OnlineFeed");
|
||||
DownloadRequest request = new DownloadRequest(feed.getFile_url(),
|
||||
feed.getDownload_url(), "OnlineFeed", 0, Feed.FEEDFILETYPE_FEED);
|
||||
/* TODO update
|
||||
HttpDownloader httpDownloader = new HttpDownloader(downloaderCallback,
|
||||
status);
|
||||
request);
|
||||
httpDownloader.start();
|
||||
*/
|
||||
}
|
||||
|
||||
/** Displays a progress indicator. */
|
||||
@ -215,13 +219,14 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity {
|
||||
} else {
|
||||
builder.setMessage(R.string.error_msg_prefix);
|
||||
}
|
||||
builder.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
builder.setNeutralButton(android.R.string.ok,
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
builder.setOnCancelListener(new OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
|
@ -1,31 +1,41 @@
|
||||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.*;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.mobeta.android.dslv.DragSortListView;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
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;
|
||||
import de.danoeh.antennapod.storage.DBReader;
|
||||
import de.danoeh.antennapod.storage.DBTasks;
|
||||
import de.danoeh.antennapod.storage.DBWriter;
|
||||
import de.danoeh.antennapod.util.UndoBarController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OrganizeQueueActivity extends ActionBarActivity implements
|
||||
UndoBarController.UndoListener {
|
||||
private static final String TAG = "OrganizeQueueActivity";
|
||||
|
||||
private static final int MENU_ID_ACCEPT = 2;
|
||||
|
||||
private List<FeedItem> queue;
|
||||
|
||||
private OrganizeAdapter adapter;
|
||||
private UndoBarController undoBarController;
|
||||
|
||||
@ -42,13 +52,37 @@ public class OrganizeQueueActivity extends ActionBarActivity implements
|
||||
listView.setDropListener(dropListener);
|
||||
listView.setRemoveListener(removeListener);
|
||||
|
||||
adapter = new OrganizeAdapter(this);
|
||||
listView.setAdapter(adapter);
|
||||
|
||||
loadData();
|
||||
undoBarController = new UndoBarController(findViewById(R.id.undobar),
|
||||
this);
|
||||
}
|
||||
|
||||
private void loadData() {
|
||||
AsyncTask<Void, Void, List<FeedItem>> loadTask = new AsyncTask<Void, Void, List<FeedItem>>() {
|
||||
|
||||
@Override
|
||||
protected List<FeedItem> doInBackground(Void... voids) {
|
||||
return DBReader.getQueue(OrganizeQueueActivity.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<FeedItem> feedItems) {
|
||||
super.onPostExecute(feedItems);
|
||||
if (feedItems != null) {
|
||||
queue = feedItems;
|
||||
if (adapter == null) {
|
||||
adapter = new OrganizeAdapter(OrganizeQueueActivity.this);
|
||||
listView.setAdapter(adapter);
|
||||
}
|
||||
adapter.notifyDataSetChanged();
|
||||
} else {
|
||||
Log.e(TAG, "Queue was null");
|
||||
}
|
||||
}
|
||||
};
|
||||
loadTask.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
@ -58,8 +92,7 @@ public class OrganizeQueueActivity extends ActionBarActivity implements
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
FeedManager.getInstance().autodownloadUndownloadedItems(
|
||||
getApplicationContext());
|
||||
DBTasks.autodownloadUndownloadedItems(getApplicationContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -73,9 +106,7 @@ public class OrganizeQueueActivity extends ActionBarActivity implements
|
||||
@Override
|
||||
public void update(EventDistributor eventDistributor, Integer arg) {
|
||||
if (((EventDistributor.QUEUE_UPDATE | EventDistributor.FEED_LIST_UPDATE) & arg) != 0) {
|
||||
if (adapter != null) {
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
loadData();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -84,9 +115,10 @@ public class OrganizeQueueActivity extends ActionBarActivity implements
|
||||
|
||||
@Override
|
||||
public void drop(int from, int to) {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
manager.moveQueueItem(OrganizeQueueActivity.this, from, to, false);
|
||||
adapter.notifyDataSetChanged();
|
||||
final FeedItem item = queue.remove(from);
|
||||
queue.add(to, item);
|
||||
adapter.notifyDataSetChanged();
|
||||
DBWriter.moveQueueItem(OrganizeQueueActivity.this, from, to, true);
|
||||
}
|
||||
};
|
||||
|
||||
@ -94,9 +126,8 @@ public class OrganizeQueueActivity extends ActionBarActivity implements
|
||||
|
||||
@Override
|
||||
public void remove(int which) {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
FeedItem item = (FeedItem) listView.getAdapter().getItem(which);
|
||||
manager.removeQueueItem(OrganizeQueueActivity.this, item, false);
|
||||
DBWriter.removeQueueItem(OrganizeQueueActivity.this, item.getId(), true);
|
||||
undoBarController.showUndoBar(false,
|
||||
getString(R.string.removed_from_queue), new UndoToken(item,
|
||||
which));
|
||||
@ -124,22 +155,18 @@ public class OrganizeQueueActivity extends ActionBarActivity implements
|
||||
public void onUndo(Parcelable token) {
|
||||
// Perform the undo
|
||||
UndoToken undoToken = (UndoToken) token;
|
||||
FeedItem feedItem = undoToken.getFeedItem();
|
||||
long itemId = undoToken.getFeedItemId();
|
||||
int position = undoToken.getPosition();
|
||||
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
manager.addQueueItemAt(OrganizeQueueActivity.this, feedItem, position,
|
||||
false);
|
||||
DBWriter.addQueueItemAt(OrganizeQueueActivity.this, itemId, position, false);
|
||||
}
|
||||
|
||||
private static class OrganizeAdapter extends BaseAdapter {
|
||||
|
||||
private Context context;
|
||||
private FeedManager manager = FeedManager.getInstance();
|
||||
private OrganizeQueueActivity organizeQueueActivity;
|
||||
|
||||
public OrganizeAdapter(Context context) {
|
||||
public OrganizeAdapter(OrganizeQueueActivity organizeQueueActivity) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.organizeQueueActivity = organizeQueueActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -149,7 +176,7 @@ public class OrganizeQueueActivity extends ActionBarActivity implements
|
||||
|
||||
if (convertView == null) {
|
||||
holder = new Holder();
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
LayoutInflater inflater = (LayoutInflater) organizeQueueActivity
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
convertView = inflater.inflate(
|
||||
R.layout.organize_queue_listitem, null);
|
||||
@ -186,13 +213,20 @@ public class OrganizeQueueActivity extends ActionBarActivity implements
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
int queueSize = manager.getQueueSize(true);
|
||||
return queueSize;
|
||||
if (organizeQueueActivity.queue != null) {
|
||||
return organizeQueueActivity.queue.size();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeedItem getItem(int position) {
|
||||
return manager.getQueueItemAtIndex(position, true);
|
||||
if (organizeQueueActivity.queue != null) {
|
||||
return organizeQueueActivity.queue.get(position);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -208,7 +242,6 @@ public class OrganizeQueueActivity extends ActionBarActivity implements
|
||||
private int position;
|
||||
|
||||
public UndoToken(FeedItem item, int position) {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
this.itemId = item.getId();
|
||||
this.feedId = item.getFeed().getId();
|
||||
this.position = position;
|
||||
@ -240,9 +273,8 @@ public class OrganizeQueueActivity extends ActionBarActivity implements
|
||||
out.writeInt(position);
|
||||
}
|
||||
|
||||
public FeedItem getFeedItem() {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
return manager.getFeedItem(itemId, feedId);
|
||||
public long getFeedItemId() {
|
||||
return itemId;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
|
@ -11,9 +11,9 @@ import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.fragment.PlaybackHistoryFragment;
|
||||
import de.danoeh.antennapod.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.storage.DBWriter;
|
||||
|
||||
public class PlaybackHistoryActivity extends ActionBarActivity {
|
||||
private static final String TAG = "PlaybackHistoryActivity";
|
||||
@ -36,7 +36,7 @@ public class PlaybackHistoryActivity extends ActionBarActivity {
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.clear_history_item:
|
||||
FeedManager.getInstance().clearPlaybackHistory(this);
|
||||
DBWriter.clearPlaybackHistory(this);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
|
@ -25,29 +25,30 @@ import de.danoeh.antennapod.AppConfig;
|
||||
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 */
|
||||
/**
|
||||
* The main preference activity
|
||||
*/
|
||||
public class PreferenceActivity extends android.preference.PreferenceActivity {
|
||||
private static final String TAG = "PreferenceActivity";
|
||||
private static final String TAG = "PreferenceActivity";
|
||||
|
||||
private static final String PREF_FLATTR_THIS_APP = "prefFlattrThisApp";
|
||||
private static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate";
|
||||
private static final String PREF_FLATTR_REVOKE = "prefRevokeAccess";
|
||||
private static final String PREF_OPML_EXPORT = "prefOpmlExport";
|
||||
private static final String PREF_ABOUT = "prefAbout";
|
||||
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
|
||||
private static final String AUTO_DL_PREF_SCREEN = "prefAutoDownloadSettings";
|
||||
private static final String PREF_FLATTR_THIS_APP = "prefFlattrThisApp";
|
||||
private static final String PREF_FLATTR_AUTH = "pref_flattr_authenticate";
|
||||
private static final String PREF_FLATTR_REVOKE = "prefRevokeAccess";
|
||||
private static final String PREF_OPML_EXPORT = "prefOpmlExport";
|
||||
private static final String PREF_ABOUT = "prefAbout";
|
||||
private static final String PREF_CHOOSE_DATA_DIR = "prefChooseDataDir";
|
||||
private static final String AUTO_DL_PREF_SCREEN = "prefAutoDownloadSettings";
|
||||
|
||||
private CheckBoxPreference[] selectedNetworks;
|
||||
private CheckBoxPreference[] selectedNetworks;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
@ -57,332 +58,319 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
|
||||
findPreference(PREF_FLATTR_THIS_APP).setOnPreferenceClickListener(
|
||||
new OnPreferenceClickListener() {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
new FlattrClickWorker(PreferenceActivity.this,
|
||||
FlattrUtils.APP_URL).executeAsync();
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
new FlattrClickWorker(PreferenceActivity.this,
|
||||
FlattrUtils.APP_URL).executeAsync();
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
findPreference(PREF_FLATTR_REVOKE).setOnPreferenceClickListener(
|
||||
new OnPreferenceClickListener() {
|
||||
findPreference(PREF_FLATTR_REVOKE).setOnPreferenceClickListener(
|
||||
new OnPreferenceClickListener() {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
FlattrUtils.revokeAccessToken(PreferenceActivity.this);
|
||||
checkItemVisibility();
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
FlattrUtils.revokeAccessToken(PreferenceActivity.this);
|
||||
checkItemVisibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
findPreference(PREF_ABOUT).setOnPreferenceClickListener(
|
||||
new OnPreferenceClickListener() {
|
||||
findPreference(PREF_ABOUT).setOnPreferenceClickListener(
|
||||
new OnPreferenceClickListener() {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
PreferenceActivity.this.startActivity(new Intent(
|
||||
PreferenceActivity.this, AboutActivity.class));
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
PreferenceActivity.this.startActivity(new Intent(
|
||||
PreferenceActivity.this, AboutActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
findPreference(PREF_OPML_EXPORT).setOnPreferenceClickListener(
|
||||
new OnPreferenceClickListener() {
|
||||
findPreference(PREF_OPML_EXPORT).setOnPreferenceClickListener(
|
||||
new OnPreferenceClickListener() {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (FeedManager.getInstance().getFeedsSize() > 0) {
|
||||
new OpmlExportWorker(PreferenceActivity.this)
|
||||
.executeAsync();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
new OpmlExportWorker(PreferenceActivity.this)
|
||||
.executeAsync();
|
||||
|
||||
findPreference(PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
|
||||
new OnPreferenceClickListener() {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
startActivityForResult(
|
||||
new Intent(PreferenceActivity.this,
|
||||
DirectoryChooserActivity.class),
|
||||
DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
findPreference(UserPreferences.PREF_THEME)
|
||||
.setOnPreferenceChangeListener(
|
||||
new OnPreferenceChangeListener() {
|
||||
findPreference(PREF_CHOOSE_DATA_DIR).setOnPreferenceClickListener(
|
||||
new OnPreferenceClickListener() {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(
|
||||
Preference preference, Object newValue) {
|
||||
Intent i = getIntent();
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
| Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
finish();
|
||||
startActivity(i);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
|
||||
.setOnPreferenceChangeListener(
|
||||
new OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
startActivityForResult(
|
||||
new Intent(PreferenceActivity.this,
|
||||
DirectoryChooserActivity.class),
|
||||
DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
findPreference(UserPreferences.PREF_THEME)
|
||||
.setOnPreferenceChangeListener(
|
||||
new OnPreferenceChangeListener() {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(
|
||||
Preference preference, Object newValue) {
|
||||
if (newValue instanceof Boolean) {
|
||||
setSelectedNetworksEnabled((Boolean) newValue);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE)
|
||||
.setOnPreferenceChangeListener(
|
||||
new OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(
|
||||
Preference preference, Object newValue) {
|
||||
Intent i = getIntent();
|
||||
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
| Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
finish();
|
||||
startActivity(i);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
|
||||
.setOnPreferenceChangeListener(
|
||||
new OnPreferenceChangeListener() {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(
|
||||
Preference preference, Object newValue) {
|
||||
if (newValue instanceof String) {
|
||||
setEpisodeCacheSizeText(Integer
|
||||
.valueOf((String) newValue));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
findPreference(UserPreferences.PREF_ENABLE_AUTODL)
|
||||
.setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(
|
||||
Preference preference, Object newValue) {
|
||||
if (newValue instanceof Boolean) {
|
||||
setSelectedNetworksEnabled((Boolean) newValue);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE)
|
||||
.setOnPreferenceChangeListener(
|
||||
new OnPreferenceChangeListener() {
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
checkItemVisibility();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
buildUpdateIntervalPreference();
|
||||
buildAutodownloadSelectedNetworsPreference();
|
||||
setSelectedNetworksEnabled(UserPreferences
|
||||
.isEnableAutodownloadWifiFilter());
|
||||
|
||||
}
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||
checkItemVisibility();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
buildUpdateIntervalPreference();
|
||||
buildAutodownloadSelectedNetworsPreference();
|
||||
setSelectedNetworksEnabled(UserPreferences
|
||||
.isEnableAutodownloadWifiFilter());
|
||||
|
||||
private void buildUpdateIntervalPreference() {
|
||||
ListPreference pref = (ListPreference) findPreference(UserPreferences.PREF_UPDATE_INTERVAL);
|
||||
String[] values = getResources().getStringArray(
|
||||
R.array.update_intervall_values);
|
||||
String[] entries = new String[values.length];
|
||||
for (int x = 0; x < values.length; x++) {
|
||||
Integer v = Integer.parseInt(values[x]);
|
||||
switch (v) {
|
||||
case 0:
|
||||
entries[x] = getString(R.string.pref_update_interval_hours_manual);
|
||||
break;
|
||||
case 1:
|
||||
entries[x] = v
|
||||
+ " "
|
||||
+ getString(R.string.pref_update_interval_hours_singular);
|
||||
break;
|
||||
default:
|
||||
entries[x] = v + " "
|
||||
+ getString(R.string.pref_update_interval_hours_plural);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
pref.setEntries(entries);
|
||||
private void buildUpdateIntervalPreference() {
|
||||
ListPreference pref = (ListPreference) findPreference(UserPreferences.PREF_UPDATE_INTERVAL);
|
||||
String[] values = getResources().getStringArray(
|
||||
R.array.update_intervall_values);
|
||||
String[] entries = new String[values.length];
|
||||
for (int x = 0; x < values.length; x++) {
|
||||
Integer v = Integer.parseInt(values[x]);
|
||||
switch (v) {
|
||||
case 0:
|
||||
entries[x] = getString(R.string.pref_update_interval_hours_manual);
|
||||
break;
|
||||
case 1:
|
||||
entries[x] = v
|
||||
+ " "
|
||||
+ getString(R.string.pref_update_interval_hours_singular);
|
||||
break;
|
||||
default:
|
||||
entries[x] = v + " "
|
||||
+ getString(R.string.pref_update_interval_hours_plural);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
pref.setEntries(entries);
|
||||
|
||||
private void setSelectedNetworksEnabled(boolean b) {
|
||||
if (selectedNetworks != null) {
|
||||
for (Preference p : selectedNetworks) {
|
||||
p.setEnabled(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
checkItemVisibility();
|
||||
setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize());
|
||||
setDataFolderText();
|
||||
}
|
||||
private void setSelectedNetworksEnabled(boolean b) {
|
||||
if (selectedNetworks != null) {
|
||||
for (Preference p : selectedNetworks) {
|
||||
p.setEnabled(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void checkItemVisibility() {
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
checkItemVisibility();
|
||||
setEpisodeCacheSizeText(UserPreferences.getEpisodeCacheSize());
|
||||
setDataFolderText();
|
||||
}
|
||||
|
||||
boolean hasFlattrToken = FlattrUtils.hasToken();
|
||||
@SuppressWarnings("deprecation")
|
||||
private void checkItemVisibility() {
|
||||
|
||||
findPreference(PREF_FLATTR_AUTH).setEnabled(!hasFlattrToken);
|
||||
findPreference(PREF_FLATTR_REVOKE).setEnabled(hasFlattrToken);
|
||||
boolean hasFlattrToken = FlattrUtils.hasToken();
|
||||
|
||||
findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
|
||||
.setEnabled(UserPreferences.isEnableAutodownload());
|
||||
setSelectedNetworksEnabled(UserPreferences.isEnableAutodownload()
|
||||
&& UserPreferences.isEnableAutodownloadWifiFilter());
|
||||
findPreference(PREF_FLATTR_AUTH).setEnabled(!hasFlattrToken);
|
||||
findPreference(PREF_FLATTR_REVOKE).setEnabled(hasFlattrToken);
|
||||
|
||||
}
|
||||
findPreference(UserPreferences.PREF_ENABLE_AUTODL_WIFI_FILTER)
|
||||
.setEnabled(UserPreferences.isEnableAutodownload());
|
||||
setSelectedNetworksEnabled(UserPreferences.isEnableAutodownload()
|
||||
&& UserPreferences.isEnableAutodownloadWifiFilter());
|
||||
|
||||
private void setEpisodeCacheSizeText(int cacheSize) {
|
||||
String s;
|
||||
if (cacheSize == getResources().getInteger(
|
||||
R.integer.episode_cache_size_unlimited)) {
|
||||
s = getString(R.string.pref_episode_cache_unlimited);
|
||||
} else {
|
||||
s = Integer.toString(cacheSize)
|
||||
+ getString(R.string.episodes_suffix);
|
||||
}
|
||||
findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setSummary(s);
|
||||
}
|
||||
}
|
||||
|
||||
private void setDataFolderText() {
|
||||
File f = UserPreferences.getDataFolder(this, null);
|
||||
if (f != null) {
|
||||
findPreference(PREF_CHOOSE_DATA_DIR)
|
||||
.setSummary(f.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
private void setEpisodeCacheSizeText(int cacheSize) {
|
||||
String s;
|
||||
if (cacheSize == getResources().getInteger(
|
||||
R.integer.episode_cache_size_unlimited)) {
|
||||
s = getString(R.string.pref_episode_cache_unlimited);
|
||||
} else {
|
||||
s = Integer.toString(cacheSize)
|
||||
+ getString(R.string.episodes_suffix);
|
||||
}
|
||||
findPreference(UserPreferences.PREF_EPISODE_CACHE_SIZE).setSummary(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
private void setDataFolderText() {
|
||||
File f = UserPreferences.getDataFolder(this, null);
|
||||
if (f != null) {
|
||||
findPreference(PREF_CHOOSE_DATA_DIR)
|
||||
.setSummary(f.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(intent);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
|
||||
theme.applyStyle(UserPreferences.getTheme(), true);
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(intent);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
|
||||
String dir = data
|
||||
.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Setting data folder");
|
||||
UserPreferences.setDataFolder(dir);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onApplyThemeResource(Theme theme, int resid, boolean first) {
|
||||
theme.applyStyle(UserPreferences.getTheme(), true);
|
||||
}
|
||||
|
||||
private void buildAutodownloadSelectedNetworsPreference() {
|
||||
if (selectedNetworks != null) {
|
||||
clearAutodownloadSelectedNetworsPreference();
|
||||
}
|
||||
// get configured networks
|
||||
WifiManager wifiservice = (WifiManager) getSystemService(Context.WIFI_SERVICE);
|
||||
List<WifiConfiguration> networks = wifiservice.getConfiguredNetworks();
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) {
|
||||
String dir = data
|
||||
.getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Setting data folder");
|
||||
UserPreferences.setDataFolder(dir);
|
||||
}
|
||||
}
|
||||
|
||||
if (networks != null) {
|
||||
selectedNetworks = new CheckBoxPreference[networks.size()];
|
||||
List<String> prefValues = Arrays.asList(UserPreferences
|
||||
.getAutodownloadSelectedNetworks());
|
||||
PreferenceScreen prefScreen = (PreferenceScreen) findPreference(AUTO_DL_PREF_SCREEN);
|
||||
OnPreferenceClickListener clickListener = new OnPreferenceClickListener() {
|
||||
private void buildAutodownloadSelectedNetworsPreference() {
|
||||
if (selectedNetworks != null) {
|
||||
clearAutodownloadSelectedNetworsPreference();
|
||||
}
|
||||
// get configured networks
|
||||
WifiManager wifiservice = (WifiManager) getSystemService(Context.WIFI_SERVICE);
|
||||
List<WifiConfiguration> networks = wifiservice.getConfiguredNetworks();
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (preference instanceof CheckBoxPreference) {
|
||||
String key = preference.getKey();
|
||||
ArrayList<String> prefValuesList = new ArrayList<String>(
|
||||
Arrays.asList(UserPreferences
|
||||
.getAutodownloadSelectedNetworks()));
|
||||
boolean newValue = ((CheckBoxPreference) preference)
|
||||
.isChecked();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Selected network " + key
|
||||
+ ". New state: " + newValue);
|
||||
if (networks != null) {
|
||||
selectedNetworks = new CheckBoxPreference[networks.size()];
|
||||
List<String> prefValues = Arrays.asList(UserPreferences
|
||||
.getAutodownloadSelectedNetworks());
|
||||
PreferenceScreen prefScreen = (PreferenceScreen) findPreference(AUTO_DL_PREF_SCREEN);
|
||||
OnPreferenceClickListener clickListener = new OnPreferenceClickListener() {
|
||||
|
||||
int index = prefValuesList.indexOf(key);
|
||||
if (index >= 0 && newValue == false) {
|
||||
// remove network
|
||||
prefValuesList.remove(index);
|
||||
} else if (index < 0 && newValue == true) {
|
||||
prefValuesList.add(key);
|
||||
}
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (preference instanceof CheckBoxPreference) {
|
||||
String key = preference.getKey();
|
||||
ArrayList<String> prefValuesList = new ArrayList<String>(
|
||||
Arrays.asList(UserPreferences
|
||||
.getAutodownloadSelectedNetworks()));
|
||||
boolean newValue = ((CheckBoxPreference) preference)
|
||||
.isChecked();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Selected network " + key
|
||||
+ ". New state: " + newValue);
|
||||
|
||||
UserPreferences.setAutodownloadSelectedNetworks(
|
||||
PreferenceActivity.this, prefValuesList
|
||||
.toArray(new String[prefValuesList
|
||||
.size()]));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
// create preference for each known network. attach listener and set
|
||||
// value
|
||||
for (int i = 0; i < networks.size(); i++) {
|
||||
WifiConfiguration config = networks.get(i);
|
||||
int index = prefValuesList.indexOf(key);
|
||||
if (index >= 0 && newValue == false) {
|
||||
// remove network
|
||||
prefValuesList.remove(index);
|
||||
} else if (index < 0 && newValue == true) {
|
||||
prefValuesList.add(key);
|
||||
}
|
||||
|
||||
CheckBoxPreference pref = new CheckBoxPreference(this);
|
||||
String key = Integer.toString(config.networkId);
|
||||
pref.setTitle(config.SSID);
|
||||
pref.setKey(key);
|
||||
pref.setOnPreferenceClickListener(clickListener);
|
||||
pref.setPersistent(false);
|
||||
pref.setChecked(prefValues.contains(key));
|
||||
selectedNetworks[i] = pref;
|
||||
prefScreen.addPreference(pref);
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Couldn't get list of configure Wi-Fi networks");
|
||||
}
|
||||
}
|
||||
UserPreferences.setAutodownloadSelectedNetworks(
|
||||
PreferenceActivity.this, prefValuesList
|
||||
.toArray(new String[prefValuesList
|
||||
.size()]));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
// create preference for each known network. attach listener and set
|
||||
// value
|
||||
for (int i = 0; i < networks.size(); i++) {
|
||||
WifiConfiguration config = networks.get(i);
|
||||
|
||||
private void clearAutodownloadSelectedNetworsPreference() {
|
||||
if (selectedNetworks != null) {
|
||||
PreferenceScreen prefScreen = (PreferenceScreen) findPreference(AUTO_DL_PREF_SCREEN);
|
||||
CheckBoxPreference pref = new CheckBoxPreference(this);
|
||||
String key = Integer.toString(config.networkId);
|
||||
pref.setTitle(config.SSID);
|
||||
pref.setKey(key);
|
||||
pref.setOnPreferenceClickListener(clickListener);
|
||||
pref.setPersistent(false);
|
||||
pref.setChecked(prefValues.contains(key));
|
||||
selectedNetworks[i] = pref;
|
||||
prefScreen.addPreference(pref);
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Couldn't get list of configure Wi-Fi networks");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < selectedNetworks.length; i++) {
|
||||
if (selectedNetworks[i] != null) {
|
||||
prefScreen.removePreference(selectedNetworks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private void clearAutodownloadSelectedNetworsPreference() {
|
||||
if (selectedNetworks != null) {
|
||||
PreferenceScreen prefScreen = (PreferenceScreen) findPreference(AUTO_DL_PREF_SCREEN);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
|
||||
Preference preference) {
|
||||
super.onPreferenceTreeClick(preferenceScreen, preference);
|
||||
if (preference != null)
|
||||
if (preference instanceof PreferenceScreen)
|
||||
if (((PreferenceScreen) preference).getDialog() != null)
|
||||
((PreferenceScreen) preference)
|
||||
.getDialog()
|
||||
.getWindow()
|
||||
.getDecorView()
|
||||
.setBackgroundDrawable(
|
||||
this.getWindow().getDecorView()
|
||||
.getBackground().getConstantState()
|
||||
.newDrawable());
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < selectedNetworks.length; i++) {
|
||||
if (selectedNetworks[i] != null) {
|
||||
prefScreen.removePreference(selectedNetworks[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
|
||||
Preference preference) {
|
||||
super.onPreferenceTreeClick(preferenceScreen, preference);
|
||||
if (preference != null)
|
||||
if (preference instanceof PreferenceScreen)
|
||||
if (((PreferenceScreen) preference).getDialog() != null)
|
||||
((PreferenceScreen) preference)
|
||||
.getDialog()
|
||||
.getWindow()
|
||||
.getDecorView()
|
||||
.setBackgroundDrawable(
|
||||
this.getWindow().getDecorView()
|
||||
.getBackground().getConstantState()
|
||||
.newDrawable());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
package de.danoeh.antennapod.activity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.SearchManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
@ -20,150 +21,152 @@ import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.adapter.SearchlistAdapter;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
import de.danoeh.antennapod.feed.FeedItem;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.feed.FeedSearcher;
|
||||
import de.danoeh.antennapod.storage.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 ActionBarActivity implements AdapterView.OnItemClickListener{
|
||||
private static final String TAG = "SearchActivity";
|
||||
/**
|
||||
* Displays the results when the user searches for FeedItems or Feeds.
|
||||
*/
|
||||
public class SearchActivity extends ActionBarActivity implements AdapterView.OnItemClickListener {
|
||||
private static final String TAG = "SearchActivity";
|
||||
|
||||
public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.searchactivity.extra.feedId";
|
||||
public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.searchactivity.extra.feedId";
|
||||
|
||||
private SearchlistAdapter searchAdapter;
|
||||
private ArrayList<SearchResult> content;
|
||||
private SearchlistAdapter searchAdapter;
|
||||
private List<SearchResult> content;
|
||||
|
||||
/** Feed that is being searched or null if the search is global. */
|
||||
private Feed selectedFeed;
|
||||
/**
|
||||
* ID of the feed that is being searched or null if the search is global.
|
||||
*/
|
||||
private long feedID;
|
||||
|
||||
private ListView listView;
|
||||
private TextView txtvStatus;
|
||||
private TextView txtvStatus;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(UserPreferences.getTheme());
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.searchlist);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setContentView(R.layout.searchlist);
|
||||
listView = (ListView) findViewById(android.R.id.list);
|
||||
txtvStatus = (TextView) findViewById(android.R.id.empty);
|
||||
txtvStatus = (TextView) findViewById(android.R.id.empty);
|
||||
|
||||
listView.setOnItemClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
setIntent(intent);
|
||||
}
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
setIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
Intent intent = getIntent();
|
||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||
Bundle extra = intent.getBundleExtra(SearchManager.APP_DATA);
|
||||
if (extra != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Found bundle extra");
|
||||
long feedId = extra.getLong(EXTRA_FEED_ID);
|
||||
selectedFeed = FeedManager.getInstance().getFeed(feedId);
|
||||
}
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Starting search");
|
||||
String query = intent.getStringExtra(SearchManager.QUERY);
|
||||
getSupportActionBar()
|
||||
.setSubtitle(
|
||||
getString(R.string.search_term_label) + "\""
|
||||
+ query + "\"");
|
||||
handleSearchRequest(query);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
Intent intent = getIntent();
|
||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||
Bundle extra = intent.getBundleExtra(SearchManager.APP_DATA);
|
||||
if (extra != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Found bundle extra");
|
||||
feedID = extra.getLong(EXTRA_FEED_ID);
|
||||
}
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Starting search");
|
||||
String query = intent.getStringExtra(SearchManager.QUERY);
|
||||
getSupportActionBar()
|
||||
.setSubtitle(
|
||||
getString(R.string.search_term_label) + "\""
|
||||
+ query + "\"");
|
||||
handleSearchRequest(query);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
|
||||
.setIcon(
|
||||
obtainStyledAttributes(
|
||||
new int[] { R.attr.action_search })
|
||||
.getDrawable(0))
|
||||
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuItemCompat.setShowAsAction(menu.add(Menu.NONE, R.id.search_item, Menu.NONE, R.string.search_label)
|
||||
.setIcon(
|
||||
obtainStyledAttributes(
|
||||
new int[]{R.attr.action_search})
|
||||
.getDrawable(0)),
|
||||
(MenuItem.SHOW_AS_ACTION_IF_ROOM));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.search_item:
|
||||
onSearchRequested();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
case R.id.search_item:
|
||||
onSearchRequested();
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSearchRequested() {
|
||||
Bundle extra = null;
|
||||
if (selectedFeed != null) {
|
||||
extra = new Bundle();
|
||||
extra.putLong(EXTRA_FEED_ID, selectedFeed.getId());
|
||||
}
|
||||
startSearch(null, false, extra, false);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onSearchRequested() {
|
||||
Bundle extra = null;
|
||||
if (feedID != 0) {
|
||||
extra = new Bundle();
|
||||
extra.putLong(EXTRA_FEED_ID, feedID);
|
||||
}
|
||||
startSearch(null, false, extra, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressLint({ "NewApi", "NewApi" })
|
||||
private void handleSearchRequest(final String query) {
|
||||
if (searchAdapter != null) {
|
||||
searchAdapter.clear();
|
||||
searchAdapter.notifyDataSetChanged();
|
||||
}
|
||||
txtvStatus.setText(R.string.search_status_searching);
|
||||
@SuppressLint({"NewApi", "NewApi"})
|
||||
private void handleSearchRequest(final String query) {
|
||||
if (searchAdapter != null) {
|
||||
searchAdapter.clear();
|
||||
searchAdapter.notifyDataSetChanged();
|
||||
}
|
||||
txtvStatus.setText(R.string.search_status_searching);
|
||||
|
||||
Thread thread = new Thread() {
|
||||
Thread thread = new Thread() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "Starting background work");
|
||||
final ArrayList<SearchResult> result = FeedSearcher
|
||||
.performSearch(SearchActivity.this, query, selectedFeed);
|
||||
if (SearchActivity.this != null) {
|
||||
SearchActivity.this.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "Starting background work");
|
||||
final List<SearchResult> result = FeedSearcher
|
||||
.performSearch(SearchActivity.this, query, feedID);
|
||||
if (SearchActivity.this != null) {
|
||||
SearchActivity.this.runOnUiThread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Background work finished");
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Found " + result.size()
|
||||
+ " results");
|
||||
content = result;
|
||||
@Override
|
||||
public void run() {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Background work finished");
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Found " + result.size()
|
||||
+ " results");
|
||||
content = result;
|
||||
|
||||
searchAdapter = new SearchlistAdapter(
|
||||
SearchActivity.this, 0, content);
|
||||
listView.setAdapter(searchAdapter);
|
||||
searchAdapter.notifyDataSetChanged();
|
||||
if (content.isEmpty()) {
|
||||
txtvStatus
|
||||
.setText(R.string.search_status_no_results);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
thread.start();
|
||||
searchAdapter = new SearchlistAdapter(
|
||||
SearchActivity.this, 0, content);
|
||||
listView.setAdapter(searchAdapter);
|
||||
searchAdapter.notifyDataSetChanged();
|
||||
if (content.isEmpty()) {
|
||||
txtvStatus
|
||||
.setText(R.string.search_status_no_results);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
thread.start();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
|
||||
|
@ -8,21 +8,22 @@ import android.view.ViewGroup;
|
||||
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.FeedImage;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.util.DownloadError;
|
||||
|
||||
/** Displays a list of DownloadStatus entries. */
|
||||
public class DownloadLogAdapter extends BaseAdapter {
|
||||
|
||||
private Context context;
|
||||
private FeedManager manager = FeedManager.getInstance();
|
||||
|
||||
public DownloadLogAdapter(Context context) {
|
||||
private ItemAccess itemAccess;
|
||||
|
||||
public DownloadLogAdapter(Context context, ItemAccess itemAccess) {
|
||||
super();
|
||||
this.itemAccess = itemAccess;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@ -91,12 +92,12 @@ public class DownloadLogAdapter extends BaseAdapter {
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return manager.getDownloadLogSize();
|
||||
return itemAccess.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadStatus getItem(int position) {
|
||||
return manager.getDownloadStatusFromLogAtIndex(position);
|
||||
return itemAccess.getItem(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -104,4 +105,9 @@ public class DownloadLogAdapter extends BaseAdapter {
|
||||
return position;
|
||||
}
|
||||
|
||||
public static interface ItemAccess {
|
||||
public int getCount();
|
||||
public DownloadStatus getItem(int position);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,11 +10,12 @@ import android.widget.ArrayAdapter;
|
||||
import android.widget.ProgressBar;
|
||||
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.FeedMedia;
|
||||
import de.danoeh.antennapod.service.download.DownloadRequest;
|
||||
import de.danoeh.antennapod.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.service.download.Downloader;
|
||||
import de.danoeh.antennapod.util.Converter;
|
||||
import de.danoeh.antennapod.util.ThemeUtils;
|
||||
@ -33,8 +34,7 @@ public class DownloadlistAdapter extends ArrayAdapter<Downloader> {
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
Holder holder;
|
||||
DownloadStatus status = getItem(position).getStatus();
|
||||
FeedFile feedFile = status.getFeedFile();
|
||||
DownloadRequest request = getItem(position).getDownloadRequest();
|
||||
// Inflate layout
|
||||
if (convertView == null) {
|
||||
holder = new Holder();
|
||||
@ -62,31 +62,16 @@ public class DownloadlistAdapter extends ArrayAdapter<Downloader> {
|
||||
} else {
|
||||
convertView.setBackgroundResource(0);
|
||||
}
|
||||
|
||||
String titleText = null;
|
||||
if (feedFile.getClass() == FeedMedia.class) {
|
||||
titleText = ((FeedMedia) feedFile).getItem().getTitle();
|
||||
} else if (feedFile.getClass() == Feed.class) {
|
||||
titleText = ((Feed) feedFile).getTitle();
|
||||
} else if (feedFile.getClass() == FeedImage.class) {
|
||||
FeedImage image = (FeedImage) feedFile;
|
||||
if (image.getFeed() != null) {
|
||||
titleText = convertView.getResources().getString(
|
||||
R.string.image_of_prefix)
|
||||
+ image.getFeed().getTitle();
|
||||
} else {
|
||||
titleText = ((FeedImage) feedFile).getTitle();
|
||||
}
|
||||
|
||||
holder.title.setText(request.getTitle());
|
||||
if (request.getStatusMsg() != 0) {
|
||||
holder.message.setText(request.getStatusMsg());
|
||||
}
|
||||
holder.title.setText(titleText);
|
||||
if (status.getStatusMsg() != 0) {
|
||||
holder.message.setText(status.getStatusMsg());
|
||||
}
|
||||
String strDownloaded = Converter.byteToString(status.getSoFar());
|
||||
if (status.getSize() != DownloadStatus.SIZE_UNKNOWN) {
|
||||
strDownloaded += " / " + Converter.byteToString(status.getSize());
|
||||
holder.percent.setText(status.getProgressPercent() + "%");
|
||||
holder.progbar.setProgress(status.getProgressPercent());
|
||||
String strDownloaded = Converter.byteToString(request.getSoFar());
|
||||
if (request.getSize() != DownloadStatus.SIZE_UNKNOWN) {
|
||||
strDownloaded += " / " + Converter.byteToString(request.getSize());
|
||||
holder.percent.setText(request.getProgressPercent() + "%");
|
||||
holder.progbar.setProgress(request.getProgressPercent());
|
||||
holder.percent.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.progbar.setProgress(0);
|
||||
|
@ -14,7 +14,6 @@ import android.widget.TextView;
|
||||
import de.danoeh.antennapod.R;
|
||||
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;
|
||||
@ -30,17 +29,18 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
|
||||
public static final int GROUP_POS_UNREAD = 1;
|
||||
|
||||
private Context context;
|
||||
private FeedManager manager = FeedManager.getInstance();
|
||||
private ItemAccess itemAccess;
|
||||
|
||||
private ActionButtonCallback feedItemActionCallback;
|
||||
private OnGroupActionClicked groupActionCallback;
|
||||
|
||||
public ExternalEpisodesListAdapter(Context context,
|
||||
ActionButtonCallback callback,
|
||||
OnGroupActionClicked groupActionCallback) {
|
||||
OnGroupActionClicked groupActionCallback,
|
||||
ItemAccess itemAccess) {
|
||||
super();
|
||||
this.context = context;
|
||||
|
||||
this.itemAccess = itemAccess;
|
||||
this.feedItemActionCallback = callback;
|
||||
this.groupActionCallback = groupActionCallback;
|
||||
}
|
||||
@ -53,10 +53,10 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
|
||||
@Override
|
||||
public FeedItem getChild(int groupPosition, int childPosition) {
|
||||
if (groupPosition == GROUP_POS_QUEUE) {
|
||||
return manager.getQueueItemAtIndex(childPosition, true);
|
||||
return itemAccess.getQueueItemAt(childPosition);
|
||||
} else if (groupPosition == GROUP_POS_UNREAD) {
|
||||
return manager.getUnreadItemAtIndex(childPosition, true);
|
||||
}
|
||||
return itemAccess.getUnreadItemAt(childPosition);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -200,9 +200,9 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
|
||||
@Override
|
||||
public int getChildrenCount(int groupPosition) {
|
||||
if (groupPosition == GROUP_POS_QUEUE) {
|
||||
return manager.getQueueSize(true);
|
||||
return itemAccess.getQueueSize();
|
||||
} else if (groupPosition == GROUP_POS_UNREAD) {
|
||||
return manager.getUnreadItemsSize(true);
|
||||
return itemAccess.getUnreadItemsSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -210,7 +210,7 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
// Hide 'unread items' group if empty
|
||||
if (manager.getUnreadItemsSize(true) > 0) {
|
||||
if (itemAccess.getUnreadItemsSize() > 0) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
@ -264,8 +264,8 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return manager.getUnreadItemsSize(true) == 0
|
||||
&& manager.getQueueSize(true) == 0;
|
||||
return itemAccess.getUnreadItemsSize() == 0
|
||||
&& itemAccess.getQueueSize() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -287,4 +287,11 @@ public class ExternalEpisodesListAdapter extends BaseExpandableListAdapter {
|
||||
public void onClick(long groupId);
|
||||
}
|
||||
|
||||
public static interface ItemAccess {
|
||||
public int getQueueSize();
|
||||
public int getUnreadItemsSize();
|
||||
public FeedItem getQueueItemAt(int position);
|
||||
public FeedItem getUnreadItemAt(int position);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,23 +11,31 @@ import android.widget.TextView;
|
||||
import de.danoeh.antennapod.R;
|
||||
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.storage.FeedItemStatistics;
|
||||
import de.danoeh.antennapod.util.ThemeUtils;
|
||||
|
||||
public class FeedlistAdapter extends BaseAdapter {
|
||||
private static final String TAG = "FeedlistAdapter";
|
||||
|
||||
private Context context;
|
||||
private FeedManager manager = FeedManager.getInstance();
|
||||
protected ItemAccess itemAccess;
|
||||
|
||||
private int selectedItemIndex;
|
||||
private ImageLoader imageLoader;
|
||||
public static final int SELECTION_NONE = -1;
|
||||
|
||||
public FeedlistAdapter(Context context) {
|
||||
public FeedlistAdapter(Context context, ItemAccess itemAccess) {
|
||||
super();
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("context must not be null");
|
||||
}
|
||||
if (itemAccess == null) {
|
||||
throw new IllegalArgumentException("itemAccess must not be null");
|
||||
}
|
||||
|
||||
this.context = context;
|
||||
this.itemAccess = itemAccess;
|
||||
selectedItemIndex = SELECTION_NONE;
|
||||
imageLoader = ImageLoader.getInstance();
|
||||
}
|
||||
@ -36,6 +44,7 @@ public class FeedlistAdapter extends BaseAdapter {
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final Holder holder;
|
||||
final Feed feed = getItem(position);
|
||||
final FeedItemStatistics feedItemStatistics = itemAccess.getFeedItemStatistics(position);
|
||||
|
||||
// Inflate Layout
|
||||
if (convertView == null) {
|
||||
@ -75,42 +84,40 @@ public class FeedlistAdapter extends BaseAdapter {
|
||||
}
|
||||
|
||||
holder.title.setText(feed.getTitle());
|
||||
int numOfItems = feed.getNumOfItems(true);
|
||||
if (DownloadRequester.getInstance().isDownloadingFile(feed)) {
|
||||
holder.lastUpdate.setText(R.string.refreshing_label);
|
||||
} else {
|
||||
if (numOfItems > 0) {
|
||||
holder.lastUpdate.setText(convertView.getResources().getString(
|
||||
R.string.most_recent_prefix)
|
||||
+ DateUtils.getRelativeTimeSpanString(
|
||||
feed.getItemAtIndex(true, 0).getPubDate().getTime(),
|
||||
System.currentTimeMillis(), 0, 0));
|
||||
} else {
|
||||
holder.lastUpdate.setText("");
|
||||
}
|
||||
}
|
||||
holder.numberOfEpisodes.setText(numOfItems
|
||||
+ convertView.getResources()
|
||||
.getString(R.string.episodes_suffix));
|
||||
|
||||
int newItems = feed.getNumOfNewItems();
|
||||
int inProgressItems = feed.getNumOfStartedItems();
|
||||
if (feedItemStatistics != null) {
|
||||
if (DownloadRequester.getInstance().isDownloadingFile(feed)) {
|
||||
holder.lastUpdate.setText(R.string.refreshing_label);
|
||||
} else {
|
||||
if (feedItemStatistics.getNumberOfItems() > 0) {
|
||||
holder.lastUpdate.setText(convertView.getResources().getString(
|
||||
R.string.most_recent_prefix)
|
||||
+ DateUtils.getRelativeTimeSpanString(
|
||||
feedItemStatistics.getLastUpdate().getTime(),
|
||||
System.currentTimeMillis(), 0, 0));
|
||||
} else {
|
||||
holder.lastUpdate.setText("");
|
||||
}
|
||||
}
|
||||
holder.numberOfEpisodes.setText(feedItemStatistics.getNumberOfItems()
|
||||
+ convertView.getResources()
|
||||
.getString(R.string.episodes_suffix));
|
||||
|
||||
if (newItems > 0) {
|
||||
holder.newEpisodes.setText(Integer.toString(newItems));
|
||||
holder.newEpisodesLabel.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.newEpisodesLabel.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
if (inProgressItems > 0) {
|
||||
holder.inProgressEpisodes
|
||||
.setText(Integer.toString(inProgressItems));
|
||||
holder.inProgressEpisodesLabel.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.inProgressEpisodesLabel.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
if (feedItemStatistics.getNumberOfNewItems() > 0) {
|
||||
holder.newEpisodes.setText(Integer.toString(feedItemStatistics.getNumberOfNewItems()));
|
||||
holder.newEpisodesLabel.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.newEpisodesLabel.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
if (feedItemStatistics.getNumberOfInProgressItems() > 0) {
|
||||
holder.inProgressEpisodes
|
||||
.setText(Integer.toString(feedItemStatistics.getNumberOfInProgressItems()));
|
||||
holder.inProgressEpisodesLabel.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.inProgressEpisodesLabel.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
final String imageUrl = (feed.getImage() != null) ? feed.getImage()
|
||||
.getFile_url() : null;
|
||||
holder.image.setTag(imageUrl);
|
||||
@ -145,12 +152,12 @@ public class FeedlistAdapter extends BaseAdapter {
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return manager.getFeedsSize();
|
||||
return itemAccess.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Feed getItem(int position) {
|
||||
return manager.getFeedAtIndex(position);
|
||||
return itemAccess.getItem(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -158,4 +165,11 @@ public class FeedlistAdapter extends BaseAdapter {
|
||||
return position;
|
||||
}
|
||||
|
||||
public interface ItemAccess {
|
||||
int getCount();
|
||||
|
||||
Feed getItem(int position);
|
||||
|
||||
FeedItemStatistics getFeedItemStatistics(int position);
|
||||
}
|
||||
}
|
||||
|
@ -14,13 +14,14 @@ import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import de.danoeh.antennapod.R;
|
||||
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.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.util.Converter;
|
||||
import de.danoeh.antennapod.util.ThemeUtils;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/** List adapter for items of feeds that the user has already subscribed to. */
|
||||
public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
|
||||
|
||||
@ -31,7 +32,7 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
|
||||
public static final int SELECTION_NONE = -1;
|
||||
|
||||
public InternalFeedItemlistAdapter(Context context,
|
||||
DefaultFeedItemlistAdapter.ItemAccess itemAccess,
|
||||
ItemAccess itemAccess,
|
||||
ActionButtonCallback callback, boolean showFeedtitle) {
|
||||
super(context, itemAccess);
|
||||
this.callback = callback;
|
||||
@ -155,7 +156,7 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
|
||||
}
|
||||
|
||||
holder.lenSize.setVisibility(View.VISIBLE);
|
||||
if (FeedManager.getInstance().isInQueue(item)) {
|
||||
if (((ItemAccess) itemAccess).isInQueue(item)) {
|
||||
holder.inPlaylist.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
holder.inPlaylist.setVisibility(View.GONE);
|
||||
@ -224,4 +225,8 @@ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter {
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public static interface ItemAccess extends DefaultFeedItemlistAdapter.ItemAccess {
|
||||
public boolean isInQueue(FeedItem item);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.os.AsyncTask;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.storage.DBWriter;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/** Removes a feed in the background. */
|
||||
public class FeedRemover extends AsyncTask<Void, Void, Void> {
|
||||
@ -23,9 +25,14 @@ public class FeedRemover extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
manager.deleteFeed(context, feed);
|
||||
return null;
|
||||
try {
|
||||
DBWriter.deleteFeed(context, feed.getId()).get();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -14,9 +14,9 @@ import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
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;
|
||||
import de.danoeh.antennapod.storage.DBReader;
|
||||
|
||||
/** Writes an OPML file into the export directory in the background. */
|
||||
public class OpmlExportWorker extends AsyncTask<Void, Void, Void> {
|
||||
@ -51,8 +51,7 @@ public class OpmlExportWorker extends AsyncTask<Void, Void, Void> {
|
||||
}
|
||||
try {
|
||||
FileWriter writer = new FileWriter(output);
|
||||
opmlWriter.writeDocument(Arrays.asList(FeedManager.getInstance().getFeedsArray()),
|
||||
writer);
|
||||
opmlWriter.writeDocument(DBReader.getFeedList(context), writer);
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
@ -92,7 +92,7 @@ public class EventDistributor extends Observable {
|
||||
super.addObserver(observer);
|
||||
if (!(observer instanceof EventListener)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Observer must be instance of FeedManager.EventListener");
|
||||
"Observer must be instance of EventListener");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,16 +170,7 @@ public class Feed extends FeedFile {
|
||||
} else {
|
||||
return download_url;
|
||||
}
|
||||
}
|
||||
|
||||
/** Calls cacheDescriptions on all items. */
|
||||
protected void cacheDescriptionsOfItems() {
|
||||
if (items != null) {
|
||||
for (FeedItem item : items) {
|
||||
item.cacheDescriptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateFromOther(Feed other) {
|
||||
super.updateFromOther(other);
|
||||
@ -284,12 +275,12 @@ public class Feed extends FeedFile {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
List<FeedItem> getItems() {
|
||||
public List<FeedItem> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public void setItems(ArrayList<FeedItem> items) {
|
||||
this.items = Collections.synchronizedList(items);
|
||||
public void setItems(List<FeedItem> list) {
|
||||
this.items = Collections.synchronizedList(list);
|
||||
}
|
||||
|
||||
/** Returns an array that contains all the feeditems of this feed. */
|
||||
|
@ -9,7 +9,7 @@ import org.apache.commons.io.IOUtils;
|
||||
|
||||
import de.danoeh.antennapod.asynctask.ImageLoader;
|
||||
|
||||
;
|
||||
|
||||
|
||||
public class FeedImage extends FeedFile implements
|
||||
ImageLoader.ImageWorkerTaskResource {
|
||||
|
@ -4,279 +4,276 @@ import java.io.InputStream;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import de.danoeh.antennapod.PodcastApp;
|
||||
import de.danoeh.antennapod.asynctask.ImageLoader;
|
||||
import de.danoeh.antennapod.storage.DBReader;
|
||||
import de.danoeh.antennapod.util.ShownotesProvider;
|
||||
|
||||
/**
|
||||
* Data Object for a XML message
|
||||
*
|
||||
*
|
||||
* @author daniel
|
||||
*
|
||||
*/
|
||||
public class FeedItem extends FeedComponent implements
|
||||
ImageLoader.ImageWorkerTaskResource {
|
||||
ImageLoader.ImageWorkerTaskResource, ShownotesProvider {
|
||||
|
||||
/** The id/guid that can be found in the rss/atom feed. Might not be set. */
|
||||
private String itemIdentifier;
|
||||
private String title;
|
||||
/**
|
||||
* The description of a feeditem. This field should only be set by the
|
||||
* parser.
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* The content of the content-encoded tag of a feeditem. This field should
|
||||
* only be set by the parser.
|
||||
*/
|
||||
private String contentEncoded;
|
||||
/**
|
||||
* The id/guid that can be found in the rss/atom feed. Might not be set.
|
||||
*/
|
||||
private String itemIdentifier;
|
||||
private String title;
|
||||
/**
|
||||
* The description of a feeditem.
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* The content of the content-encoded tag of a feeditem.
|
||||
*/
|
||||
private String contentEncoded;
|
||||
|
||||
private SoftReference<String> cachedDescription;
|
||||
private SoftReference<String> cachedContentEncoded;
|
||||
private String link;
|
||||
private Date pubDate;
|
||||
private FeedMedia media;
|
||||
|
||||
private String link;
|
||||
private Date pubDate;
|
||||
private FeedMedia media;
|
||||
private Feed feed;
|
||||
private boolean read;
|
||||
private String paymentLink;
|
||||
private List<Chapter> chapters;
|
||||
private Feed feed;
|
||||
private long feedId;
|
||||
|
||||
public FeedItem() {
|
||||
this.read = true;
|
||||
}
|
||||
private boolean read;
|
||||
private String paymentLink;
|
||||
private List<Chapter> chapters;
|
||||
|
||||
public void updateFromOther(FeedItem other) {
|
||||
super.updateFromOther(other);
|
||||
if (other.title != null) {
|
||||
title = other.title;
|
||||
}
|
||||
if (other.getDescription() != null) {
|
||||
description = other.getDescription();
|
||||
}
|
||||
if (other.getContentEncoded() != null) {
|
||||
contentEncoded = other.contentEncoded;
|
||||
}
|
||||
if (other.link != null) {
|
||||
link = other.link;
|
||||
}
|
||||
if (other.pubDate != null && other.pubDate != pubDate) {
|
||||
pubDate = other.pubDate;
|
||||
}
|
||||
if (other.media != null) {
|
||||
if (media == null) {
|
||||
media = other.media;
|
||||
} else if (media.compareWithOther(other)) {
|
||||
media.updateFromOther(other);
|
||||
}
|
||||
}
|
||||
if (other.paymentLink != null) {
|
||||
paymentLink = other.paymentLink;
|
||||
}
|
||||
if (other.chapters != null) {
|
||||
if (chapters == null) {
|
||||
chapters = other.chapters;
|
||||
}
|
||||
}
|
||||
}
|
||||
public FeedItem() {
|
||||
this.read = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the 'description' and 'contentEncoded' field of feeditem to their
|
||||
* SoftReference fields.
|
||||
*/
|
||||
protected void cacheDescriptions() {
|
||||
if (description != null) {
|
||||
cachedDescription = new SoftReference<String>(description);
|
||||
}
|
||||
if (contentEncoded != null) {
|
||||
cachedContentEncoded = new SoftReference<String>(contentEncoded);
|
||||
}
|
||||
description = null;
|
||||
contentEncoded = null;
|
||||
}
|
||||
public void updateFromOther(FeedItem other) {
|
||||
super.updateFromOther(other);
|
||||
if (other.title != null) {
|
||||
title = other.title;
|
||||
}
|
||||
if (other.getDescription() != null) {
|
||||
description = other.getDescription();
|
||||
}
|
||||
if (other.getContentEncoded() != null) {
|
||||
contentEncoded = other.contentEncoded;
|
||||
}
|
||||
if (other.link != null) {
|
||||
link = other.link;
|
||||
}
|
||||
if (other.pubDate != null && other.pubDate != pubDate) {
|
||||
pubDate = other.pubDate;
|
||||
}
|
||||
if (other.media != null) {
|
||||
if (media == null) {
|
||||
media = other.media;
|
||||
} else if (media.compareWithOther(other)) {
|
||||
media.updateFromOther(other);
|
||||
}
|
||||
}
|
||||
if (other.paymentLink != null) {
|
||||
paymentLink = other.paymentLink;
|
||||
}
|
||||
if (other.chapters != null) {
|
||||
if (chapters == null) {
|
||||
chapters = other.chapters;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value that uniquely identifies this FeedItem. If the
|
||||
* itemIdentifier attribute is not null, it will be returned. Else it will
|
||||
* try to return the title. If the title is not given, it will use the link
|
||||
* of the entry.
|
||||
* */
|
||||
public String getIdentifyingValue() {
|
||||
if (itemIdentifier != null) {
|
||||
return itemIdentifier;
|
||||
} else if (title != null) {
|
||||
return title;
|
||||
} else {
|
||||
return link;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns the value that uniquely identifies this FeedItem. If the
|
||||
* itemIdentifier attribute is not null, it will be returned. Else it will
|
||||
* try to return the title. If the title is not given, it will use the link
|
||||
* of the entry.
|
||||
*/
|
||||
public String getIdentifyingValue() {
|
||||
if (itemIdentifier != null) {
|
||||
return itemIdentifier;
|
||||
} else if (title != null) {
|
||||
return title;
|
||||
} else {
|
||||
return link;
|
||||
}
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
if (description == null && cachedDescription != null) {
|
||||
return cachedDescription.get();
|
||||
}
|
||||
return description;
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getLink() {
|
||||
return link;
|
||||
}
|
||||
public String getLink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
public void setLink(String link) {
|
||||
this.link = link;
|
||||
}
|
||||
public void setLink(String link) {
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
public Date getPubDate() {
|
||||
return pubDate;
|
||||
}
|
||||
public Date getPubDate() {
|
||||
return pubDate;
|
||||
}
|
||||
|
||||
public void setPubDate(Date pubDate) {
|
||||
this.pubDate = pubDate;
|
||||
}
|
||||
public void setPubDate(Date pubDate) {
|
||||
this.pubDate = pubDate;
|
||||
}
|
||||
|
||||
public FeedMedia getMedia() {
|
||||
return media;
|
||||
}
|
||||
public FeedMedia getMedia() {
|
||||
return media;
|
||||
}
|
||||
|
||||
public void setMedia(FeedMedia media) {
|
||||
this.media = media;
|
||||
}
|
||||
public void setMedia(FeedMedia media) {
|
||||
this.media = media;
|
||||
}
|
||||
|
||||
public Feed getFeed() {
|
||||
return feed;
|
||||
}
|
||||
public Feed getFeed() {
|
||||
return feed;
|
||||
}
|
||||
|
||||
public void setFeed(Feed feed) {
|
||||
this.feed = feed;
|
||||
}
|
||||
public void setFeed(Feed feed) {
|
||||
this.feed = feed;
|
||||
}
|
||||
|
||||
public boolean isRead() {
|
||||
return read || isInProgress();
|
||||
}
|
||||
public boolean isRead() {
|
||||
return read || isInProgress();
|
||||
}
|
||||
|
||||
public void setRead(boolean read) {
|
||||
this.read = read;
|
||||
}
|
||||
public void setRead(boolean read) {
|
||||
this.read = read;
|
||||
}
|
||||
|
||||
private boolean isInProgress() {
|
||||
return (media != null && media.isInProgress());
|
||||
}
|
||||
private boolean isInProgress() {
|
||||
return (media != null && media.isInProgress());
|
||||
}
|
||||
|
||||
public String getContentEncoded() {
|
||||
if (contentEncoded == null && cachedContentEncoded != null) {
|
||||
return cachedContentEncoded.get();
|
||||
public String getContentEncoded() {
|
||||
return contentEncoded;
|
||||
}
|
||||
|
||||
}
|
||||
return contentEncoded;
|
||||
}
|
||||
public void setContentEncoded(String contentEncoded) {
|
||||
this.contentEncoded = contentEncoded;
|
||||
}
|
||||
|
||||
public void setContentEncoded(String contentEncoded) {
|
||||
this.contentEncoded = contentEncoded;
|
||||
}
|
||||
public String getPaymentLink() {
|
||||
return paymentLink;
|
||||
}
|
||||
|
||||
public String getPaymentLink() {
|
||||
return paymentLink;
|
||||
}
|
||||
public void setPaymentLink(String paymentLink) {
|
||||
this.paymentLink = paymentLink;
|
||||
}
|
||||
|
||||
public void setPaymentLink(String paymentLink) {
|
||||
this.paymentLink = paymentLink;
|
||||
}
|
||||
public List<Chapter> getChapters() {
|
||||
return chapters;
|
||||
}
|
||||
|
||||
public List<Chapter> getChapters() {
|
||||
return chapters;
|
||||
}
|
||||
public void setChapters(List<Chapter> chapters) {
|
||||
this.chapters = chapters;
|
||||
}
|
||||
|
||||
public void setChapters(List<Chapter> chapters) {
|
||||
this.chapters = chapters;
|
||||
}
|
||||
public String getItemIdentifier() {
|
||||
return itemIdentifier;
|
||||
}
|
||||
|
||||
public String getItemIdentifier() {
|
||||
return itemIdentifier;
|
||||
}
|
||||
public void setItemIdentifier(String itemIdentifier) {
|
||||
this.itemIdentifier = itemIdentifier;
|
||||
}
|
||||
|
||||
public void setItemIdentifier(String itemIdentifier) {
|
||||
this.itemIdentifier = itemIdentifier;
|
||||
}
|
||||
public boolean hasMedia() {
|
||||
return media != null;
|
||||
}
|
||||
|
||||
public boolean hasMedia() {
|
||||
return media != null;
|
||||
}
|
||||
private boolean isPlaying() {
|
||||
if (media != null) {
|
||||
return media.isPlaying();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isPlaying() {
|
||||
if (media != null) {
|
||||
return media.isPlaying();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public Callable<String> loadShownotes() {
|
||||
return new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
|
||||
public void setCachedDescription(String d) {
|
||||
cachedDescription = new SoftReference<String>(d);
|
||||
}
|
||||
if (contentEncoded == null || description == null) {
|
||||
DBReader.loadExtraInformationOfFeedItem(PodcastApp.getInstance(), FeedItem.this);
|
||||
|
||||
public void setCachedContentEncoded(String c) {
|
||||
cachedContentEncoded = new SoftReference<String>(c);
|
||||
}
|
||||
}
|
||||
return (contentEncoded != null) ? contentEncoded : description;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public enum State {
|
||||
NEW, IN_PROGRESS, READ, PLAYING
|
||||
}
|
||||
public enum State {
|
||||
NEW, IN_PROGRESS, READ, PLAYING
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
if (hasMedia()) {
|
||||
if (isPlaying()) {
|
||||
return State.PLAYING;
|
||||
}
|
||||
if (isInProgress()) {
|
||||
return State.IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
return (isRead() ? State.READ : State.NEW);
|
||||
}
|
||||
public State getState() {
|
||||
if (hasMedia()) {
|
||||
if (isPlaying()) {
|
||||
return State.PLAYING;
|
||||
}
|
||||
if (isInProgress()) {
|
||||
return State.IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
return (isRead() ? State.READ : State.NEW);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openImageInputStream() {
|
||||
InputStream out = null;
|
||||
if (hasMedia()) {
|
||||
out = media.openImageInputStream();
|
||||
}
|
||||
if (out == null && feed.getImage() != null) {
|
||||
out = feed.getImage().openImageInputStream();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@Override
|
||||
public InputStream openImageInputStream() {
|
||||
InputStream out = null;
|
||||
if (hasMedia()) {
|
||||
out = media.openImageInputStream();
|
||||
}
|
||||
if (out == null && feed.getImage() != null) {
|
||||
out = feed.getImage().openImageInputStream();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream reopenImageInputStream(InputStream input) {
|
||||
InputStream out = null;
|
||||
if (hasMedia()) {
|
||||
out = media.reopenImageInputStream(input);
|
||||
}
|
||||
if (out == null && feed.getImage() != null) {
|
||||
out = feed.getImage().reopenImageInputStream(input);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@Override
|
||||
public InputStream reopenImageInputStream(InputStream input) {
|
||||
InputStream out = null;
|
||||
if (hasMedia()) {
|
||||
out = media.reopenImageInputStream(input);
|
||||
}
|
||||
if (out == null && feed.getImage() != null) {
|
||||
out = feed.getImage().reopenImageInputStream(input);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageLoaderCacheKey() {
|
||||
String out = null;
|
||||
if (hasMedia()) {
|
||||
out = media.getImageLoaderCacheKey();
|
||||
}
|
||||
if (out == null && feed.getImage() != null) {
|
||||
out = feed.getImage().getImageLoaderCacheKey();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public long getFeedId() {
|
||||
return feedId;
|
||||
}
|
||||
|
||||
public void setFeedId(long feedId) {
|
||||
this.feedId = feedId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageLoaderCacheKey() {
|
||||
String out = null;
|
||||
if (hasMedia()) {
|
||||
out = media.getImageLoaderCacheKey();
|
||||
}
|
||||
if (out == null && feed.getImage() != null) {
|
||||
out = feed.getImage().getImageLoaderCacheKey();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,7 @@ import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
@ -11,358 +12,383 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import de.danoeh.antennapod.PodcastApp;
|
||||
import de.danoeh.antennapod.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.storage.DBReader;
|
||||
import de.danoeh.antennapod.storage.DBWriter;
|
||||
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 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";
|
||||
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
|
||||
private long size; // File size in Byte
|
||||
private String mime_type;
|
||||
private FeedItem item;
|
||||
private Date playbackCompletionDate;
|
||||
private int duration;
|
||||
private int position; // Current position in file
|
||||
private long size; // File size in Byte
|
||||
private String mime_type;
|
||||
private volatile FeedItem item;
|
||||
private Date playbackCompletionDate;
|
||||
|
||||
public FeedMedia(FeedItem i, String download_url, long size,
|
||||
String mime_type) {
|
||||
super(null, download_url, false);
|
||||
this.item = i;
|
||||
this.size = size;
|
||||
this.mime_type = mime_type;
|
||||
}
|
||||
/* Used for loading item when restoring from parcel. */
|
||||
private long itemID;
|
||||
|
||||
public FeedMedia(long id, FeedItem item, int duration, int position,
|
||||
long size, String mime_type, String file_url, String download_url,
|
||||
boolean downloaded, Date playbackCompletionDate) {
|
||||
super(file_url, download_url, downloaded);
|
||||
this.id = id;
|
||||
this.item = item;
|
||||
this.duration = duration;
|
||||
this.position = position;
|
||||
this.size = size;
|
||||
this.mime_type = mime_type;
|
||||
this.playbackCompletionDate = playbackCompletionDate;
|
||||
}
|
||||
public FeedMedia(FeedItem i, String download_url, long size,
|
||||
String mime_type) {
|
||||
super(null, download_url, false);
|
||||
this.item = i;
|
||||
this.size = size;
|
||||
this.mime_type = mime_type;
|
||||
}
|
||||
|
||||
public FeedMedia(long id, FeedItem item) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.item = item;
|
||||
}
|
||||
public FeedMedia(long id, FeedItem item, int duration, int position,
|
||||
long size, String mime_type, String file_url, String download_url,
|
||||
boolean downloaded, Date playbackCompletionDate) {
|
||||
super(file_url, download_url, downloaded);
|
||||
this.id = id;
|
||||
this.item = item;
|
||||
this.duration = duration;
|
||||
this.position = position;
|
||||
this.size = size;
|
||||
this.mime_type = mime_type;
|
||||
this.playbackCompletionDate = playbackCompletionDate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHumanReadableIdentifier() {
|
||||
if (item != null && item.getTitle() != null) {
|
||||
return item.getTitle();
|
||||
} else {
|
||||
return download_url;
|
||||
}
|
||||
}
|
||||
public FeedMedia(long id, FeedItem item) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
/** Uses mimetype to determine the type of media. */
|
||||
public MediaType getMediaType() {
|
||||
if (mime_type == null || mime_type.isEmpty()) {
|
||||
return MediaType.UNKNOWN;
|
||||
} else {
|
||||
if (mime_type.startsWith("audio")) {
|
||||
return MediaType.AUDIO;
|
||||
} else if (mime_type.startsWith("video")) {
|
||||
return MediaType.VIDEO;
|
||||
} else if (mime_type.equals("application/ogg")) {
|
||||
return MediaType.AUDIO;
|
||||
}
|
||||
}
|
||||
return MediaType.UNKNOWN;
|
||||
}
|
||||
@Override
|
||||
public String getHumanReadableIdentifier() {
|
||||
if (item != null && item.getTitle() != null) {
|
||||
return item.getTitle();
|
||||
} else {
|
||||
return download_url;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateFromOther(FeedMedia other) {
|
||||
super.updateFromOther(other);
|
||||
if (other.size > 0) {
|
||||
size = other.size;
|
||||
}
|
||||
if (other.mime_type != null) {
|
||||
mime_type = other.mime_type;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Uses mimetype to determine the type of media.
|
||||
*/
|
||||
public MediaType getMediaType() {
|
||||
if (mime_type == null || mime_type.isEmpty()) {
|
||||
return MediaType.UNKNOWN;
|
||||
} else {
|
||||
if (mime_type.startsWith("audio")) {
|
||||
return MediaType.AUDIO;
|
||||
} else if (mime_type.startsWith("video")) {
|
||||
return MediaType.VIDEO;
|
||||
} else if (mime_type.equals("application/ogg")) {
|
||||
return MediaType.AUDIO;
|
||||
}
|
||||
}
|
||||
return MediaType.UNKNOWN;
|
||||
}
|
||||
|
||||
public boolean compareWithOther(FeedMedia other) {
|
||||
if (super.compareWithOther(other)) {
|
||||
return true;
|
||||
}
|
||||
if (other.mime_type != null) {
|
||||
if (mime_type == null || !mime_type.equals(other.mime_type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (other.size > 0 && other.size != size) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public void updateFromOther(FeedMedia other) {
|
||||
super.updateFromOther(other);
|
||||
if (other.size > 0) {
|
||||
size = other.size;
|
||||
}
|
||||
if (other.mime_type != null) {
|
||||
mime_type = other.mime_type;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads playback preferences to determine whether this FeedMedia object is
|
||||
* currently being played.
|
||||
*/
|
||||
public boolean isPlaying() {
|
||||
return PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA
|
||||
&& PlaybackPreferences.getCurrentlyPlayingFeedMediaId() == id;
|
||||
}
|
||||
public boolean compareWithOther(FeedMedia other) {
|
||||
if (super.compareWithOther(other)) {
|
||||
return true;
|
||||
}
|
||||
if (other.mime_type != null) {
|
||||
if (mime_type == null || !mime_type.equals(other.mime_type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (other.size > 0 && other.size != size) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTypeAsInt() {
|
||||
return FEEDFILETYPE_FEEDMEDIA;
|
||||
}
|
||||
/**
|
||||
* Reads playback preferences to determine whether this FeedMedia object is
|
||||
* currently being played.
|
||||
*/
|
||||
public boolean isPlaying() {
|
||||
return PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA
|
||||
&& PlaybackPreferences.getCurrentlyPlayingFeedMediaId() == id;
|
||||
}
|
||||
|
||||
public int getDuration() {
|
||||
return duration;
|
||||
}
|
||||
@Override
|
||||
public int getTypeAsInt() {
|
||||
return FEEDFILETYPE_FEEDMEDIA;
|
||||
}
|
||||
|
||||
public void setDuration(int duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
public int getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
public void setDuration(int duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public void setPosition(int position) {
|
||||
this.position = position;
|
||||
}
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
public void setPosition(int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public void setSize(long size) {
|
||||
this.size = size;
|
||||
}
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getMime_type() {
|
||||
return mime_type;
|
||||
}
|
||||
public void setSize(long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public void setMime_type(String mime_type) {
|
||||
this.mime_type = mime_type;
|
||||
}
|
||||
public String getMime_type() {
|
||||
return mime_type;
|
||||
}
|
||||
|
||||
public FeedItem getItem() {
|
||||
return item;
|
||||
}
|
||||
public void setMime_type(String mime_type) {
|
||||
this.mime_type = mime_type;
|
||||
}
|
||||
|
||||
public void setItem(FeedItem item) {
|
||||
this.item = item;
|
||||
}
|
||||
public FeedItem getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
public Date getPlaybackCompletionDate() {
|
||||
return playbackCompletionDate;
|
||||
}
|
||||
public void setItem(FeedItem item) {
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
public void setPlaybackCompletionDate(Date playbackCompletionDate) {
|
||||
this.playbackCompletionDate = playbackCompletionDate;
|
||||
}
|
||||
public Date getPlaybackCompletionDate() {
|
||||
return playbackCompletionDate;
|
||||
}
|
||||
|
||||
public boolean isInProgress() {
|
||||
return (this.position > 0);
|
||||
}
|
||||
public void setPlaybackCompletionDate(Date playbackCompletionDate) {
|
||||
this.playbackCompletionDate = playbackCompletionDate;
|
||||
}
|
||||
|
||||
public FeedImage getImage() {
|
||||
if (item != null && item.getFeed() != null) {
|
||||
return item.getFeed().getImage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public boolean isInProgress() {
|
||||
return (this.position > 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
public FeedImage getImage() {
|
||||
if (item != null && item.getFeed() != null) {
|
||||
return item.getFeed().getImage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(item.getFeed().getId());
|
||||
dest.writeLong(item.getId());
|
||||
}
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToPreferences(Editor prefEditor) {
|
||||
prefEditor.putLong(PREF_FEED_ID, item.getFeed().getId());
|
||||
prefEditor.putLong(PREF_MEDIA_ID, id);
|
||||
}
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(id);
|
||||
dest.writeLong(item.getId());
|
||||
|
||||
@Override
|
||||
public void loadMetadata() throws PlayableException {
|
||||
}
|
||||
dest.writeInt(duration);
|
||||
dest.writeInt(position);
|
||||
dest.writeLong(size);
|
||||
dest.writeString(mime_type);
|
||||
dest.writeString(file_url);
|
||||
dest.writeString(download_url);
|
||||
dest.writeByte((byte) ((downloaded) ? 1 : 0));
|
||||
dest.writeLong((playbackCompletionDate != null) ? playbackCompletionDate.getTime() : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadChapterMarks() {
|
||||
if (getChapters() == null && !localFileAvailable()) {
|
||||
ChapterUtils.loadChaptersFromStreamUrl(this);
|
||||
if (getChapters() != null) {
|
||||
FeedManager.getInstance().setFeedItem(PodcastApp.getInstance(),
|
||||
item);
|
||||
}
|
||||
}
|
||||
@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 (item == null && itemID != 0) {
|
||||
item = DBReader.getFeedItem(PodcastApp.getInstance(), itemID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEpisodeTitle() {
|
||||
if (getItem().getTitle() != null) {
|
||||
return getItem().getTitle();
|
||||
} else {
|
||||
return getItem().getIdentifyingValue();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void loadChapterMarks() {
|
||||
if (getChapters() == null && !localFileAvailable()) {
|
||||
ChapterUtils.loadChaptersFromStreamUrl(this);
|
||||
if (getChapters() != null && item != null) {
|
||||
DBWriter.setFeedItem(PodcastApp.getInstance(),
|
||||
item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Chapter> getChapters() {
|
||||
return getItem().getChapters();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWebsiteLink() {
|
||||
return getItem().getLink();
|
||||
}
|
||||
@Override
|
||||
public String getEpisodeTitle() {
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
if (getItem().getTitle() != null) {
|
||||
return getItem().getTitle();
|
||||
} else {
|
||||
return getItem().getIdentifyingValue();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeedTitle() {
|
||||
return getItem().getFeed().getTitle();
|
||||
}
|
||||
@Override
|
||||
public List<Chapter> getChapters() {
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
return getItem().getChapters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getIdentifier() {
|
||||
return id;
|
||||
}
|
||||
@Override
|
||||
public String getWebsiteLink() {
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
return getItem().getLink();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLocalMediaUrl() {
|
||||
return file_url;
|
||||
}
|
||||
@Override
|
||||
public String getFeedTitle() {
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
return getItem().getFeed().getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStreamUrl() {
|
||||
return download_url;
|
||||
}
|
||||
@Override
|
||||
public Object getIdentifier() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean localFileAvailable() {
|
||||
return isDownloaded() && file_url != null;
|
||||
}
|
||||
@Override
|
||||
public String getLocalMediaUrl() {
|
||||
return file_url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean streamAvailable() {
|
||||
return download_url != null;
|
||||
}
|
||||
@Override
|
||||
public String getStreamUrl() {
|
||||
return download_url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveCurrentPosition(SharedPreferences pref, int newPosition) {
|
||||
position = newPosition;
|
||||
FeedManager.getInstance().setFeedMedia(PodcastApp.getInstance(), this);
|
||||
}
|
||||
@Override
|
||||
public String getPaymentLink() {
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
return getItem().getPaymentLink();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackStart() {
|
||||
}
|
||||
@Override
|
||||
public boolean localFileAvailable() {
|
||||
return isDownloaded() && file_url != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackCompleted() {
|
||||
@Override
|
||||
public boolean streamAvailable() {
|
||||
return download_url != null;
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void saveCurrentPosition(SharedPreferences pref, int newPosition) {
|
||||
position = newPosition;
|
||||
DBWriter.setFeedMediaPosition(PodcastApp.getInstance(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayableType() {
|
||||
return PLAYABLE_TYPE_FEEDMEDIA;
|
||||
}
|
||||
@Override
|
||||
public void onPlaybackStart() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChapters(List<Chapter> chapters) {
|
||||
getItem().setChapters(chapters);
|
||||
}
|
||||
@Override
|
||||
public void onPlaybackCompleted() {
|
||||
|
||||
@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]);
|
||||
@Override
|
||||
public int getPlayableType() {
|
||||
return PLAYABLE_TYPE_FEEDMEDIA;
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void setChapters(List<Chapter> chapters) {
|
||||
getItem().setChapters(chapters);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback.onShownotesLoaded(contentEncoded);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Callable<String> loadShownotes() {
|
||||
return new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
if (item == null) {
|
||||
item = DBReader.getFeedItem(PodcastApp.getInstance(), itemID);
|
||||
}
|
||||
if (item.getContentEncoded() == null || item.getDescription() == null) {
|
||||
DBReader.loadExtraInformationOfFeedItem(PodcastApp.getInstance(), item);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (item.getContentEncoded() != null) ? item.getContentEncoded() : item.getDescription();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public FeedMedia[] newArray(int size) {
|
||||
return new FeedMedia[size];
|
||||
}
|
||||
};
|
||||
public static final Parcelable.Creator<FeedMedia> CREATOR = new Parcelable.Creator<FeedMedia>() {
|
||||
public FeedMedia createFromParcel(Parcel in) {
|
||||
final long id = in.readLong();
|
||||
final long itemID = in.readLong();
|
||||
FeedMedia result = new FeedMedia(id, null, in.readInt(), in.readInt(), in.readLong(), in.readString(), in.readString(),
|
||||
in.readString(), in.readByte() != 0, new Date(in.readLong()));
|
||||
result.itemID = itemID;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openImageInputStream() {
|
||||
InputStream out = new Playable.DefaultPlayableImageLoader(this)
|
||||
.openImageInputStream();
|
||||
if (out == null) {
|
||||
if (item.getFeed().getImage() != null) {
|
||||
return item.getFeed().getImage().openImageInputStream();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
public FeedMedia[] newArray(int size) {
|
||||
return new FeedMedia[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public String getImageLoaderCacheKey() {
|
||||
String out = new Playable.DefaultPlayableImageLoader(this)
|
||||
.getImageLoaderCacheKey();
|
||||
if (out == null) {
|
||||
if (item.getFeed().getImage() != null) {
|
||||
return item.getFeed().getImage().getImageLoaderCacheKey();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@Override
|
||||
public InputStream openImageInputStream() {
|
||||
InputStream out = new Playable.DefaultPlayableImageLoader(this)
|
||||
.openImageInputStream();
|
||||
if (out == null) {
|
||||
if (item.getFeed().getImage() != null) {
|
||||
return item.getFeed().getImage().openImageInputStream();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream reopenImageInputStream(InputStream input) {
|
||||
if (input instanceof FileInputStream) {
|
||||
return item.getFeed().getImage().reopenImageInputStream(input);
|
||||
} else {
|
||||
return new Playable.DefaultPlayableImageLoader(this)
|
||||
.reopenImageInputStream(input);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String getImageLoaderCacheKey() {
|
||||
String out = new Playable.DefaultPlayableImageLoader(this)
|
||||
.getImageLoaderCacheKey();
|
||||
if (out == null) {
|
||||
if (item.getFeed().getImage() != null) {
|
||||
return item.getFeed().getImage().getImageLoaderCacheKey();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream reopenImageInputStream(InputStream input) {
|
||||
if (input instanceof FileInputStream) {
|
||||
return item.getFeed().getImage().reopenImageInputStream(input);
|
||||
} else {
|
||||
return new Playable.DefaultPlayableImageLoader(this)
|
||||
.reopenImageInputStream(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,253 +0,0 @@
|
||||
package de.danoeh.antennapod.feed;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.PodcastApp;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.storage.PodDBAdapter;
|
||||
import de.danoeh.antennapod.util.comparator.SearchResultValueComparator;
|
||||
|
||||
/** Performs search on Feeds and FeedItems */
|
||||
public class FeedSearcher {
|
||||
private static final String TAG = "FeedSearcher";
|
||||
|
||||
// Search result values
|
||||
private static final int VALUE_FEED_TITLE = 3;
|
||||
private static final int VALUE_ITEM_TITLE = 2;
|
||||
private static final int VALUE_ITEM_CHAPTER = 1;
|
||||
private static final int VALUE_ITEM_DESCRIPTION = 0;
|
||||
private static final int VALUE_WORD_MATCH = 4;
|
||||
|
||||
/** Performs a search in all feeds or one specific feed. */
|
||||
public static ArrayList<SearchResult> performSearch(final Context context,
|
||||
final String query, final Feed selectedFeed) {
|
||||
final String lcQuery = query.toLowerCase();
|
||||
final ArrayList<SearchResult> result = new ArrayList<SearchResult>();
|
||||
if (selectedFeed == null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Performing global search");
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Searching Feed titles");
|
||||
searchFeedtitles(lcQuery, result);
|
||||
} else if (AppConfig.DEBUG) {
|
||||
Log.d(TAG, "Performing search on specific feed");
|
||||
}
|
||||
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Searching Feeditem titles");
|
||||
searchFeedItemTitles(lcQuery, result, selectedFeed);
|
||||
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Searching item-chaptertitles");
|
||||
searchFeedItemChapters(lcQuery, result, selectedFeed);
|
||||
|
||||
final FeedManager manager = FeedManager.getInstance();
|
||||
Looper.prepare();
|
||||
manager.searchFeedItemDescription(context, selectedFeed, lcQuery,
|
||||
new FeedManager.QueryTaskCallback() {
|
||||
|
||||
@Override
|
||||
public void handleResult(Cursor cResult) {
|
||||
searchFeedItemContentEncodedCursor(lcQuery, result,
|
||||
selectedFeed, cResult);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompletion() {
|
||||
manager.searchFeedItemContentEncoded(context,
|
||||
selectedFeed, lcQuery,
|
||||
new FeedManager.QueryTaskCallback() {
|
||||
|
||||
@Override
|
||||
public void handleResult(Cursor cResult) {
|
||||
searchFeedItemDescriptionCursor(
|
||||
lcQuery, result, selectedFeed,
|
||||
cResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompletion() {
|
||||
Looper.myLooper().quit();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Looper.loop();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Sorting results");
|
||||
Collections.sort(result, new SearchResultValueComparator());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void searchFeedtitles(String query,
|
||||
ArrayList<SearchResult> destination) {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
for (Feed feed : manager.getFeeds()) {
|
||||
SearchResult result = createSearchResult(feed, query, feed
|
||||
.getTitle().toLowerCase(), VALUE_FEED_TITLE);
|
||||
if (result != null) {
|
||||
destination.add(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void searchFeedItemTitles(String query,
|
||||
ArrayList<SearchResult> destination, Feed selectedFeed) {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
if (selectedFeed == null) {
|
||||
for (Feed feed : manager.getFeeds()) {
|
||||
searchFeedItemTitlesSingleFeed(query, destination, feed);
|
||||
}
|
||||
} else {
|
||||
searchFeedItemTitlesSingleFeed(query, destination, selectedFeed);
|
||||
}
|
||||
}
|
||||
|
||||
private static void searchFeedItemTitlesSingleFeed(String query,
|
||||
ArrayList<SearchResult> destination, Feed feed) {
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
SearchResult result = createSearchResult(item, query, item
|
||||
.getTitle().toLowerCase(), VALUE_ITEM_TITLE);
|
||||
if (result != null) {
|
||||
result.setSubtitle(PodcastApp.getInstance().getString(
|
||||
R.string.found_in_title_label));
|
||||
destination.add(result);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void searchFeedItemChapters(String query,
|
||||
ArrayList<SearchResult> destination, Feed selectedFeed) {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
if (selectedFeed == null) {
|
||||
for (Feed feed : manager.getFeeds()) {
|
||||
searchFeedItemChaptersSingleFeed(query, destination, feed);
|
||||
}
|
||||
} else {
|
||||
searchFeedItemChaptersSingleFeed(query, destination, selectedFeed);
|
||||
}
|
||||
}
|
||||
|
||||
private static void searchFeedItemChaptersSingleFeed(String query,
|
||||
ArrayList<SearchResult> destination, Feed feed) {
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
if (item.getChapters() != null) {
|
||||
for (Chapter sc : item.getChapters()) {
|
||||
SearchResult result = createSearchResult(item, query, sc
|
||||
.getTitle().toLowerCase(), VALUE_ITEM_CHAPTER);
|
||||
if (result != null) {
|
||||
result.setSubtitle(PodcastApp.getInstance().getString(
|
||||
R.string.found_in_chapters_label));
|
||||
destination.add(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void searchFeedItemDescriptionCursor(String query,
|
||||
ArrayList<SearchResult> destination, Feed feed, Cursor cursor) {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
final long itemId = cursor
|
||||
.getLong(PodDBAdapter.IDX_FI_EXTRA_ID);
|
||||
String content = cursor
|
||||
.getString(PodDBAdapter.IDX_FI_EXTRA_DESCRIPTION);
|
||||
if (content != null) {
|
||||
content = content.toLowerCase();
|
||||
final long feedId = cursor
|
||||
.getLong(PodDBAdapter.IDX_FI_EXTRA_FEED);
|
||||
FeedItem item = null;
|
||||
if (feed == null) {
|
||||
item = manager.getFeedItem(itemId, feedId);
|
||||
} else {
|
||||
item = manager.getFeedItem(itemId, feed);
|
||||
}
|
||||
if (item != null) {
|
||||
SearchResult searchResult = createSearchResult(item,
|
||||
query, content, VALUE_ITEM_DESCRIPTION);
|
||||
if (searchResult != null) {
|
||||
searchResult.setSubtitle(PodcastApp.getInstance()
|
||||
.getString(
|
||||
R.string.found_in_shownotes_label));
|
||||
destination.add(searchResult);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
}
|
||||
|
||||
private static void searchFeedItemContentEncodedCursor(String query,
|
||||
ArrayList<SearchResult> destination, Feed feed, Cursor cursor) {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
final long itemId = cursor
|
||||
.getLong(PodDBAdapter.IDX_FI_EXTRA_ID);
|
||||
String content = cursor
|
||||
.getString(PodDBAdapter.IDX_FI_EXTRA_CONTENT_ENCODED);
|
||||
if (content != null) {
|
||||
content = content.toLowerCase();
|
||||
|
||||
final long feedId = cursor
|
||||
.getLong(PodDBAdapter.IDX_FI_EXTRA_FEED);
|
||||
FeedItem item = null;
|
||||
if (feed == null) {
|
||||
item = manager.getFeedItem(itemId, feedId);
|
||||
} else {
|
||||
item = manager.getFeedItem(itemId, feed);
|
||||
}
|
||||
if (item != null) {
|
||||
SearchResult searchResult = createSearchResult(item,
|
||||
query, content, VALUE_ITEM_DESCRIPTION);
|
||||
if (searchResult != null) {
|
||||
searchResult.setSubtitle(PodcastApp.getInstance()
|
||||
.getString(
|
||||
R.string.found_in_shownotes_label));
|
||||
destination.add(searchResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
}
|
||||
|
||||
private static SearchResult createSearchResult(FeedComponent component,
|
||||
String query, String text, int baseValue) {
|
||||
int bonus = 0;
|
||||
boolean found = false;
|
||||
// try word search
|
||||
Pattern word = Pattern.compile("\b" + query + "\b");
|
||||
Matcher matcher = word.matcher(text);
|
||||
found = matcher.find();
|
||||
if (found) {
|
||||
bonus = VALUE_WORD_MATCH;
|
||||
} else {
|
||||
// search for other occurence
|
||||
found = text.contains(query);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
return new SearchResult(component, baseValue + bonus);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -7,10 +7,11 @@ public class SearchResult {
|
||||
/** Higher value means more importance */
|
||||
private int value;
|
||||
|
||||
public SearchResult(FeedComponent component, int value) {
|
||||
public SearchResult(FeedComponent component, int value, String subtitle) {
|
||||
super();
|
||||
this.component = component;
|
||||
this.value = value;
|
||||
this.subtitle = subtitle;
|
||||
}
|
||||
|
||||
public FeedComponent getComponent() {
|
||||
|
@ -1,6 +1,8 @@
|
||||
package de.danoeh.antennapod.fragment;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
@ -18,10 +20,15 @@ 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.storage.DBReader;
|
||||
import de.danoeh.antennapod.storage.DBTasks;
|
||||
import de.danoeh.antennapod.storage.DBWriter;
|
||||
import de.danoeh.antennapod.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.util.QueueAccess;
|
||||
import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EpisodesFragment extends Fragment {
|
||||
private static final String TAG = "EpisodesFragment";
|
||||
|
||||
@ -34,6 +41,9 @@ public class EpisodesFragment extends Fragment {
|
||||
private ExpandableListView listView;
|
||||
private ExternalEpisodesListAdapter adapter;
|
||||
|
||||
private List<FeedItem> queue;
|
||||
private List<FeedItem> unreadItems;
|
||||
|
||||
protected FeedItem selectedItem = null;
|
||||
protected long selectedGroupId = -1;
|
||||
protected boolean contextMenuClosed = true;
|
||||
@ -86,7 +96,7 @@ public class EpisodesFragment extends Fragment {
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
adapter = new ExternalEpisodesListAdapter(getActivity(),
|
||||
adapterCallback, groupActionCallback);
|
||||
adapterCallback, groupActionCallback, itemAccess);
|
||||
listView.setAdapter(adapter);
|
||||
listView.expandGroup(ExternalEpisodesListAdapter.GROUP_POS_QUEUE);
|
||||
listView.expandGroup(ExternalEpisodesListAdapter.GROUP_POS_UNREAD);
|
||||
@ -111,9 +121,73 @@ public class EpisodesFragment extends Fragment {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
loadData();
|
||||
registerForContextMenu(listView);
|
||||
|
||||
}
|
||||
|
||||
ExternalEpisodesListAdapter.ItemAccess itemAccess = new ExternalEpisodesListAdapter.ItemAccess() {
|
||||
|
||||
@Override
|
||||
public int getQueueSize() {
|
||||
return (queue != null) ? queue.size() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnreadItemsSize() {
|
||||
return (unreadItems != null) ? unreadItems.size() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeedItem getQueueItemAt(int position) {
|
||||
return (queue != null) ? queue.get(position) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FeedItem getUnreadItemAt(int position) {
|
||||
return (unreadItems != null) ? unreadItems.get(position) : null;
|
||||
}
|
||||
};
|
||||
|
||||
private void loadData() {
|
||||
AsyncTask<Void, Void, Void> loadTask = new AsyncTask<Void, Void, Void>() {
|
||||
private volatile List<FeedItem> queueRef;
|
||||
private volatile List<FeedItem> unreadItemsRef;
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
if (AppConfig.DEBUG) Log.d(TAG, "Starting to load list data");
|
||||
Context context = EpisodesFragment.this.getActivity();
|
||||
if (context != null) {
|
||||
queueRef = DBReader.getQueue(context);
|
||||
unreadItemsRef = DBReader.getUnreadItemsList(context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
super.onPostExecute(aVoid);
|
||||
if (queueRef != null && unreadItemsRef != null) {
|
||||
if (AppConfig.DEBUG) Log.d(TAG, "Done loading list data");
|
||||
queue = queueRef;
|
||||
unreadItems = unreadItemsRef;
|
||||
if (adapter != null) {
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
} else {
|
||||
if (queueRef == null) {
|
||||
Log.e(TAG, "Could not load queue");
|
||||
}
|
||||
if (unreadItemsRef == null) {
|
||||
Log.e(TAG, "Could not load unread items");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
loadTask.execute();
|
||||
}
|
||||
|
||||
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
|
||||
|
||||
@Override
|
||||
@ -121,7 +195,7 @@ public class EpisodesFragment extends Fragment {
|
||||
if ((EVENTS & arg) != 0) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Received contentUpdate Intent.");
|
||||
adapter.notifyDataSetChanged();
|
||||
loadData();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -140,13 +214,13 @@ public class EpisodesFragment extends Fragment {
|
||||
|
||||
menu.setHeaderTitle(selectedItem.getTitle());
|
||||
FeedItemMenuHandler.onPrepareMenu(
|
||||
new FeedItemMenuHandler.MenuInterface() {
|
||||
new FeedItemMenuHandler.MenuInterface() {
|
||||
|
||||
@Override
|
||||
public void setItemVisibility(int id, boolean visible) {
|
||||
menu.findItem(id).setVisible(visible);
|
||||
}
|
||||
}, selectedItem, false);
|
||||
@Override
|
||||
public void setItemVisibility(int id, boolean visible) {
|
||||
menu.findItem(id).setVisible(visible);
|
||||
}
|
||||
}, selectedItem, false, QueueAccess.ItemListAccess(queue));
|
||||
|
||||
} else if (selectedGroupId == ExternalEpisodesListAdapter.GROUP_POS_QUEUE) {
|
||||
menu.add(Menu.NONE, R.id.organize_queue_item, Menu.NONE,
|
||||
@ -166,7 +240,6 @@ public class EpisodesFragment extends Fragment {
|
||||
@Override
|
||||
public boolean onContextItemSelected(android.view.MenuItem item) {
|
||||
boolean handled = false;
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
if (selectedItem != null) {
|
||||
try {
|
||||
handled = FeedItemMenuHandler.onMenuItemClicked(
|
||||
@ -185,10 +258,10 @@ public class EpisodesFragment extends Fragment {
|
||||
OrganizeQueueActivity.class));
|
||||
break;
|
||||
case R.id.clear_queue_item:
|
||||
manager.clearQueue(getActivity());
|
||||
DBWriter.clearQueue(getActivity());
|
||||
break;
|
||||
case R.id.download_all_item:
|
||||
manager.downloadAllItemsInQueue(getActivity());
|
||||
DBTasks.downloadAllItemsInQueue(getActivity());
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
@ -197,10 +270,10 @@ public class EpisodesFragment extends Fragment {
|
||||
handled = true;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.mark_all_read_item:
|
||||
manager.markAllItemsRead(getActivity());
|
||||
DBWriter.markAllItemsRead(getActivity());
|
||||
break;
|
||||
case R.id.enqueue_all_item:
|
||||
manager.enqueueAllNewItems(getActivity());
|
||||
DBTasks.enqueueAllNewItems(getActivity());
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
|
@ -1,19 +1,18 @@
|
||||
package de.danoeh.antennapod.fragment;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.support.v7.view.ActionMode;
|
||||
import android.util.Log;
|
||||
import android.view.*;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.GridView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.*;
|
||||
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.R;
|
||||
@ -24,8 +23,9 @@ 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.storage.DBReader;
|
||||
import de.danoeh.antennapod.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.storage.FeedItemStatistics;
|
||||
import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
|
||||
|
||||
public class FeedlistFragment extends Fragment implements
|
||||
@ -33,191 +33,251 @@ public class FeedlistFragment extends Fragment implements
|
||||
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 static final int EVENTS = EventDistributor.DOWNLOAD_HANDLED
|
||||
| EventDistributor.DOWNLOAD_QUEUED
|
||||
| EventDistributor.FEED_LIST_UPDATE
|
||||
| EventDistributor.UNREAD_ITEMS_UPDATE;
|
||||
|
||||
private FeedManager manager;
|
||||
private FeedlistAdapter fla;
|
||||
public static final String EXTRA_SELECTED_FEED = "extra.de.danoeh.antennapod.activity.selected_feed";
|
||||
|
||||
private Feed selectedFeed;
|
||||
private ActionMode mActionMode;
|
||||
private FeedlistAdapter fla;
|
||||
private List<Feed> feeds;
|
||||
private List<FeedItemStatistics> feedItemStatistics;
|
||||
|
||||
private GridView gridView;
|
||||
private ListView listView;
|
||||
private TextView txtvEmpty;
|
||||
private Feed selectedFeed;
|
||||
private ActionMode mActionMode;
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
}
|
||||
private GridView gridView;
|
||||
private ListView listView;
|
||||
private TextView emptyView;
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
}
|
||||
private FeedlistAdapter.ItemAccess itemAccess = new FeedlistAdapter.ItemAccess() {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Creating");
|
||||
manager = FeedManager.getInstance();
|
||||
fla = new FeedlistAdapter(getActivity());
|
||||
@Override
|
||||
public Feed getItem(int position) {
|
||||
if (feeds != null) {
|
||||
return feeds.get(position);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public FeedItemStatistics getFeedItemStatistics(int position) {
|
||||
if (feedItemStatistics != null && position < feedItemStatistics.size()) {
|
||||
return feedItemStatistics.get(position);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View result = inflater.inflate(R.layout.feedlist, container, false);
|
||||
listView = (ListView) result.findViewById(android.R.id.list);
|
||||
gridView = (GridView) result.findViewById(R.id.grid);
|
||||
txtvEmpty = (TextView) result.findViewById(android.R.id.empty);
|
||||
@Override
|
||||
public int getCount() {
|
||||
if (feeds != null) {
|
||||
return feeds.size();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return result;
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Creating");
|
||||
fla = new FeedlistAdapter(getActivity(), itemAccess);
|
||||
loadFeeds();
|
||||
}
|
||||
|
||||
}
|
||||
private void loadFeeds() {
|
||||
AsyncTask<Void, Void, List[]> loadTask = new AsyncTask<Void, Void, List[]>() {
|
||||
@Override
|
||||
protected List[] doInBackground(Void... params) {
|
||||
return new List[]{DBReader.getFeedList(getActivity()),
|
||||
DBReader.getFeedStatisticsList(getActivity())};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
if (listView != null) {
|
||||
listView.setOnItemClickListener(this);
|
||||
listView.setOnItemLongClickListener(this);
|
||||
listView.setAdapter(fla);
|
||||
listView.setEmptyView(txtvEmpty);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Using ListView");
|
||||
} else {
|
||||
gridView.setOnItemClickListener(this);
|
||||
gridView.setOnItemLongClickListener(this);
|
||||
gridView.setAdapter(fla);
|
||||
gridView.setEmptyView(txtvEmpty);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Using GridView");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Resuming");
|
||||
EventDistributor.getInstance().register(contentUpdate);
|
||||
fla.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
EventDistributor.getInstance().unregister(contentUpdate);
|
||||
if (mActionMode != null) {
|
||||
mActionMode.finish();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(List[] result) {
|
||||
super.onPostExecute(result);
|
||||
if (result != null) {
|
||||
feeds = result[0];
|
||||
feedItemStatistics = result[1];
|
||||
setEmptyViewIfListIsEmpty();
|
||||
if (fla != null) {
|
||||
fla.notifyDataSetChanged();
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Failed to load feeds");
|
||||
}
|
||||
}
|
||||
};
|
||||
loadTask.execute();
|
||||
}
|
||||
|
||||
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
|
||||
|
||||
@Override
|
||||
public void update(EventDistributor eventDistributor, Integer arg) {
|
||||
if ((EVENTS & arg) != 0) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Received contentUpdate Intent.");
|
||||
fla.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View result = inflater.inflate(R.layout.feedlist, container, false);
|
||||
listView = (ListView) result.findViewById(android.R.id.list);
|
||||
gridView = (GridView) result.findViewById(R.id.grid);
|
||||
emptyView = (TextView) result.findViewById(android.R.id.empty);
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
FeedMenuHandler.onCreateOptionsMenu(mode.getMenuInflater(), menu);
|
||||
mode.setTitle(selectedFeed.getTitle());
|
||||
return true;
|
||||
}
|
||||
return result;
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
return FeedMenuHandler.onPrepareOptionsMenu(menu, selectedFeed);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
try {
|
||||
if (FeedMenuHandler.onOptionsItemClicked(getActivity(),
|
||||
item, selectedFeed)) {
|
||||
fla.notifyDataSetChanged();
|
||||
} else {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.remove_item:
|
||||
final FeedRemover remover = new FeedRemover(
|
||||
getActivity(), selectedFeed) {
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
super.onPostExecute(result);
|
||||
fla.notifyDataSetChanged();
|
||||
}
|
||||
};
|
||||
ConfirmationDialog conDialog = new ConfirmationDialog(
|
||||
getActivity(), R.string.remove_feed_label,
|
||||
R.string.feed_delete_confirmation_msg) {
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
if (listView != null) {
|
||||
listView.setOnItemClickListener(this);
|
||||
listView.setOnItemLongClickListener(this);
|
||||
listView.setAdapter(fla);
|
||||
listView.setEmptyView(emptyView);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Using ListView");
|
||||
} else {
|
||||
gridView.setOnItemClickListener(this);
|
||||
gridView.setOnItemLongClickListener(this);
|
||||
gridView.setAdapter(fla);
|
||||
gridView.setEmptyView(emptyView);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Using GridView");
|
||||
}
|
||||
setEmptyViewIfListIsEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfirmButtonPressed(
|
||||
DialogInterface dialog) {
|
||||
dialog.dismiss();
|
||||
remover.executeAsync();
|
||||
}
|
||||
};
|
||||
conDialog.createNewDialog().show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
DownloadRequestErrorDialogCreator.newRequestErrorDialog(
|
||||
getActivity(), e.getMessage());
|
||||
}
|
||||
mode.finish();
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Resuming");
|
||||
EventDistributor.getInstance().register(contentUpdate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
mActionMode = null;
|
||||
selectedFeed = null;
|
||||
fla.setSelectedItemIndex(FeedlistAdapter.SELECTION_NONE);
|
||||
}
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
EventDistributor.getInstance().unregister(contentUpdate);
|
||||
if (mActionMode != null) {
|
||||
mActionMode.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
|
||||
long id) {
|
||||
Feed selection = fla.getItem(position);
|
||||
Intent showFeed = new Intent(getActivity(), FeedItemlistActivity.class);
|
||||
showFeed.putExtra(EXTRA_SELECTED_FEED, selection.getId());
|
||||
private EventDistributor.EventListener contentUpdate = new EventDistributor.EventListener() {
|
||||
|
||||
getActivity().startActivity(showFeed);
|
||||
}
|
||||
@Override
|
||||
public void update(EventDistributor eventDistributor, Integer arg) {
|
||||
if ((EVENTS & arg) != 0) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Received contentUpdate Intent.");
|
||||
loadFeeds();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view,
|
||||
int position, long id) {
|
||||
Feed selection = fla.getItem(position);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Selected Feed with title " + selection.getTitle());
|
||||
if (selection != null) {
|
||||
if (mActionMode != null) {
|
||||
mActionMode.finish();
|
||||
}
|
||||
fla.setSelectedItemIndex(position);
|
||||
selectedFeed = selection;
|
||||
mActionMode = ((ActionBarActivity) getActivity()).startSupportActionMode(FeedlistFragment.this);
|
||||
@Override
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
FeedMenuHandler.onCreateOptionsMenu(mode.getMenuInflater(), menu);
|
||||
mode.setTitle(selectedFeed.getTitle());
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
return FeedMenuHandler.onPrepareOptionsMenu(menu, selectedFeed);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
try {
|
||||
if (FeedMenuHandler.onOptionsItemClicked(getActivity(),
|
||||
item, selectedFeed)) {
|
||||
loadFeeds();
|
||||
} else {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.remove_item:
|
||||
final FeedRemover remover = new FeedRemover(
|
||||
getActivity(), selectedFeed) {
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
super.onPostExecute(result);
|
||||
loadFeeds();
|
||||
}
|
||||
};
|
||||
ConfirmationDialog conDialog = new ConfirmationDialog(
|
||||
getActivity(), R.string.remove_feed_label,
|
||||
R.string.feed_delete_confirmation_msg) {
|
||||
|
||||
@Override
|
||||
public void onConfirmButtonPressed(
|
||||
DialogInterface dialog) {
|
||||
dialog.dismiss();
|
||||
remover.executeAsync();
|
||||
}
|
||||
};
|
||||
conDialog.createNewDialog().show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
DownloadRequestErrorDialogCreator.newRequestErrorDialog(
|
||||
getActivity(), e.getMessage());
|
||||
}
|
||||
mode.finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
mActionMode = null;
|
||||
selectedFeed = null;
|
||||
fla.setSelectedItemIndex(FeedlistAdapter.SELECTION_NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
|
||||
long id) {
|
||||
Feed selection = fla.getItem(position);
|
||||
Intent showFeed = new Intent(getActivity(), FeedItemlistActivity.class);
|
||||
showFeed.putExtra(EXTRA_SELECTED_FEED, selection.getId());
|
||||
|
||||
getActivity().startActivity(showFeed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemLongClick(AdapterView<?> parent, View view,
|
||||
int position, long id) {
|
||||
Feed selection = fla.getItem(position);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Selected Feed with title " + selection.getTitle());
|
||||
if (selection != null) {
|
||||
if (mActionMode != null) {
|
||||
mActionMode.finish();
|
||||
}
|
||||
fla.setSelectedItemIndex(position);
|
||||
selectedFeed = selection;
|
||||
mActionMode = ((ActionBarActivity) getActivity()).startSupportActionMode(FeedlistFragment.this);
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private AbsListView getMainView() {
|
||||
return (listView != null) ? listView : gridView;
|
||||
}
|
||||
|
||||
private void setEmptyViewIfListIsEmpty() {
|
||||
if (getMainView() != null && emptyView != null && feeds != null) {
|
||||
if (feeds.isEmpty()) {
|
||||
emptyView.setText(R.string.no_feeds_label);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,9 @@ package de.danoeh.antennapod.fragment;
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import de.danoeh.antennapod.feed.FeedItem;
|
||||
import de.danoeh.antennapod.storage.DBReader;
|
||||
import de.danoeh.antennapod.util.ShownotesProvider;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
@ -30,439 +33,423 @@ import android.webkit.WebViewClient;
|
||||
import android.widget.Toast;
|
||||
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.PodcastApp;
|
||||
import de.danoeh.antennapod.R;
|
||||
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;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/** Displays the description of a Playable object in a Webview. */
|
||||
public class ItemDescriptionFragment extends Fragment {
|
||||
|
||||
private static final String TAG = "ItemDescriptionFragment";
|
||||
private static final String TAG = "ItemDescriptionFragment";
|
||||
|
||||
private static final String PREF = "ItemDescriptionFragmentPrefs";
|
||||
private static final String PREF_SCROLL_Y = "prefScrollY";
|
||||
private static final String PREF_PLAYABLE_ID = "prefPlayableId";
|
||||
private static final String PREF = "ItemDescriptionFragmentPrefs";
|
||||
private static final String PREF_SCROLL_Y = "prefScrollY";
|
||||
private static final String PREF_PLAYABLE_ID = "prefPlayableId";
|
||||
|
||||
private static final String ARG_PLAYABLE = "arg.playable";
|
||||
private static final String ARG_PLAYABLE = "arg.playable";
|
||||
private static final String ARG_FEEDITEM_ID = "arg.feeditem";
|
||||
|
||||
private static final String ARG_FEED_ID = "arg.feedId";
|
||||
private static final String ARG_FEED_ITEM_ID = "arg.feeditemId";
|
||||
private static final String ARG_SAVE_STATE = "arg.saveState";
|
||||
private static final String ARG_SAVE_STATE = "arg.saveState";
|
||||
|
||||
private WebView webvDescription;
|
||||
private Playable media;
|
||||
private WebView webvDescription;
|
||||
|
||||
private FeedItem item;
|
||||
private ShownotesProvider shownotesProvider;
|
||||
private Playable media;
|
||||
|
||||
private AsyncTask<Void, Void, Void> webViewLoader;
|
||||
|
||||
private String shownotes;
|
||||
private AsyncTask<Void, Void, Void> webViewLoader;
|
||||
|
||||
/** URL that was selected via long-press. */
|
||||
private String selectedURL;
|
||||
/**
|
||||
* URL that was selected via long-press.
|
||||
*/
|
||||
private String selectedURL;
|
||||
|
||||
/**
|
||||
* True if Fragment should save its state (e.g. scrolling position) in a
|
||||
* shared preference.
|
||||
*/
|
||||
private boolean saveState;
|
||||
/**
|
||||
* True if Fragment should save its state (e.g. scrolling position) in a
|
||||
* shared preference.
|
||||
*/
|
||||
private boolean saveState;
|
||||
|
||||
public static ItemDescriptionFragment newInstance(Playable media,
|
||||
boolean saveState) {
|
||||
ItemDescriptionFragment f = new ItemDescriptionFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(ARG_PLAYABLE, media);
|
||||
args.putBoolean(ARG_SAVE_STATE, saveState);
|
||||
f.setArguments(args);
|
||||
return f;
|
||||
}
|
||||
public static ItemDescriptionFragment newInstance(Playable media,
|
||||
boolean saveState) {
|
||||
ItemDescriptionFragment f = new ItemDescriptionFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable(ARG_PLAYABLE, media);
|
||||
args.putBoolean(ARG_SAVE_STATE, saveState);
|
||||
f.setArguments(args);
|
||||
return f;
|
||||
}
|
||||
|
||||
public static ItemDescriptionFragment newInstance(FeedItem item,
|
||||
boolean saveState) {
|
||||
ItemDescriptionFragment f = new ItemDescriptionFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putLong(ARG_FEED_ID, item.getFeed().getId());
|
||||
args.putLong(ARG_FEED_ITEM_ID, item.getId());
|
||||
args.putBoolean(ARG_SAVE_STATE, saveState);
|
||||
f.setArguments(args);
|
||||
return f;
|
||||
}
|
||||
public static ItemDescriptionFragment newInstance(FeedItem item, boolean saveState) {
|
||||
ItemDescriptionFragment f = new ItemDescriptionFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putLong(ARG_FEEDITEM_ID, item.getId());
|
||||
args.putBoolean(ARG_SAVE_STATE, saveState);
|
||||
f.setArguments(args);
|
||||
return f;
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Creating view");
|
||||
webvDescription = new WebView(getActivity());
|
||||
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.getSettings().setUseWideViewPort(false);
|
||||
webvDescription.getSettings().setLayoutAlgorithm(
|
||||
LayoutAlgorithm.NARROW_COLUMNS);
|
||||
webvDescription.getSettings().setLoadWithOverviewMode(true);
|
||||
webvDescription.setOnLongClickListener(webViewLongClickListener);
|
||||
webvDescription.setWebViewClient(new WebViewClient() {
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Creating view");
|
||||
webvDescription = new WebView(getActivity());
|
||||
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.getSettings().setUseWideViewPort(false);
|
||||
webvDescription.getSettings().setLayoutAlgorithm(
|
||||
LayoutAlgorithm.NARROW_COLUMNS);
|
||||
webvDescription.getSettings().setLoadWithOverviewMode(true);
|
||||
webvDescription.setOnLongClickListener(webViewLongClickListener);
|
||||
webvDescription.setWebViewClient(new WebViewClient() {
|
||||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Page finished");
|
||||
// Restoring the scroll position might not always work
|
||||
view.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Page finished");
|
||||
// Restoring the scroll position might not always work
|
||||
view.postDelayed(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
restoreFromPreference();
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
restoreFromPreference();
|
||||
}
|
||||
|
||||
}, 50);
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
|
||||
});
|
||||
registerForContextMenu(webvDescription);
|
||||
return webvDescription;
|
||||
}
|
||||
});
|
||||
registerForContextMenu(webvDescription);
|
||||
return webvDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
}
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Fragment attached");
|
||||
}
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Fragment attached");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Fragment detached");
|
||||
if (webViewLoader != null) {
|
||||
webViewLoader.cancel(true);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Fragment detached");
|
||||
if (webViewLoader != null) {
|
||||
webViewLoader.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Fragment destroyed");
|
||||
if (webViewLoader != null) {
|
||||
webViewLoader.cancel(true);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Fragment destroyed");
|
||||
if (webViewLoader != null) {
|
||||
webViewLoader.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Creating fragment");
|
||||
Bundle args = getArguments();
|
||||
saveState = args.getBoolean(ARG_SAVE_STATE, false);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Creating fragment");
|
||||
Bundle args = getArguments();
|
||||
saveState = args.getBoolean(ARG_SAVE_STATE, false);
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
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) {
|
||||
FeedManager.getInstance().loadExtraInformationOfItem(
|
||||
PodcastApp.getInstance(), item,
|
||||
new FeedManager.TaskCallback<String[]>() {
|
||||
@Override
|
||||
public void onCompletion(String[] result) {
|
||||
if (result[1] != null) {
|
||||
shownotes = result[1];
|
||||
} else {
|
||||
shownotes = result[0];
|
||||
}
|
||||
if (shownotes != null) {
|
||||
startLoader();
|
||||
}
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
Bundle args = getArguments();
|
||||
if (args.containsKey(ARG_PLAYABLE)) {
|
||||
media = args.getParcelable(ARG_PLAYABLE);
|
||||
shownotesProvider = media;
|
||||
startLoader();
|
||||
} else if (args.containsKey(ARG_FEEDITEM_ID)) {
|
||||
AsyncTask<Void, Void, FeedItem> itemLoadTask = new AsyncTask<Void, Void, FeedItem>() {
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
shownotes = item.getContentEncoded();
|
||||
startLoader();
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Error in onViewCreated: Item and media were null");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected FeedItem doInBackground(Void... voids) {
|
||||
return DBReader.getFeedItem(getActivity(), getArguments().getLong(ARG_FEEDITEM_ID));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(FeedItem feedItem) {
|
||||
super.onPostExecute(feedItem);
|
||||
shownotesProvider = feedItem;
|
||||
startLoader();
|
||||
}
|
||||
};
|
||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
itemLoadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
itemLoadTask.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private void startLoader() {
|
||||
webViewLoader = createLoader();
|
||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
webViewLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
webViewLoader.execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CSS style of the Webview.
|
||||
*
|
||||
* @param textColor
|
||||
* the default color to use for the text in the webview. This
|
||||
* value is inserted directly into the CSS String.
|
||||
* */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
WebView.HitTestResult r = webvDescription.getHitTestResult();
|
||||
if (r != null
|
||||
&& r.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"Link of webview was long-pressed. Extra: "
|
||||
+ r.getExtra());
|
||||
selectedURL = r.getExtra();
|
||||
webvDescription.showContextMenu();
|
||||
return true;
|
||||
}
|
||||
selectedURL = null;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@SuppressLint("NewApi")
|
||||
private void startLoader() {
|
||||
webViewLoader = createLoader();
|
||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
webViewLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
} else {
|
||||
webViewLoader.execute();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
boolean handled = selectedURL != null;
|
||||
if (selectedURL != null) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.open_in_browser_item:
|
||||
Uri uri = Uri.parse(selectedURL);
|
||||
getActivity()
|
||||
.startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
||||
break;
|
||||
case R.id.share_url_item:
|
||||
ShareUtils.shareLink(getActivity(), selectedURL);
|
||||
break;
|
||||
case R.id.copy_url_item:
|
||||
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
||||
ClipData clipData = ClipData.newPlainText(selectedURL,
|
||||
selectedURL);
|
||||
android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity()
|
||||
.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cm.setPrimaryClip(clipData);
|
||||
} else {
|
||||
android.text.ClipboardManager cm = (android.text.ClipboardManager) getActivity()
|
||||
.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cm.setText(selectedURL);
|
||||
}
|
||||
Toast t = Toast.makeText(getActivity(),
|
||||
R.string.copied_url_msg, Toast.LENGTH_SHORT);
|
||||
t.show();
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
break;
|
||||
/**
|
||||
* Return the CSS style of the Webview.
|
||||
*
|
||||
* @param textColor the default color to use for the text in the webview. This
|
||||
* value is inserted directly into the CSS String.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
selectedURL = null;
|
||||
}
|
||||
return handled;
|
||||
private View.OnLongClickListener webViewLongClickListener = new View.OnLongClickListener() {
|
||||
|
||||
}
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
WebView.HitTestResult r = webvDescription.getHitTestResult();
|
||||
if (r != null
|
||||
&& r.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"Link of webview was long-pressed. Extra: "
|
||||
+ r.getExtra());
|
||||
selectedURL = r.getExtra();
|
||||
webvDescription.showContextMenu();
|
||||
return true;
|
||||
}
|
||||
selectedURL = null;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
if (selectedURL != null) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
menu.add(Menu.NONE, R.id.open_in_browser_item, Menu.NONE,
|
||||
R.string.open_in_browser_label);
|
||||
menu.add(Menu.NONE, R.id.copy_url_item, Menu.NONE,
|
||||
R.string.copy_url_label);
|
||||
menu.add(Menu.NONE, R.id.share_url_item, Menu.NONE,
|
||||
R.string.share_url_label);
|
||||
menu.setHeaderTitle(selectedURL);
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("deprecation")
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
boolean handled = selectedURL != null;
|
||||
if (selectedURL != null) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.open_in_browser_item:
|
||||
Uri uri = Uri.parse(selectedURL);
|
||||
getActivity()
|
||||
.startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
||||
break;
|
||||
case R.id.share_url_item:
|
||||
ShareUtils.shareLink(getActivity(), selectedURL);
|
||||
break;
|
||||
case R.id.copy_url_item:
|
||||
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
||||
ClipData clipData = ClipData.newPlainText(selectedURL,
|
||||
selectedURL);
|
||||
android.content.ClipboardManager cm = (android.content.ClipboardManager) getActivity()
|
||||
.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cm.setPrimaryClip(clipData);
|
||||
} else {
|
||||
android.text.ClipboardManager cm = (android.text.ClipboardManager) getActivity()
|
||||
.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
cm.setText(selectedURL);
|
||||
}
|
||||
Toast t = Toast.makeText(getActivity(),
|
||||
R.string.copied_url_msg, Toast.LENGTH_SHORT);
|
||||
t.show();
|
||||
break;
|
||||
default:
|
||||
handled = false;
|
||||
break;
|
||||
|
||||
private AsyncTask<Void, Void, Void> createLoader() {
|
||||
return new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
super.onCancelled();
|
||||
if (getActivity() != null) {
|
||||
}
|
||||
selectedURL = null;
|
||||
}
|
||||
return handled;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
if (selectedURL != null) {
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
menu.add(Menu.NONE, R.id.open_in_browser_item, Menu.NONE,
|
||||
R.string.open_in_browser_label);
|
||||
menu.add(Menu.NONE, R.id.copy_url_item, Menu.NONE,
|
||||
R.string.copy_url_label);
|
||||
menu.add(Menu.NONE, R.id.share_url_item, Menu.NONE,
|
||||
R.string.share_url_label);
|
||||
menu.setHeaderTitle(selectedURL);
|
||||
}
|
||||
}
|
||||
|
||||
private AsyncTask<Void, Void, Void> createLoader() {
|
||||
return new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
super.onCancelled();
|
||||
if (getActivity() != null) {
|
||||
((ActionBarActivity) getActivity())
|
||||
.setSupportProgressBarIndeterminateVisibility(false);
|
||||
}
|
||||
webViewLoader = null;
|
||||
}
|
||||
.setSupportProgressBarIndeterminateVisibility(false);
|
||||
}
|
||||
webViewLoader = null;
|
||||
}
|
||||
|
||||
String data;
|
||||
String data;
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
super.onPostExecute(result);
|
||||
// /webvDescription.loadData(url, "text/html", "utf-8");
|
||||
webvDescription.loadDataWithBaseURL(null, data, "text/html",
|
||||
"utf-8", "about:blank");
|
||||
if (getActivity() != null) {
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
super.onPostExecute(result);
|
||||
// /webvDescription.loadData(url, "text/html", "utf-8");
|
||||
webvDescription.loadDataWithBaseURL(null, data, "text/html",
|
||||
"utf-8", "about:blank");
|
||||
if (getActivity() != null) {
|
||||
((ActionBarActivity) getActivity())
|
||||
.setSupportProgressBarIndeterminateVisibility(false);
|
||||
}
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Webview loaded");
|
||||
webViewLoader = null;
|
||||
}
|
||||
.setSupportProgressBarIndeterminateVisibility(false);
|
||||
}
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Webview loaded");
|
||||
webViewLoader = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
if (getActivity() != null) {
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
if (getActivity() != null) {
|
||||
((ActionBarActivity) getActivity())
|
||||
.setSupportProgressBarIndeterminateVisibility(true);
|
||||
}
|
||||
}
|
||||
.setSupportProgressBarIndeterminateVisibility(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Loading Webview");
|
||||
data = "";
|
||||
data = StringEscapeUtils.unescapeHtml4(shownotes);
|
||||
Activity activity = getActivity();
|
||||
if (activity != null) {
|
||||
TypedArray res = getActivity()
|
||||
.getTheme()
|
||||
.obtainStyledAttributes(
|
||||
new int[] { android.R.attr.textColorPrimary });
|
||||
int colorResource = res.getColor(0, 0);
|
||||
String colorString = String.format("#%06X",
|
||||
0xFFFFFF & colorResource);
|
||||
Log.i(TAG, "text color: " + colorString);
|
||||
res.recycle();
|
||||
data = applyWebviewStyle(colorString, data);
|
||||
} else {
|
||||
cancel(true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Loading Webview");
|
||||
try {
|
||||
Callable<String> shownotesLoadTask = shownotesProvider.loadShownotes();
|
||||
final String shownotes = shownotesLoadTask.call();
|
||||
|
||||
};
|
||||
}
|
||||
data = "";
|
||||
data = StringEscapeUtils.unescapeHtml4(shownotes);
|
||||
Activity activity = getActivity();
|
||||
if (activity != null) {
|
||||
TypedArray res = getActivity()
|
||||
.getTheme()
|
||||
.obtainStyledAttributes(
|
||||
new int[]{android.R.attr.textColorPrimary});
|
||||
int colorResource = res.getColor(0, 0);
|
||||
String colorString = String.format("#%06X",
|
||||
0xFFFFFF & colorResource);
|
||||
Log.i(TAG, "text color: " + colorString);
|
||||
res.recycle();
|
||||
data = applyWebviewStyle(colorString, data);
|
||||
} else {
|
||||
cancel(true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
savePreference();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void savePreference() {
|
||||
if (saveState) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Saving preferences");
|
||||
SharedPreferences prefs = getActivity().getSharedPreferences(PREF,
|
||||
Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
if (media != null && webvDescription != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"Saving scroll position: "
|
||||
+ webvDescription.getScrollY());
|
||||
editor.putInt(PREF_SCROLL_Y, webvDescription.getScrollY());
|
||||
editor.putString(PREF_PLAYABLE_ID, media.getIdentifier()
|
||||
.toString());
|
||||
} else {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"savePreferences was called while media or webview was null");
|
||||
editor.putInt(PREF_SCROLL_Y, -1);
|
||||
editor.putString(PREF_PLAYABLE_ID, "");
|
||||
}
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
savePreference();
|
||||
}
|
||||
|
||||
private boolean restoreFromPreference() {
|
||||
if (saveState) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Restoring from preferences");
|
||||
Activity activity = getActivity();
|
||||
if (activity != null) {
|
||||
SharedPreferences prefs = activity.getSharedPreferences(
|
||||
PREF, Activity.MODE_PRIVATE);
|
||||
String id = prefs.getString(PREF_PLAYABLE_ID, "");
|
||||
int scrollY = prefs.getInt(PREF_SCROLL_Y, -1);
|
||||
if (scrollY != -1 && media != null
|
||||
&& id.equals(media.getIdentifier().toString())
|
||||
&& webvDescription != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Restored scroll Position: " + scrollY);
|
||||
webvDescription.scrollTo(webvDescription.getScrollX(),
|
||||
scrollY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private void savePreference() {
|
||||
if (saveState) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Saving preferences");
|
||||
SharedPreferences prefs = getActivity().getSharedPreferences(PREF,
|
||||
Activity.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
if (media != null && webvDescription != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"Saving scroll position: "
|
||||
+ webvDescription.getScrollY());
|
||||
editor.putInt(PREF_SCROLL_Y, webvDescription.getScrollY());
|
||||
editor.putString(PREF_PLAYABLE_ID, media.getIdentifier()
|
||||
.toString());
|
||||
} else {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"savePreferences was called while media or webview was null");
|
||||
editor.putInt(PREF_SCROLL_Y, -1);
|
||||
editor.putString(PREF_PLAYABLE_ID, "");
|
||||
}
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean restoreFromPreference() {
|
||||
if (saveState) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Restoring from preferences");
|
||||
Activity activity = getActivity();
|
||||
if (activity != null) {
|
||||
SharedPreferences prefs = activity.getSharedPreferences(
|
||||
PREF, Activity.MODE_PRIVATE);
|
||||
String id = prefs.getString(PREF_PLAYABLE_ID, "");
|
||||
int scrollY = prefs.getInt(PREF_SCROLL_Y, -1);
|
||||
if (scrollY != -1 && media != null
|
||||
&& id.equals(media.getIdentifier().toString())
|
||||
&& webvDescription != null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Restored scroll Position: " + scrollY);
|
||||
webvDescription.scrollTo(webvDescription.getScrollX(),
|
||||
scrollY);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package de.danoeh.antennapod.fragment;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
@ -14,22 +16,27 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
|
||||
import android.widget.TextView;
|
||||
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.ItemviewActivity;
|
||||
import de.danoeh.antennapod.adapter.ActionButtonCallback;
|
||||
import de.danoeh.antennapod.adapter.DefaultFeedItemlistAdapter;
|
||||
import de.danoeh.antennapod.adapter.InternalFeedItemlistAdapter;
|
||||
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;
|
||||
import de.danoeh.antennapod.service.download.DownloadService;
|
||||
import de.danoeh.antennapod.storage.DBReader;
|
||||
import de.danoeh.antennapod.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.util.QueueAccess;
|
||||
import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/** Displays a list of FeedItems. */
|
||||
@SuppressLint("ValidFragment")
|
||||
public class ItemlistFragment extends ListFragment {
|
||||
@ -43,12 +50,10 @@ public class ItemlistFragment extends ListFragment {
|
||||
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 InternalFeedItemlistAdapter fila;
|
||||
protected FeedManager manager = FeedManager.getInstance();
|
||||
protected DownloadRequester requester = DownloadRequester.getInstance();
|
||||
|
||||
private DefaultFeedItemlistAdapter.ItemAccess itemAccess;
|
||||
|
||||
private Feed feed;
|
||||
protected List<Long> queue;
|
||||
|
||||
protected FeedItem selectedItem = null;
|
||||
protected boolean contextMenuClosed = true;
|
||||
@ -56,10 +61,8 @@ public class ItemlistFragment extends ListFragment {
|
||||
/** Argument for FeeditemlistAdapter */
|
||||
protected boolean showFeedtitle;
|
||||
|
||||
public ItemlistFragment(DefaultFeedItemlistAdapter.ItemAccess itemAccess,
|
||||
boolean showFeedtitle) {
|
||||
public ItemlistFragment(boolean showFeedtitle) {
|
||||
super();
|
||||
this.itemAccess = itemAccess;
|
||||
this.showFeedtitle = showFeedtitle;
|
||||
}
|
||||
|
||||
@ -83,6 +86,30 @@ public class ItemlistFragment extends ListFragment {
|
||||
return i;
|
||||
}
|
||||
|
||||
private InternalFeedItemlistAdapter.ItemAccess itemAccessRef;
|
||||
protected InternalFeedItemlistAdapter.ItemAccess itemAccess() {
|
||||
if (itemAccessRef == null) {
|
||||
itemAccessRef = new InternalFeedItemlistAdapter.ItemAccess() {
|
||||
|
||||
@Override
|
||||
public FeedItem getItem(int position) {
|
||||
return (feed != null) ? feed.getItemAtIndex(true, position) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return (feed != null) ? feed.getNumOfItems(true) : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInQueue(FeedItem item) {
|
||||
return (queue != null) && queue.contains(item.getId());
|
||||
}
|
||||
};
|
||||
}
|
||||
return itemAccessRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
@ -92,27 +119,71 @@ public class ItemlistFragment extends ListFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (itemAccess == null) {
|
||||
long feedId = getArguments().getLong(ARGUMENT_FEED_ID);
|
||||
final Feed feed = FeedManager.getInstance().getFeed(feedId);
|
||||
this.feed = feed;
|
||||
itemAccess = new DefaultFeedItemlistAdapter.ItemAccess() {
|
||||
|
||||
@Override
|
||||
public FeedItem getItem(int position) {
|
||||
return feed.getItemAtIndex(true, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return feed.getNumOfItems(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
loadData();
|
||||
}
|
||||
|
||||
protected void loadData() {
|
||||
final long feedId;
|
||||
if (feed == null) {
|
||||
feedId = getArguments().getLong(ARGUMENT_FEED_ID);
|
||||
} else {
|
||||
feedId = feed.getId();
|
||||
}
|
||||
AsyncTask<Long, Void, Feed> loadTask = new AsyncTask<Long, Void, Feed>(){
|
||||
private volatile List<Long> queueRef;
|
||||
|
||||
@Override
|
||||
protected Feed doInBackground(Long... longs) {
|
||||
Context context = ItemlistFragment.this.getActivity();
|
||||
if (context != null) {
|
||||
Feed result = DBReader.getFeed(context, longs[0]);
|
||||
if (result != null) {
|
||||
result.setItems(DBReader.getFeedItemList(context, result));
|
||||
queueRef = DBReader.getQueueIDList(context);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Feed result) {
|
||||
super.onPostExecute(result);
|
||||
if (result != null && result.getItems() != null) {
|
||||
feed = result;
|
||||
if (queueRef != null) {
|
||||
queue = queueRef;
|
||||
} else {
|
||||
Log.e(TAG, "Could not load queue");
|
||||
}
|
||||
if (result.getItems().isEmpty()) {
|
||||
}
|
||||
setEmptyViewIfListIsEmpty();
|
||||
if (fila != null) {
|
||||
fila.notifyDataSetChanged();
|
||||
}
|
||||
} else {
|
||||
if (result == null) {
|
||||
Log.e(TAG, "Could not load feed with id " + feedId);
|
||||
} else if (result.getItems() == null) {
|
||||
Log.e(TAG, "Could not load feed items");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
loadTask.execute(feedId);
|
||||
}
|
||||
|
||||
private void setEmptyViewIfListIsEmpty() {
|
||||
if (getListView() != null && feed != null && feed.getItems() != null) {
|
||||
if (feed.getItems().isEmpty()) {
|
||||
((TextView) getActivity().findViewById(android.R.id.empty)).setText(R.string.no_items_label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected InternalFeedItemlistAdapter createListAdapter() {
|
||||
return new InternalFeedItemlistAdapter(getActivity(), itemAccess,
|
||||
return new InternalFeedItemlistAdapter(getActivity(), itemAccess(),
|
||||
adapterCallback, showFeedtitle);
|
||||
}
|
||||
|
||||
@ -162,7 +233,9 @@ public class ItemlistFragment extends ListFragment {
|
||||
if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) {
|
||||
updateProgressBarVisibility();
|
||||
} else {
|
||||
fila.notifyDataSetChanged();
|
||||
if (feed != null) {
|
||||
loadData();
|
||||
}
|
||||
updateProgressBarVisibility();
|
||||
}
|
||||
}
|
||||
@ -218,13 +291,13 @@ public class ItemlistFragment extends ListFragment {
|
||||
|
||||
menu.setHeaderTitle(selectedItem.getTitle());
|
||||
FeedItemMenuHandler.onPrepareMenu(
|
||||
new FeedItemMenuHandler.MenuInterface() {
|
||||
new FeedItemMenuHandler.MenuInterface() {
|
||||
|
||||
@Override
|
||||
public void setItemVisibility(int id, boolean visible) {
|
||||
menu.findItem(id).setVisible(visible);
|
||||
}
|
||||
}, selectedItem, false);
|
||||
@Override
|
||||
public void setItemVisibility(int id, boolean visible) {
|
||||
menu.findItem(id).setVisible(visible);
|
||||
}
|
||||
}, selectedItem, false, QueueAccess.IDListAccess(queue));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,53 @@
|
||||
package de.danoeh.antennapod.fragment;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.adapter.DefaultFeedItemlistAdapter;
|
||||
import de.danoeh.antennapod.adapter.InternalFeedItemlistAdapter;
|
||||
import de.danoeh.antennapod.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.feed.FeedItem;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.storage.DBReader;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class PlaybackHistoryFragment extends ItemlistFragment {
|
||||
private static final String TAG = "PlaybackHistoryFragment";
|
||||
|
||||
private List<FeedItem> playbackHistory;
|
||||
|
||||
public PlaybackHistoryFragment() {
|
||||
super(new DefaultFeedItemlistAdapter.ItemAccess() {
|
||||
|
||||
@Override
|
||||
public FeedItem getItem(int position) {
|
||||
return FeedManager.getInstance().getPlaybackHistoryItemIndex(
|
||||
position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return FeedManager.getInstance().getPlaybackHistorySize();
|
||||
}
|
||||
}, true);
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
InternalFeedItemlistAdapter.ItemAccess itemAccessRef;
|
||||
@Override
|
||||
protected InternalFeedItemlistAdapter.ItemAccess itemAccess() {
|
||||
if (itemAccessRef == null) {
|
||||
itemAccessRef = new InternalFeedItemlistAdapter.ItemAccess() {
|
||||
|
||||
@Override
|
||||
public FeedItem getItem(int position) {
|
||||
return (playbackHistory != null) ? playbackHistory.get(position) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return (playbackHistory != null) ? playbackHistory.size() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInQueue(FeedItem item) {
|
||||
return (queue != null) ? queue.contains(item.getId()) : false;
|
||||
}
|
||||
};
|
||||
}
|
||||
return itemAccessRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
EventDistributor.getInstance().register(historyUpdate);
|
||||
@ -46,10 +66,48 @@ public class PlaybackHistoryFragment extends ItemlistFragment {
|
||||
if ((EventDistributor.PLAYBACK_HISTORY_UPDATE & arg) != 0) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Received content update");
|
||||
fila.notifyDataSetChanged();
|
||||
loadData();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void loadData() {
|
||||
AsyncTask<Void, Void, Void> loadTask = new AsyncTask<Void, Void, Void>() {
|
||||
private volatile List<FeedItem> phRef;
|
||||
private volatile List<Long> queueRef;
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
Context context = PlaybackHistoryFragment.this.getActivity();
|
||||
if (context != null) {
|
||||
queueRef = DBReader.getQueueIDList(context);
|
||||
phRef = DBReader.getPlaybackHistory(context);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
super.onPostExecute(aVoid);
|
||||
if (queueRef != null && phRef != null) {
|
||||
queue = queueRef;
|
||||
playbackHistory = phRef;
|
||||
Log.i(TAG, "Number of items in playback history: " + playbackHistory.size());
|
||||
if (fila != null) {
|
||||
fila.notifyDataSetChanged();
|
||||
}
|
||||
} else {
|
||||
if (queueRef == null) {
|
||||
Log.e(TAG, "Could not load queue");
|
||||
}
|
||||
if (phRef == null) {
|
||||
Log.e(TAG, "Could not load playback history");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
loadTask.execute();
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.storage.DBTasks;
|
||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.util.NetworkUtils;
|
||||
|
||||
@ -27,7 +27,7 @@ public class ConnectivityActionReceiver extends BroadcastReceiver {
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
FeedManager.getInstance()
|
||||
DBTasks
|
||||
.autodownloadUndownloadedItems(context);
|
||||
}
|
||||
}.start();
|
||||
|
@ -7,8 +7,8 @@ import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.storage.DBTasks;
|
||||
|
||||
/** Refreshes all feeds when it receives an intent */
|
||||
public class FeedUpdateReceiver extends BroadcastReceiver {
|
||||
@ -22,7 +22,7 @@ public class FeedUpdateReceiver extends BroadcastReceiver {
|
||||
Log.d(TAG, "Received intent");
|
||||
boolean mobileUpdate = UserPreferences.isAllowMobileUpdate();
|
||||
if (mobileUpdate || connectedToWifi(context)) {
|
||||
FeedManager.getInstance().refreshExpiredFeeds(context);
|
||||
DBTasks.refreshExpiredFeeds(context);
|
||||
} else {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
|
File diff suppressed because it is too large
Load Diff
177
src/de/danoeh/antennapod/service/download/DownloadRequest.java
Normal file
177
src/de/danoeh/antennapod/service/download/DownloadRequest.java
Normal file
@ -0,0 +1,177 @@
|
||||
package de.danoeh.antennapod.service.download;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public class DownloadRequest implements Parcelable {
|
||||
|
||||
private final String destination;
|
||||
private final String source;
|
||||
private final String title;
|
||||
private final long feedfileId;
|
||||
private final int feedfileType;
|
||||
|
||||
protected int progressPercent;
|
||||
protected long soFar;
|
||||
protected long size;
|
||||
protected int statusMsg;
|
||||
|
||||
public DownloadRequest(String destination, String source, String title,
|
||||
long feedfileId, int feedfileType) {
|
||||
if (destination == null) {
|
||||
throw new IllegalArgumentException("Destination must not be null");
|
||||
}
|
||||
if (source == null) {
|
||||
throw new IllegalArgumentException("Source must not be null");
|
||||
}
|
||||
if (title == null) {
|
||||
throw new IllegalArgumentException("Title must not be null");
|
||||
}
|
||||
|
||||
this.destination = destination;
|
||||
this.source = source;
|
||||
this.title = title;
|
||||
this.feedfileId = feedfileId;
|
||||
this.feedfileType = feedfileType;
|
||||
}
|
||||
|
||||
private DownloadRequest(Parcel in) {
|
||||
destination = in.readString();
|
||||
source = in.readString();
|
||||
title = in.readString();
|
||||
feedfileId = in.readLong();
|
||||
feedfileType = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(destination);
|
||||
dest.writeString(source);
|
||||
dest.writeString(title);
|
||||
dest.writeLong(feedfileId);
|
||||
dest.writeInt(feedfileType);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<DownloadRequest> CREATOR = new Parcelable.Creator<DownloadRequest>() {
|
||||
public DownloadRequest createFromParcel(Parcel in) {
|
||||
return new DownloadRequest(in);
|
||||
}
|
||||
|
||||
public DownloadRequest[] newArray(int size) {
|
||||
return new DownloadRequest[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result
|
||||
+ ((destination == null) ? 0 : destination.hashCode());
|
||||
result = prime * result + (int) (feedfileId ^ (feedfileId >>> 32));
|
||||
result = prime * result + feedfileType;
|
||||
result = prime * result + progressPercent;
|
||||
result = prime * result + (int) (size ^ (size >>> 32));
|
||||
result = prime * result + (int) (soFar ^ (soFar >>> 32));
|
||||
result = prime * result + ((source == null) ? 0 : source.hashCode());
|
||||
result = prime * result + statusMsg;
|
||||
result = prime * result + ((title == null) ? 0 : title.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
DownloadRequest other = (DownloadRequest) obj;
|
||||
if (destination == null) {
|
||||
if (other.destination != null)
|
||||
return false;
|
||||
} else if (!destination.equals(other.destination))
|
||||
return false;
|
||||
if (feedfileId != other.feedfileId)
|
||||
return false;
|
||||
if (feedfileType != other.feedfileType)
|
||||
return false;
|
||||
if (progressPercent != other.progressPercent)
|
||||
return false;
|
||||
if (size != other.size)
|
||||
return false;
|
||||
if (soFar != other.soFar)
|
||||
return false;
|
||||
if (source == null) {
|
||||
if (other.source != null)
|
||||
return false;
|
||||
} else if (!source.equals(other.source))
|
||||
return false;
|
||||
if (statusMsg != other.statusMsg)
|
||||
return false;
|
||||
if (title == null) {
|
||||
if (other.title != null)
|
||||
return false;
|
||||
} else if (!title.equals(other.title))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public long getFeedfileId() {
|
||||
return feedfileId;
|
||||
}
|
||||
|
||||
public int getFeedfileType() {
|
||||
return feedfileType;
|
||||
}
|
||||
|
||||
public int getProgressPercent() {
|
||||
return progressPercent;
|
||||
}
|
||||
|
||||
public void setProgressPercent(int progressPercent) {
|
||||
this.progressPercent = progressPercent;
|
||||
}
|
||||
|
||||
public long getSoFar() {
|
||||
return soFar;
|
||||
}
|
||||
|
||||
public void setSoFar(long soFar) {
|
||||
this.soFar = soFar;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public int getStatusMsg() {
|
||||
return statusMsg;
|
||||
}
|
||||
|
||||
public void setStatusMsg(int statusMsg) {
|
||||
this.statusMsg = statusMsg;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
package de.danoeh.antennapod.asynctask;
|
||||
package de.danoeh.antennapod.service.download;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -13,10 +13,6 @@ public class DownloadStatus {
|
||||
*/
|
||||
public static final int SIZE_UNKNOWN = -1;
|
||||
|
||||
public Date getCompletionDate() {
|
||||
return completionDate;
|
||||
}
|
||||
|
||||
// ----------------------------------- ATTRIBUTES STORED IN DB
|
||||
/** Unique id for storing the object in database. */
|
||||
protected long id;
|
||||
@ -34,7 +30,7 @@ public class DownloadStatus {
|
||||
protected String reasonDetailed;
|
||||
protected boolean successful;
|
||||
protected Date completionDate;
|
||||
protected FeedFile feedfile;
|
||||
protected long feedfileId;
|
||||
/**
|
||||
* Is used to determine the type of the feedfile even if the feedfile does
|
||||
* not exist anymore. The value should be FEEDFILETYPE_FEED,
|
||||
@ -43,33 +39,17 @@ public class DownloadStatus {
|
||||
protected int feedfileType;
|
||||
|
||||
// ------------------------------------ NOT STORED IN DB
|
||||
protected int progressPercent;
|
||||
protected long soFar;
|
||||
protected long size;
|
||||
protected int statusMsg;
|
||||
protected boolean done;
|
||||
protected boolean cancelled;
|
||||
|
||||
public DownloadStatus(FeedFile feedfile, String title) {
|
||||
this.feedfile = feedfile;
|
||||
if (feedfile != null) {
|
||||
feedfileType = feedfile.getTypeAsInt();
|
||||
}
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/** Constructor for restoring Download status entries from DB. */
|
||||
public DownloadStatus(long id, String title, FeedFile feedfile,
|
||||
public DownloadStatus(long id, String title, long feedfileId,
|
||||
int feedfileType, boolean successful, DownloadError reason,
|
||||
Date completionDate, String reasonDetailed) {
|
||||
progressPercent = 100;
|
||||
soFar = 0;
|
||||
size = 0;
|
||||
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.done = true;
|
||||
this.feedfile = feedfile;
|
||||
this.feedfileId = feedfileId;
|
||||
this.reason = reason;
|
||||
this.successful = successful;
|
||||
this.completionDate = completionDate;
|
||||
@ -77,11 +57,49 @@ public class DownloadStatus {
|
||||
this.feedfileType = feedfileType;
|
||||
}
|
||||
|
||||
public DownloadStatus(DownloadRequest request, DownloadError reason,
|
||||
boolean successful, boolean cancelled, String reasonDetailed) {
|
||||
if (request == null) {
|
||||
throw new IllegalArgumentException("request must not be null");
|
||||
}
|
||||
this.title = request.getTitle();
|
||||
this.feedfileId = request.getFeedfileId();
|
||||
this.feedfileType = request.getFeedfileType();
|
||||
this.reason = reason;
|
||||
this.successful = successful;
|
||||
this.cancelled = cancelled;
|
||||
this.reasonDetailed = reasonDetailed;
|
||||
this.completionDate = new Date();
|
||||
}
|
||||
|
||||
/** Constructor for creating new completed downloads. */
|
||||
public DownloadStatus(FeedFile feedfile, String title, DownloadError reason,
|
||||
boolean successful, String reasonDetailed) {
|
||||
this(0, title, feedfile, feedfile.getTypeAsInt(), successful, reason,
|
||||
new Date(), reasonDetailed);
|
||||
if (feedfile == null) {
|
||||
throw new IllegalArgumentException("feedfile must not be null");
|
||||
}
|
||||
|
||||
this.title = title;
|
||||
this.done = true;
|
||||
this.feedfileId = feedfile.getId();
|
||||
this.feedfileType = feedfile.getTypeAsInt();
|
||||
this.reason = reason;
|
||||
this.successful = successful;
|
||||
this.completionDate = new Date();
|
||||
this.reasonDetailed = reasonDetailed;
|
||||
}
|
||||
|
||||
/** Constructor for creating new completed downloads. */
|
||||
public DownloadStatus(long feedfileId, int feedfileType, String title,
|
||||
DownloadError reason, boolean successful, String reasonDetailed) {
|
||||
this.title = title;
|
||||
this.done = true;
|
||||
this.feedfileId = feedfileId;
|
||||
this.feedfileType = feedfileType;
|
||||
this.reason = reason;
|
||||
this.successful = successful;
|
||||
this.completionDate = new Date();
|
||||
this.reasonDetailed = reasonDetailed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -89,68 +107,50 @@ public class DownloadStatus {
|
||||
return "DownloadStatus [id=" + id + ", title=" + title + ", reason="
|
||||
+ reason + ", reasonDetailed=" + reasonDetailed
|
||||
+ ", successful=" + successful + ", completionDate="
|
||||
+ completionDate + ", feedfile=" + feedfile + ", feedfileType="
|
||||
+ feedfileType + ", progressPercent=" + progressPercent
|
||||
+ ", soFar=" + soFar + ", size=" + size + ", statusMsg="
|
||||
+ statusMsg + ", done=" + done + ", cancelled=" + cancelled
|
||||
+ "]";
|
||||
+ completionDate + ", feedfileId=" + feedfileId
|
||||
+ ", feedfileType=" + feedfileType + ", done=" + done
|
||||
+ ", cancelled=" + cancelled + "]";
|
||||
}
|
||||
|
||||
public FeedFile getFeedFile() {
|
||||
return feedfile;
|
||||
}
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getProgressPercent() {
|
||||
return progressPercent;
|
||||
}
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public long getSoFar() {
|
||||
return soFar;
|
||||
}
|
||||
public DownloadError getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
public long getSize() {
|
||||
return size;
|
||||
}
|
||||
public String getReasonDetailed() {
|
||||
return reasonDetailed;
|
||||
}
|
||||
|
||||
public int getStatusMsg() {
|
||||
return statusMsg;
|
||||
}
|
||||
public boolean isSuccessful() {
|
||||
return successful;
|
||||
}
|
||||
|
||||
public DownloadError getReason() {
|
||||
return reason;
|
||||
}
|
||||
public Date getCompletionDate() {
|
||||
return completionDate;
|
||||
}
|
||||
|
||||
public boolean isSuccessful() {
|
||||
return successful;
|
||||
}
|
||||
public long getFeedfileId() {
|
||||
return feedfileId;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
public int getFeedfileType() {
|
||||
return feedfileType;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
public boolean isDone() {
|
||||
return done;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return done;
|
||||
}
|
||||
|
||||
public void setProgressPercent(int progressPercent) {
|
||||
this.progressPercent = progressPercent;
|
||||
}
|
||||
|
||||
public void setSoFar(long soFar) {
|
||||
this.soFar = soFar;
|
||||
}
|
||||
|
||||
public void setSize(long size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public void setStatusMsg(int statusMsg) {
|
||||
this.statusMsg = statusMsg;
|
||||
}
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
public void setSuccessful() {
|
||||
this.successful = true;
|
||||
@ -171,36 +171,11 @@ public class DownloadStatus {
|
||||
this.cancelled = true;
|
||||
}
|
||||
|
||||
public void setCompletionDate(Date completionDate) {
|
||||
this.completionDate = completionDate;
|
||||
}
|
||||
public void setCompletionDate(Date completionDate) {
|
||||
this.completionDate = completionDate;
|
||||
}
|
||||
|
||||
public String getReasonDetailed() {
|
||||
return reasonDetailed;
|
||||
}
|
||||
|
||||
public void setReasonDetailed(String reasonDetailed) {
|
||||
this.reasonDetailed = reasonDetailed;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public int getFeedfileType() {
|
||||
return feedfileType;
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
public void setCancelled(boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
|
||||
}
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
@ -1,49 +1,50 @@
|
||||
package de.danoeh.antennapod.service.download;
|
||||
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/** Downloads files */
|
||||
public abstract class Downloader extends Thread {
|
||||
public abstract class Downloader implements Callable<Downloader> {
|
||||
private static final String TAG = "Downloader";
|
||||
private DownloaderCallback downloaderCallback;
|
||||
|
||||
protected boolean finished;
|
||||
protected volatile boolean finished;
|
||||
|
||||
protected volatile boolean cancelled;
|
||||
|
||||
protected volatile DownloadStatus status;
|
||||
protected DownloadRequest request;
|
||||
protected DownloadStatus result;
|
||||
|
||||
public Downloader(DownloaderCallback downloaderCallback,
|
||||
DownloadStatus status) {
|
||||
public Downloader(DownloadRequest request) {
|
||||
super();
|
||||
this.downloaderCallback = downloaderCallback;
|
||||
this.status = status;
|
||||
this.status.setStatusMsg(R.string.download_pending);
|
||||
this.request = request;
|
||||
this.request.setStatusMsg(R.string.download_pending);
|
||||
this.cancelled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method must be called when the download was completed, failed, or
|
||||
* was cancelled
|
||||
*/
|
||||
protected void finish() {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
downloaderCallback.onDownloadCompleted(this);
|
||||
}
|
||||
this.result = new DownloadStatus(request, null, false, false, null);
|
||||
}
|
||||
|
||||
protected abstract void download();
|
||||
|
||||
@Override
|
||||
public final void run() {
|
||||
public final Downloader call() {
|
||||
download();
|
||||
finish();
|
||||
if (result == null) {
|
||||
throw new IllegalStateException(
|
||||
"Downloader hasn't created DownloadStatus object");
|
||||
}
|
||||
finished = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownloadStatus getStatus() {
|
||||
return status;
|
||||
public DownloadRequest getDownloadRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public DownloadStatus getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
return finished;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
|
@ -26,7 +26,6 @@ import android.util.Log;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.PodcastApp;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
||||
import de.danoeh.antennapod.util.DownloadError;
|
||||
import de.danoeh.antennapod.util.StorageUtils;
|
||||
|
||||
@ -39,9 +38,8 @@ public class HttpDownloader extends Downloader {
|
||||
private static final int CONNECTION_TIMEOUT = 30000;
|
||||
private static final int SOCKET_TIMEOUT = 30000;
|
||||
|
||||
public HttpDownloader(DownloaderCallback downloaderCallback,
|
||||
DownloadStatus status) {
|
||||
super(downloaderCallback, status);
|
||||
public HttpDownloader(DownloadRequest request) {
|
||||
super(request);
|
||||
}
|
||||
|
||||
private DefaultHttpClient createHttpClient() {
|
||||
@ -63,11 +61,10 @@ public class HttpDownloader extends Downloader {
|
||||
@Override
|
||||
protected void download() {
|
||||
DefaultHttpClient httpClient = null;
|
||||
BufferedOutputStream out = null;
|
||||
OutputStream out = null;
|
||||
InputStream connection = null;
|
||||
try {
|
||||
HttpGet httpGet = new HttpGet(status.getFeedFile()
|
||||
.getDownload_url());
|
||||
HttpGet httpGet = new HttpGet(request.getSource());
|
||||
httpClient = createHttpClient();
|
||||
HttpResponse response = httpClient.execute(httpGet);
|
||||
HttpEntity httpEntity = response.getEntity();
|
||||
@ -76,8 +73,7 @@ public class HttpDownloader extends Downloader {
|
||||
Log.d(TAG, "Response code is " + responseCode);
|
||||
if (responseCode == HttpURLConnection.HTTP_OK && httpEntity != null) {
|
||||
if (StorageUtils.storageAvailable(PodcastApp.getInstance())) {
|
||||
File destination = new File(status.getFeedFile()
|
||||
.getFile_url());
|
||||
File destination = new File(request.getDestination());
|
||||
if (!destination.exists()) {
|
||||
connection = AndroidHttpClient
|
||||
.getUngzippedContent(httpEntity);
|
||||
@ -86,34 +82,34 @@ public class HttpDownloader extends Downloader {
|
||||
destination));
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
int count = 0;
|
||||
status.setStatusMsg(R.string.download_running);
|
||||
request.setStatusMsg(R.string.download_running);
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Getting size of download");
|
||||
status.setSize(httpEntity.getContentLength());
|
||||
request.setSize(httpEntity.getContentLength());
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Size is " + status.getSize());
|
||||
if (status.getSize() < 0) {
|
||||
status.setSize(DownloadStatus.SIZE_UNKNOWN);
|
||||
Log.d(TAG, "Size is " + request.getSize());
|
||||
if (request.getSize() < 0) {
|
||||
request.setSize(DownloadStatus.SIZE_UNKNOWN);
|
||||
}
|
||||
|
||||
long freeSpace = StorageUtils.getFreeSpaceAvailable();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Free space is " + freeSpace);
|
||||
if (status.getSize() == DownloadStatus.SIZE_UNKNOWN
|
||||
|| status.getSize() <= freeSpace) {
|
||||
if (request.getSize() == DownloadStatus.SIZE_UNKNOWN
|
||||
|| request.getSize() <= freeSpace) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Starting download");
|
||||
while (!cancelled
|
||||
&& (count = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, count);
|
||||
status.setSoFar(status.getSoFar() + count);
|
||||
status.setProgressPercent((int) (((double) status
|
||||
.getSoFar() / (double) status.getSize()) * 100));
|
||||
request.setSoFar(request.getSoFar() + count);
|
||||
request.setProgressPercent((int) (((double) request
|
||||
.getSoFar() / (double) request
|
||||
.getSize()) * 100));
|
||||
}
|
||||
if (cancelled) {
|
||||
onCancelled();
|
||||
} else {
|
||||
out.flush();
|
||||
onSuccess();
|
||||
}
|
||||
} else {
|
||||
@ -145,10 +141,8 @@ public class HttpDownloader extends Downloader {
|
||||
} catch (NullPointerException e) {
|
||||
// might be thrown by connection.getInputStream()
|
||||
e.printStackTrace();
|
||||
onFail(DownloadError.ERROR_CONNECTION_ERROR, status.getFeedFile()
|
||||
.getDownload_url());
|
||||
onFail(DownloadError.ERROR_CONNECTION_ERROR, request.getSource());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(connection);
|
||||
IOUtils.closeQuietly(out);
|
||||
if (httpClient != null) {
|
||||
httpClient.getConnectionManager().shutdown();
|
||||
@ -159,29 +153,28 @@ public class HttpDownloader extends Downloader {
|
||||
private void onSuccess() {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Download was successful");
|
||||
status.setSuccessful();
|
||||
result.setSuccessful();
|
||||
}
|
||||
|
||||
private void onFail(DownloadError reason, String reasonDetailed) {
|
||||
if (AppConfig.DEBUG) {
|
||||
Log.d(TAG, "Download failed");
|
||||
}
|
||||
status.setFailed(reason, reasonDetailed);
|
||||
result.setFailed(reason, reasonDetailed);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
private void onCancelled() {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Download was cancelled");
|
||||
status.setCancelled();
|
||||
result.setCancelled();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
/** Deletes unfinished downloads. */
|
||||
private void cleanup() {
|
||||
if (status != null && status.getFeedFile() != null
|
||||
&& status.getFeedFile().getFile_url() != null) {
|
||||
File dest = new File(status.getFeedFile().getFile_url());
|
||||
if (request.getDestination() != null) {
|
||||
File dest = new File(request.getDestination());
|
||||
if (dest.exists()) {
|
||||
boolean rc = dest.delete();
|
||||
if (AppConfig.DEBUG)
|
||||
|
752
src/de/danoeh/antennapod/storage/DBReader.java
Normal file
752
src/de/danoeh/antennapod/storage/DBReader.java
Normal file
@ -0,0 +1,752 @@
|
||||
package de.danoeh.antennapod.storage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.feed.Chapter;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
import de.danoeh.antennapod.feed.FeedImage;
|
||||
import de.danoeh.antennapod.feed.FeedItem;
|
||||
import de.danoeh.antennapod.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.feed.ID3Chapter;
|
||||
import de.danoeh.antennapod.feed.SimpleChapter;
|
||||
import de.danoeh.antennapod.feed.VorbisCommentChapter;
|
||||
import de.danoeh.antennapod.service.download.*;
|
||||
import de.danoeh.antennapod.util.DownloadError;
|
||||
import de.danoeh.antennapod.util.comparator.DownloadStatusComparator;
|
||||
import de.danoeh.antennapod.util.comparator.FeedItemPubdateComparator;
|
||||
|
||||
/**
|
||||
* Provides methods for reading data from the AntennaPod database.
|
||||
* In general, all database calls in DBReader-methods are executed on the caller's thread.
|
||||
* This means that the caller should make sure that DBReader-methods are not executed on the GUI-thread.
|
||||
* This class will use the {@link de.danoeh.antennapod.feed.EventDistributor} to notify listeners about changes in the database.
|
||||
|
||||
*/
|
||||
public final class DBReader {
|
||||
private static final String TAG = "DBReader";
|
||||
|
||||
/**
|
||||
* Maximum size of the list returned by {@link #getPlaybackHistory(android.content.Context)}.
|
||||
*/
|
||||
public static final int PLAYBACK_HISTORY_SIZE = 50;
|
||||
|
||||
/**
|
||||
* Maximum size of the list returned by {@link #getDownloadLog(android.content.Context)}.
|
||||
*/
|
||||
public static final int DOWNLOAD_LOG_SIZE = 200;
|
||||
|
||||
|
||||
private DBReader() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of Feeds, sorted alphabetically by their title.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return A list of Feeds, sorted alphabetically by their title. A Feed-object
|
||||
* of the returned list does NOT have its list of FeedItems yet. The FeedItem-list
|
||||
* can be loaded separately with {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.feed.Feed)}.
|
||||
*/
|
||||
public static List<Feed> getFeedList(final Context context) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Extracting Feedlist");
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
|
||||
Cursor feedlistCursor = adapter.getAllFeedsCursor();
|
||||
List<Feed> feeds = new ArrayList<Feed>(feedlistCursor.getCount());
|
||||
|
||||
if (feedlistCursor.moveToFirst()) {
|
||||
do {
|
||||
Feed feed = extractFeedFromCursorRow(adapter, feedlistCursor);
|
||||
feeds.add(feed);
|
||||
} while (feedlistCursor.moveToNext());
|
||||
}
|
||||
feedlistCursor.close();
|
||||
return feeds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of 'expired Feeds', i.e. Feeds that have not been updated for a certain amount of time.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param expirationTime Time that is used for determining whether a feed is outdated or not.
|
||||
* A Feed is considered expired if 'lastUpdate < (currentTime - expirationTime)' evaluates to true.
|
||||
* @return A list of Feeds, sorted alphabetically by their title. A Feed-object
|
||||
* of the returned list does NOT have its list of FeedItems yet. The FeedItem-list
|
||||
* can be loaded separately with {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.feed.Feed)}.
|
||||
*/
|
||||
static List<Feed> getExpiredFeedsList(final Context context, final long expirationTime) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, String.format("getExpiredFeedsList(%d)", expirationTime));
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
|
||||
Cursor feedlistCursor = adapter.getExpiredFeedsCursor(expirationTime);
|
||||
List<Feed> feeds = new ArrayList<Feed>(feedlistCursor.getCount());
|
||||
|
||||
if (feedlistCursor.moveToFirst()) {
|
||||
do {
|
||||
Feed feed = extractFeedFromCursorRow(adapter, feedlistCursor);
|
||||
feeds.add(feed);
|
||||
} while (feedlistCursor.moveToNext());
|
||||
}
|
||||
feedlistCursor.close();
|
||||
return feeds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a list of FeedItems and loads their corresponding Feed-objects from the database.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param items The FeedItems whose Feed-objects should be loaded.
|
||||
*/
|
||||
public static void loadFeedDataOfFeedItemlist(Context context,
|
||||
List<FeedItem> items) {
|
||||
List<Feed> feeds = getFeedList(context);
|
||||
for (FeedItem item : items) {
|
||||
for (Feed feed : feeds) {
|
||||
if (feed.getId() == item.getFeedId()) {
|
||||
item.setFeed(feed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (item.getFeed() == null) {
|
||||
Log.w(TAG, "No match found for item with ID " + item.getId() + ". Feed ID was " + item.getFeedId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the list of FeedItems for a certain Feed-object. This method should NOT be used if the FeedItems are not
|
||||
* used. In order to get information ABOUT the list of FeedItems, consider using {@link #getFeedStatisticsList(android.content.Context)} instead.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param feed The Feed whose items should be loaded
|
||||
* @return A list with the FeedItems of the Feed. The Feed-attribute of the FeedItems will already be set correctly.
|
||||
* The method does NOT change the items-attribute of the feed.
|
||||
*/
|
||||
public static List<FeedItem> getFeedItemList(Context context,
|
||||
final Feed feed) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Extracting Feeditems of feed " + feed.getTitle());
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
|
||||
Cursor itemlistCursor = adapter.getAllItemsOfFeedCursor(feed);
|
||||
List<FeedItem> items = extractItemlistFromCursor(adapter,
|
||||
itemlistCursor);
|
||||
itemlistCursor.close();
|
||||
|
||||
Collections.sort(items, new FeedItemPubdateComparator());
|
||||
|
||||
adapter.close();
|
||||
|
||||
for (FeedItem item : items) {
|
||||
item.setFeed(feed);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
static List<FeedItem> extractItemlistFromCursor(Context context, Cursor itemlistCursor) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
List<FeedItem> result = extractItemlistFromCursor(adapter, itemlistCursor);
|
||||
adapter.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<FeedItem> extractItemlistFromCursor(
|
||||
PodDBAdapter adapter, Cursor itemlistCursor) {
|
||||
ArrayList<String> itemIds = new ArrayList<String>();
|
||||
List<FeedItem> items = new ArrayList<FeedItem>(
|
||||
itemlistCursor.getCount());
|
||||
|
||||
if (itemlistCursor.moveToFirst()) {
|
||||
do {
|
||||
FeedItem item = new FeedItem();
|
||||
|
||||
item.setId(itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_ID));
|
||||
item.setTitle(itemlistCursor
|
||||
.getString(PodDBAdapter.IDX_FI_SMALL_TITLE));
|
||||
item.setLink(itemlistCursor
|
||||
.getString(PodDBAdapter.IDX_FI_SMALL_LINK));
|
||||
item.setPubDate(new Date(itemlistCursor
|
||||
.getLong(PodDBAdapter.IDX_FI_SMALL_PUBDATE)));
|
||||
item.setPaymentLink(itemlistCursor
|
||||
.getString(PodDBAdapter.IDX_FI_SMALL_PAYMENT_LINK));
|
||||
item.setFeedId(itemlistCursor
|
||||
.getLong(PodDBAdapter.IDX_FI_SMALL_FEED));
|
||||
itemIds.add(String.valueOf(item.getId()));
|
||||
|
||||
item.setRead((itemlistCursor
|
||||
.getInt(PodDBAdapter.IDX_FI_SMALL_READ) > 0));
|
||||
item.setItemIdentifier(itemlistCursor
|
||||
.getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER));
|
||||
|
||||
// extract chapters
|
||||
boolean hasSimpleChapters = itemlistCursor
|
||||
.getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0;
|
||||
if (hasSimpleChapters) {
|
||||
Cursor chapterCursor = adapter
|
||||
.getSimpleChaptersOfFeedItemCursor(item);
|
||||
if (chapterCursor.moveToFirst()) {
|
||||
item.setChapters(new ArrayList<Chapter>());
|
||||
do {
|
||||
int chapterType = chapterCursor
|
||||
.getInt(PodDBAdapter.KEY_CHAPTER_TYPE_INDEX);
|
||||
Chapter chapter = null;
|
||||
long start = chapterCursor
|
||||
.getLong(PodDBAdapter.KEY_CHAPTER_START_INDEX);
|
||||
String title = chapterCursor
|
||||
.getString(PodDBAdapter.KEY_TITLE_INDEX);
|
||||
String link = chapterCursor
|
||||
.getString(PodDBAdapter.KEY_CHAPTER_LINK_INDEX);
|
||||
|
||||
switch (chapterType) {
|
||||
case SimpleChapter.CHAPTERTYPE_SIMPLECHAPTER:
|
||||
chapter = new SimpleChapter(start, title, item,
|
||||
link);
|
||||
break;
|
||||
case ID3Chapter.CHAPTERTYPE_ID3CHAPTER:
|
||||
chapter = new ID3Chapter(start, title, item,
|
||||
link);
|
||||
break;
|
||||
case VorbisCommentChapter.CHAPTERTYPE_VORBISCOMMENT_CHAPTER:
|
||||
chapter = new VorbisCommentChapter(start,
|
||||
title, item, link);
|
||||
break;
|
||||
}
|
||||
chapter.setId(chapterCursor
|
||||
.getLong(PodDBAdapter.KEY_ID_INDEX));
|
||||
item.getChapters().add(chapter);
|
||||
} while (chapterCursor.moveToNext());
|
||||
}
|
||||
chapterCursor.close();
|
||||
}
|
||||
items.add(item);
|
||||
} while (itemlistCursor.moveToNext());
|
||||
}
|
||||
|
||||
extractMediafromItemlist(adapter, items, itemIds);
|
||||
return items;
|
||||
}
|
||||
|
||||
private static void extractMediafromItemlist(PodDBAdapter adapter,
|
||||
List<FeedItem> items, ArrayList<String> itemIds) {
|
||||
|
||||
List<FeedItem> itemsCopy = new ArrayList<FeedItem>(items);
|
||||
Cursor cursor = adapter.getFeedMediaCursorByItemID(itemIds
|
||||
.toArray(new String[itemIds.size()]));
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
long itemId = cursor.getLong(PodDBAdapter.KEY_MEDIA_FEEDITEM_INDEX);
|
||||
// find matching feed item
|
||||
FeedItem item = getMatchingItemForMedia(itemId, itemsCopy);
|
||||
if (item != null) {
|
||||
item.setMedia(extractFeedMediaFromCursorRow(cursor));
|
||||
item.getMedia().setItem(item);
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static FeedMedia extractFeedMediaFromCursorRow(final Cursor cursor) {
|
||||
long mediaId = cursor.getLong(PodDBAdapter.KEY_ID_INDEX);
|
||||
Date playbackCompletionDate = null;
|
||||
long playbackCompletionTime = cursor
|
||||
.getLong(PodDBAdapter.KEY_PLAYBACK_COMPLETION_DATE_INDEX);
|
||||
if (playbackCompletionTime > 0) {
|
||||
playbackCompletionDate = new Date(
|
||||
playbackCompletionTime);
|
||||
}
|
||||
|
||||
return new FeedMedia(
|
||||
mediaId,
|
||||
null,
|
||||
cursor.getInt(PodDBAdapter.KEY_DURATION_INDEX),
|
||||
cursor.getInt(PodDBAdapter.KEY_POSITION_INDEX),
|
||||
cursor.getLong(PodDBAdapter.KEY_SIZE_INDEX),
|
||||
cursor.getString(PodDBAdapter.KEY_MIME_TYPE_INDEX),
|
||||
cursor.getString(PodDBAdapter.KEY_FILE_URL_INDEX),
|
||||
cursor.getString(PodDBAdapter.KEY_DOWNLOAD_URL_INDEX),
|
||||
cursor.getInt(PodDBAdapter.KEY_DOWNLOADED_INDEX) > 0,
|
||||
playbackCompletionDate);
|
||||
}
|
||||
|
||||
private static Feed extractFeedFromCursorRow(PodDBAdapter adapter,
|
||||
Cursor cursor) {
|
||||
Date lastUpdate = new Date(
|
||||
cursor.getLong(PodDBAdapter.KEY_LAST_UPDATE_INDEX));
|
||||
Feed feed = new Feed(lastUpdate);
|
||||
|
||||
feed.setId(cursor.getLong(PodDBAdapter.KEY_ID_INDEX));
|
||||
feed.setTitle(cursor.getString(PodDBAdapter.KEY_TITLE_INDEX));
|
||||
feed.setLink(cursor.getString(PodDBAdapter.KEY_LINK_INDEX));
|
||||
feed.setDescription(cursor
|
||||
.getString(PodDBAdapter.KEY_DESCRIPTION_INDEX));
|
||||
feed.setPaymentLink(cursor
|
||||
.getString(PodDBAdapter.KEY_PAYMENT_LINK_INDEX));
|
||||
feed.setAuthor(cursor.getString(PodDBAdapter.KEY_AUTHOR_INDEX));
|
||||
feed.setLanguage(cursor.getString(PodDBAdapter.KEY_LANGUAGE_INDEX));
|
||||
feed.setType(cursor.getString(PodDBAdapter.KEY_TYPE_INDEX));
|
||||
feed.setFeedIdentifier(cursor
|
||||
.getString(PodDBAdapter.KEY_FEED_IDENTIFIER_INDEX));
|
||||
long imageIndex = cursor.getLong(PodDBAdapter.KEY_IMAGE_INDEX);
|
||||
if (imageIndex != 0) {
|
||||
feed.setImage(getFeedImage(adapter, imageIndex));
|
||||
feed.getImage().setFeed(feed);
|
||||
}
|
||||
feed.setFile_url(cursor.getString(PodDBAdapter.KEY_FILE_URL_INDEX));
|
||||
feed.setDownload_url(cursor
|
||||
.getString(PodDBAdapter.KEY_DOWNLOAD_URL_INDEX));
|
||||
feed.setDownloaded(cursor.getInt(PodDBAdapter.KEY_DOWNLOADED_INDEX) > 0);
|
||||
|
||||
return feed;
|
||||
}
|
||||
|
||||
private static FeedItem getMatchingItemForMedia(long itemId,
|
||||
List<FeedItem> items) {
|
||||
for (FeedItem item : items) {
|
||||
if (item.getId() == itemId) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<FeedItem> getQueue(Context context, PodDBAdapter adapter) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Extracting queue");
|
||||
|
||||
Cursor itemlistCursor = adapter.getQueueCursor();
|
||||
List<FeedItem> items = extractItemlistFromCursor(adapter,
|
||||
itemlistCursor);
|
||||
itemlistCursor.close();
|
||||
loadFeedDataOfFeedItemlist(context, items);
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the IDs of the FeedItems in the queue. This method should be preferred over
|
||||
* {@link #getQueue(android.content.Context)} if the FeedItems of the queue are not needed.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return A list of IDs sorted by the same order as the queue. The caller can wrap the returned
|
||||
* list in a {@link de.danoeh.antennapod.util.QueueAccess} object for easier access to the queue's properties.
|
||||
*/
|
||||
public static List<Long> getQueueIDList(Context context) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
|
||||
adapter.open();
|
||||
List<Long> result = getQueueIDList(adapter);
|
||||
adapter.close();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static List<Long> getQueueIDList(PodDBAdapter adapter) {
|
||||
adapter.open();
|
||||
Cursor queueCursor = adapter.getQueueIDCursor();
|
||||
|
||||
List<Long> queueIds = new ArrayList<Long>(queueCursor.getCount());
|
||||
if (queueCursor.moveToFirst()) {
|
||||
do {
|
||||
queueIds.add(queueCursor.getLong(0));
|
||||
} while (queueCursor.moveToNext());
|
||||
}
|
||||
return queueIds;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Loads a list of the FeedItems in the queue. If the FeedItems of the queue are not used directly, consider using
|
||||
* {@link #getQueueIDList(android.content.Context)} instead.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return A list of FeedItems sorted by the same order as the queue. The caller can wrap the returned
|
||||
* list in a {@link de.danoeh.antennapod.util.QueueAccess} object for easier access to the queue's properties.
|
||||
*/
|
||||
public static List<FeedItem> getQueue(Context context) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Extracting queue");
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
List<FeedItem> items = getQueue(context, adapter);
|
||||
adapter.close();
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a list of FeedItems whose episode has been downloaded.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return A list of FeedItems whose episdoe has been downloaded.
|
||||
*/
|
||||
public static List<FeedItem> getDownloadedItems(Context context) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Extracting downloaded items");
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
|
||||
Cursor itemlistCursor = adapter.getDownloadedItemsCursor();
|
||||
List<FeedItem> items = extractItemlistFromCursor(adapter,
|
||||
itemlistCursor);
|
||||
itemlistCursor.close();
|
||||
loadFeedDataOfFeedItemlist(context, items);
|
||||
Collections.sort(items, new FeedItemPubdateComparator());
|
||||
|
||||
adapter.close();
|
||||
return items;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a list of FeedItems whose 'read'-attribute is set to false.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return A list of FeedItems whose 'read'-attribute it set to false. If the FeedItems in the list are not used,
|
||||
* consider using {@link #getUnreadItemIds(android.content.Context)} instead.
|
||||
*/
|
||||
public static List<FeedItem> getUnreadItemsList(Context context) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Extracting unread items list");
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
|
||||
Cursor itemlistCursor = adapter.getUnreadItemsCursor();
|
||||
List<FeedItem> items = extractItemlistFromCursor(adapter,
|
||||
itemlistCursor);
|
||||
itemlistCursor.close();
|
||||
|
||||
loadFeedDataOfFeedItemlist(context, items);
|
||||
|
||||
adapter.close();
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the IDs of the FeedItems whose 'read'-attribute is set to false.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return A list of IDs of the FeedItems whose 'read'-attribute is set to false. This method should be preferred
|
||||
* over {@link #getUnreadItemsList(android.content.Context)} if the FeedItems in the UnreadItems list are not used.
|
||||
*/
|
||||
public static long[] getUnreadItemIds(Context context) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
Cursor cursor = adapter.getUnreadItemIdsCursor();
|
||||
long[] itemIds = new long[cursor.getCount()];
|
||||
int i = 0;
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
itemIds[i] = cursor.getLong(PodDBAdapter.KEY_ID_INDEX);
|
||||
i++;
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
return itemIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the playback history from the database. A FeedItem is in the playback history if playback of the correpsonding episode
|
||||
* has been completed at least once.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return The playback history. The FeedItems are sorted by their media's playbackCompletionDate in descending order.
|
||||
* The size of the returned list is limited by {@link #PLAYBACK_HISTORY_SIZE}.
|
||||
*/
|
||||
public static List<FeedItem> getPlaybackHistory(final Context context) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Loading playback history");
|
||||
final int PLAYBACK_HISTORY_SIZE = 50;
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
|
||||
Cursor mediaCursor = adapter.getCompletedMediaCursor(PLAYBACK_HISTORY_SIZE);
|
||||
String[] itemIds = new String[mediaCursor.getCount()];
|
||||
for (int i = 0; i < itemIds.length && mediaCursor.moveToPosition(i); i++) {
|
||||
itemIds[i] = Long.toString(mediaCursor.getLong(PodDBAdapter.KEY_MEDIA_FEEDITEM_INDEX));
|
||||
}
|
||||
mediaCursor.close();
|
||||
Cursor itemCursor = adapter.getFeedItemCursor(itemIds);
|
||||
List<FeedItem> items = extractItemlistFromCursor(adapter, itemCursor);
|
||||
loadFeedDataOfFeedItemlist(context, items);
|
||||
itemCursor.close();
|
||||
|
||||
adapter.close();
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the download log from the database.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return A list with DownloadStatus objects that represent the download log.
|
||||
* The size of the returned list is limited by {@link #DOWNLOAD_LOG_SIZE}.
|
||||
*/
|
||||
public static List<DownloadStatus> getDownloadLog(Context context) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Extracting DownloadLog");
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
Cursor logCursor = adapter.getDownloadLogCursor(DOWNLOAD_LOG_SIZE);
|
||||
List<DownloadStatus> downloadLog = new ArrayList<DownloadStatus>(
|
||||
logCursor.getCount());
|
||||
|
||||
if (logCursor.moveToFirst()) {
|
||||
do {
|
||||
long id = logCursor.getLong(PodDBAdapter.KEY_ID_INDEX);
|
||||
|
||||
long feedfileId = logCursor
|
||||
.getLong(PodDBAdapter.KEY_FEEDFILE_INDEX);
|
||||
int feedfileType = logCursor
|
||||
.getInt(PodDBAdapter.KEY_FEEDFILETYPE_INDEX);
|
||||
boolean successful = logCursor
|
||||
.getInt(PodDBAdapter.KEY_SUCCESSFUL_INDEX) > 0;
|
||||
int reason = logCursor.getInt(PodDBAdapter.KEY_REASON_INDEX);
|
||||
String reasonDetailed = logCursor
|
||||
.getString(PodDBAdapter.KEY_REASON_DETAILED_INDEX);
|
||||
String title = logCursor
|
||||
.getString(PodDBAdapter.KEY_DOWNLOADSTATUS_TITLE_INDEX);
|
||||
Date completionDate = new Date(
|
||||
logCursor
|
||||
.getLong(PodDBAdapter.KEY_COMPLETION_DATE_INDEX));
|
||||
downloadLog.add(new DownloadStatus(id, title, feedfileId,
|
||||
feedfileType, successful, DownloadError.fromCode(reason), completionDate,
|
||||
reasonDetailed));
|
||||
|
||||
} while (logCursor.moveToNext());
|
||||
}
|
||||
logCursor.close();
|
||||
Collections.sort(downloadLog, new DownloadStatusComparator());
|
||||
return downloadLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the FeedItemStatistics objects of all Feeds in the database. This method should be preferred over
|
||||
* {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.feed.Feed)} if only metadata about
|
||||
* the FeedItems is needed.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return A list of FeedItemStatistics objects sorted alphabetically by their Feed's title.
|
||||
*/
|
||||
public static List<FeedItemStatistics> getFeedStatisticsList(final Context context) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
List<FeedItemStatistics> result = new ArrayList<FeedItemStatistics>();
|
||||
Cursor cursor = adapter.getFeedStatisticsCursor();
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
result.add(new FeedItemStatistics(cursor.getLong(PodDBAdapter.IDX_FEEDSTATISTICS_FEED),
|
||||
cursor.getInt(PodDBAdapter.IDX_FEEDSTATISTICS_NUM_ITEMS),
|
||||
cursor.getInt(PodDBAdapter.IDX_FEEDSTATISTICS_NEW_ITEMS),
|
||||
cursor.getInt(PodDBAdapter.IDX_FEEDSTATISTICS_IN_PROGRESS_EPISODES),
|
||||
new Date(cursor.getLong(PodDBAdapter.IDX_FEEDSTATISTICS_LATEST_EPISODE))));
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
adapter.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a specific Feed from the database.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param feedId The ID of the Feed
|
||||
* @return The Feed or null if the Feed could not be found. The Feeds FeedItems will also be loaded from the
|
||||
* database and the items-attribute will be set correctly.
|
||||
*/
|
||||
public static Feed getFeed(final Context context, final long feedId) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Loading feed with id " + feedId);
|
||||
Feed feed = null;
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
Cursor feedCursor = adapter.getFeedCursor(feedId);
|
||||
if (feedCursor.moveToFirst()) {
|
||||
feed = extractFeedFromCursorRow(adapter, feedCursor);
|
||||
feed.setItems(getFeedItemList(context, feed));
|
||||
} else {
|
||||
Log.e(TAG, "getFeed could not find feed with id " + feedId);
|
||||
}
|
||||
adapter.close();
|
||||
return feed;
|
||||
}
|
||||
|
||||
static FeedItem getFeedItem(final Context context, final long itemId, PodDBAdapter adapter) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Loading feeditem with id " + itemId);
|
||||
FeedItem item = null;
|
||||
|
||||
Cursor itemCursor = adapter.getFeedItemCursor(Long.toString(itemId));
|
||||
if (itemCursor.moveToFirst()) {
|
||||
List<FeedItem> list = extractItemlistFromCursor(adapter, itemCursor);
|
||||
if (list.size() > 0) {
|
||||
item = list.get(0);
|
||||
loadFeedDataOfFeedItemlist(context, list);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a specific FeedItem from the database.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param itemId The ID of the FeedItem
|
||||
* @return The FeedItem or null if the FeedItem could not be found. All FeedComponent-attributes of the FeedItem will
|
||||
* also be loaded from the database.
|
||||
*/
|
||||
public static FeedItem getFeedItem(final Context context, final long itemId) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Loading feeditem with id " + itemId);
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
FeedItem item = getFeedItem(context, itemId, adapter);
|
||||
adapter.close();
|
||||
return item;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads additional information about a FeedItem, e.g. shownotes
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param item The FeedItem
|
||||
*/
|
||||
public static void loadExtraInformationOfFeedItem(final Context context, final FeedItem item) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
Cursor extraCursor = adapter.getExtraInformationOfItem(item);
|
||||
if (extraCursor.moveToFirst()) {
|
||||
String description = extraCursor
|
||||
.getString(PodDBAdapter.IDX_FI_EXTRA_DESCRIPTION);
|
||||
String contentEncoded = extraCursor
|
||||
.getString(PodDBAdapter.IDX_FI_EXTRA_CONTENT_ENCODED);
|
||||
item.setDescription(description);
|
||||
item.setContentEncoded(contentEncoded);
|
||||
}
|
||||
adapter.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of downloaded episodes.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return The number of downloaded episodes.
|
||||
*/
|
||||
public static int getNumberOfDownloadedEpisodes(final Context context) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
final int result = adapter.getNumberOfDownloadedEpisodes();
|
||||
adapter.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of unread items.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @return The number of unread items.
|
||||
*/
|
||||
public static int getNumberOfUnreadItems(final Context context) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
final int result = adapter.getNumberOfUnreadItems();
|
||||
adapter.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the DB for a FeedImage of the given id.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param imageId The id of the object
|
||||
* @return The found object
|
||||
*/
|
||||
public static FeedImage getFeedImage(final Context context, final long imageId) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
FeedImage result = getFeedImage(adapter, imageId);
|
||||
adapter.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the DB for a FeedImage of the given id.
|
||||
*
|
||||
* @param id The id of the object
|
||||
* @return The found object
|
||||
*/
|
||||
static FeedImage getFeedImage(PodDBAdapter adapter, final long id) {
|
||||
Cursor cursor = adapter.getImageOfFeedCursor(id);
|
||||
if ((cursor.getCount() == 0) || !cursor.moveToFirst()) {
|
||||
throw new SQLException("No FeedImage found at index: " + id);
|
||||
}
|
||||
FeedImage image = new FeedImage(id, cursor.getString(cursor
|
||||
.getColumnIndex(PodDBAdapter.KEY_TITLE)),
|
||||
cursor.getString(cursor
|
||||
.getColumnIndex(PodDBAdapter.KEY_FILE_URL)),
|
||||
cursor.getString(cursor
|
||||
.getColumnIndex(PodDBAdapter.KEY_DOWNLOAD_URL)),
|
||||
cursor.getInt(cursor
|
||||
.getColumnIndex(PodDBAdapter.KEY_DOWNLOADED)) > 0);
|
||||
cursor.close();
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the DB for a FeedMedia of the given id.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param mediaId The id of the object
|
||||
* @return The found object
|
||||
*/
|
||||
public static FeedMedia getFeedMedia(final Context context, final long mediaId) {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
|
||||
adapter.open();
|
||||
Cursor mediaCursor = adapter.getSingleFeedMediaCursor(mediaId);
|
||||
|
||||
FeedMedia media = null;
|
||||
if (mediaCursor.moveToFirst()) {
|
||||
final long itemId = mediaCursor.getLong(PodDBAdapter.KEY_MEDIA_FEEDITEM_INDEX);
|
||||
media = extractFeedMediaFromCursorRow(mediaCursor);
|
||||
FeedItem item = getFeedItem(context, itemId);
|
||||
if (media != null && item != null) {
|
||||
media.setItem(item);
|
||||
item.setMedia(media);
|
||||
}
|
||||
}
|
||||
|
||||
mediaCursor.close();
|
||||
adapter.close();
|
||||
|
||||
return media;
|
||||
}
|
||||
}
|
731
src/de/danoeh/antennapod/storage/DBTasks.java
Normal file
731
src/de/danoeh/antennapod/storage/DBTasks.java
Normal file
@ -0,0 +1,731 @@
|
||||
package de.danoeh.antennapod.storage;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.feed.EventDistributor;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
import de.danoeh.antennapod.feed.FeedImage;
|
||||
import de.danoeh.antennapod.feed.FeedItem;
|
||||
import de.danoeh.antennapod.feed.FeedMedia;
|
||||
import de.danoeh.antennapod.preferences.UserPreferences;
|
||||
import de.danoeh.antennapod.service.PlaybackService;
|
||||
import de.danoeh.antennapod.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.util.DownloadError;
|
||||
import de.danoeh.antennapod.util.NetworkUtils;
|
||||
import de.danoeh.antennapod.util.QueueAccess;
|
||||
import de.danoeh.antennapod.util.exception.MediaFileNotFoundException;
|
||||
|
||||
/**
|
||||
* Provides methods for doing common tasks that use DBReader and DBWriter.
|
||||
*/
|
||||
public final class DBTasks {
|
||||
private static final String TAG = "DBTasks";
|
||||
|
||||
private DBTasks() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts playback of a FeedMedia object's file. This method will build an Intent based on the given parameters to
|
||||
* start the {@link PlaybackService}.
|
||||
*
|
||||
* @param context Used for sending starting Services and Activities.
|
||||
* @param media The FeedMedia object.
|
||||
* @param showPlayer If true, starts the appropriate player activity ({@link de.danoeh.antennapod.activity.AudioplayerActivity}
|
||||
* or {@link de.danoeh.antennapod.activity.VideoplayerActivity}
|
||||
* @param startWhenPrepared Parameter for the {@link PlaybackService} start intent. If true, playback will start as
|
||||
* soon as the PlaybackService has finished loading the FeedMedia object's file.
|
||||
* @param shouldStream Parameter for the {@link PlaybackService} start intent. If true, the FeedMedia object's file
|
||||
* will be streamed, otherwise the downloaded file will be used. If the downloaded file cannot be
|
||||
* found, the PlaybackService will shutdown and the database entry of the FeedMedia object will be
|
||||
* corrected.
|
||||
*/
|
||||
public static void playMedia(final Context context, final FeedMedia media,
|
||||
boolean showPlayer, boolean startWhenPrepared, boolean shouldStream) {
|
||||
try {
|
||||
if (!shouldStream) {
|
||||
if (media.fileExists() == false) {
|
||||
throw new MediaFileNotFoundException(
|
||||
"No episode was found at " + media.getFile_url(),
|
||||
media);
|
||||
}
|
||||
}
|
||||
// Start playback Service
|
||||
Intent launchIntent = new Intent(context, PlaybackService.class);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_PLAYABLE, media);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_START_WHEN_PREPARED,
|
||||
startWhenPrepared);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_SHOULD_STREAM,
|
||||
shouldStream);
|
||||
launchIntent.putExtra(PlaybackService.EXTRA_PREPARE_IMMEDIATELY,
|
||||
true);
|
||||
context.startService(launchIntent);
|
||||
if (showPlayer) {
|
||||
// Launch media player
|
||||
context.startActivity(PlaybackService.getPlayerActivityIntent(
|
||||
context, media));
|
||||
}
|
||||
DBWriter.addQueueItemAt(context, media.getItem().getId(), 0, false);
|
||||
} catch (MediaFileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
if (media.isPlaying()) {
|
||||
context.sendBroadcast(new Intent(
|
||||
PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
|
||||
}
|
||||
notifyMissingFeedMediaFile(context, media);
|
||||
}
|
||||
}
|
||||
|
||||
private static AtomicBoolean isRefreshing = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* Refreshes a given list of Feeds in a separate Thread. This method might ignore subsequent calls if it is still
|
||||
* enqueuing Feeds for download from a previous call
|
||||
*
|
||||
* @param context Might be used for accessing the database
|
||||
* @param feeds List of Feeds that should be refreshed.
|
||||
*/
|
||||
public static void refreshAllFeeds(final Context context,
|
||||
final List<Feed> feeds) {
|
||||
if (isRefreshing.compareAndSet(false, true)) {
|
||||
new Thread() {
|
||||
public void run() {
|
||||
if (feeds != null) {
|
||||
refreshFeeds(context, feeds);
|
||||
} else {
|
||||
refreshFeeds(context, DBReader.getFeedList(context));
|
||||
}
|
||||
isRefreshing.set(false);
|
||||
}
|
||||
}.start();
|
||||
} else {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"Ignoring request to refresh all feeds: Refresh lock is locked");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes expired Feeds in the list returned by the getExpiredFeedsList(Context, long) method in DBReader.
|
||||
* The expiration date parameter is determined by the update interval specified in {@link UserPreferences}.
|
||||
*
|
||||
* @param context Used for DB access.
|
||||
*/
|
||||
public static void refreshExpiredFeeds(final Context context) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Refreshing expired feeds");
|
||||
|
||||
new Thread() {
|
||||
public void run() {
|
||||
long millis = UserPreferences.getUpdateInterval();
|
||||
|
||||
if (millis > 0) {
|
||||
long now = Calendar.getInstance().getTime().getTime();
|
||||
|
||||
// Allow a 10 minute window
|
||||
millis -= 10 * 60 * 1000;
|
||||
List<Feed> feedList = DBReader.getExpiredFeedsList(context,
|
||||
now - millis);
|
||||
if (feedList.size() > 0) {
|
||||
refreshFeeds(context, feedList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
private static void refreshFeeds(final Context context,
|
||||
final List<Feed> feedList) {
|
||||
|
||||
for (Feed feed : feedList) {
|
||||
try {
|
||||
refreshFeed(context, feed);
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
DBWriter.addDownloadStatus(
|
||||
context,
|
||||
new DownloadStatus(feed, feed
|
||||
.getHumanReadableIdentifier(),
|
||||
DownloadError.ERROR_REQUEST_ERROR, false, e
|
||||
.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a specific Feed.
|
||||
*
|
||||
* @param context Used for requesting the download.
|
||||
* @param feed The Feed object.
|
||||
*/
|
||||
public static void refreshFeed(Context context, Feed feed)
|
||||
throws DownloadRequestException {
|
||||
DownloadRequester.getInstance().downloadFeed(context,
|
||||
new Feed(feed.getDownload_url(), new Date(), feed.getTitle()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the database about a missing FeedImage file. This method will attempt to re-download the file.
|
||||
*
|
||||
* @param context Used for requesting the download.
|
||||
* @param image The FeedImage object.
|
||||
*/
|
||||
public static void notifyInvalidImageFile(final Context context,
|
||||
final FeedImage image) {
|
||||
Log.i(TAG,
|
||||
"The DB was notified about an invalid image download. It will now try to re-download the image file");
|
||||
try {
|
||||
DownloadRequester.getInstance().downloadImage(context, image);
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
Log.w(TAG, "Failed to download invalid feed image");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the database about a missing FeedMedia file. This method will correct the FeedMedia object's values in the
|
||||
* DB and send a FeedUpdateBroadcast.
|
||||
*/
|
||||
public static void notifyMissingFeedMediaFile(final Context context,
|
||||
final FeedMedia media) {
|
||||
Log.i(TAG,
|
||||
"The feedmanager was notified about a missing episode. It will update its database now.");
|
||||
media.setDownloaded(false);
|
||||
media.setFile_url(null);
|
||||
DBWriter.setFeedMedia(context, media);
|
||||
EventDistributor.getInstance().sendFeedUpdateBroadcast();
|
||||
}
|
||||
|
||||
/**
|
||||
* Request the download of all objects in the queue. from a separate Thread.
|
||||
*
|
||||
* @param context Used for requesting the download an accessing the database.
|
||||
*/
|
||||
public static void downloadAllItemsInQueue(final Context context) {
|
||||
new Thread() {
|
||||
public void run() {
|
||||
List<FeedItem> queue = DBReader.getQueue(context);
|
||||
if (!queue.isEmpty()) {
|
||||
try {
|
||||
downloadFeedItems(context,
|
||||
queue.toArray(new FeedItem[queue.size()]));
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the download of a list of FeedItem objects.
|
||||
*
|
||||
* @param context Used for requesting the download and accessing the DB.
|
||||
* @param items The FeedItem objects.
|
||||
*/
|
||||
public static void downloadFeedItems(final Context context,
|
||||
FeedItem... items) throws DownloadRequestException {
|
||||
downloadFeedItems(true, context, items);
|
||||
}
|
||||
|
||||
private static void downloadFeedItems(boolean performAutoCleanup,
|
||||
final Context context, final FeedItem... items)
|
||||
throws DownloadRequestException {
|
||||
final DownloadRequester requester = DownloadRequester.getInstance();
|
||||
|
||||
if (performAutoCleanup) {
|
||||
new Thread() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
performAutoCleanup(context,
|
||||
getPerformAutoCleanupArgs(context, items.length));
|
||||
}
|
||||
|
||||
}.start();
|
||||
}
|
||||
for (FeedItem item : items) {
|
||||
if (item.getMedia() != null
|
||||
&& !requester.isDownloadingFile(item.getMedia())
|
||||
&& !item.getMedia().isDownloaded()) {
|
||||
if (items.length > 1) {
|
||||
try {
|
||||
requester.downloadMedia(context, item.getMedia());
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
DBWriter.addDownloadStatus(context,
|
||||
new DownloadStatus(item.getMedia(), item
|
||||
.getMedia()
|
||||
.getHumanReadableIdentifier(),
|
||||
DownloadError.ERROR_REQUEST_ERROR,
|
||||
false, e.getMessage()));
|
||||
}
|
||||
} else {
|
||||
requester.downloadMedia(context, item.getMedia());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int getNumberOfUndownloadedEpisodes(
|
||||
final List<FeedItem> queue, final List<FeedItem> unreadItems) {
|
||||
int counter = 0;
|
||||
for (FeedItem item : queue) {
|
||||
if (item.hasMedia() && !item.getMedia().isDownloaded()
|
||||
&& !item.getMedia().isPlaying()) {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
for (FeedItem item : unreadItems) {
|
||||
if (item.hasMedia() && !item.getMedia().isDownloaded()) {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
return counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for undownloaded episodes in the queue or list of unread items and request a download if
|
||||
* 1. Network is available
|
||||
* 2. There is free space in the episode cache
|
||||
* This method should NOT be executed on the GUI thread.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
*/
|
||||
public static void autodownloadUndownloadedItems(final Context context) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Performing auto-dl of undownloaded episodes");
|
||||
if (NetworkUtils.autodownloadNetworkAvailable(context)
|
||||
&& UserPreferences.isEnableAutodownload()) {
|
||||
final List<FeedItem> queue = DBReader.getQueue(context);
|
||||
final List<FeedItem> unreadItems = DBReader
|
||||
.getUnreadItemsList(context);
|
||||
|
||||
int undownloadedEpisodes = getNumberOfUndownloadedEpisodes(queue,
|
||||
unreadItems);
|
||||
int downloadedEpisodes = DBReader
|
||||
.getNumberOfDownloadedEpisodes(context);
|
||||
int deletedEpisodes = performAutoCleanup(context,
|
||||
getPerformAutoCleanupArgs(context, undownloadedEpisodes));
|
||||
int episodeSpaceLeft = undownloadedEpisodes;
|
||||
boolean cacheIsUnlimited = UserPreferences.getEpisodeCacheSize() == UserPreferences
|
||||
.getEpisodeCacheSizeUnlimited();
|
||||
|
||||
if (!cacheIsUnlimited
|
||||
&& UserPreferences.getEpisodeCacheSize() < downloadedEpisodes
|
||||
+ undownloadedEpisodes) {
|
||||
episodeSpaceLeft = UserPreferences.getEpisodeCacheSize()
|
||||
- (downloadedEpisodes - deletedEpisodes);
|
||||
}
|
||||
|
||||
List<FeedItem> itemsToDownload = new ArrayList<FeedItem>();
|
||||
if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) {
|
||||
for (int i = 0; i < queue.size(); i++) { // ignore playing item
|
||||
FeedItem item = queue.get(i);
|
||||
if (item.hasMedia() && !item.getMedia().isDownloaded()
|
||||
&& !item.getMedia().isPlaying()) {
|
||||
itemsToDownload.add(item);
|
||||
episodeSpaceLeft--;
|
||||
undownloadedEpisodes--;
|
||||
if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (episodeSpaceLeft > 0 && undownloadedEpisodes > 0) {
|
||||
for (FeedItem item : unreadItems) {
|
||||
if (item.hasMedia() && !item.getMedia().isDownloaded()) {
|
||||
itemsToDownload.add(item);
|
||||
episodeSpaceLeft--;
|
||||
undownloadedEpisodes--;
|
||||
if (episodeSpaceLeft == 0 || undownloadedEpisodes == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Enqueueing " + itemsToDownload.size()
|
||||
+ " items for download");
|
||||
|
||||
try {
|
||||
downloadFeedItems(false, context,
|
||||
itemsToDownload.toArray(new FeedItem[itemsToDownload
|
||||
.size()]));
|
||||
} catch (DownloadRequestException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static int getPerformAutoCleanupArgs(Context context,
|
||||
final int episodeNumber) {
|
||||
if (episodeNumber >= 0
|
||||
&& UserPreferences.getEpisodeCacheSize() != UserPreferences
|
||||
.getEpisodeCacheSizeUnlimited()) {
|
||||
int downloadedEpisodes = DBReader
|
||||
.getNumberOfDownloadedEpisodes(context);
|
||||
if (downloadedEpisodes + episodeNumber >= UserPreferences
|
||||
.getEpisodeCacheSize()) {
|
||||
|
||||
return downloadedEpisodes + episodeNumber
|
||||
- UserPreferences.getEpisodeCacheSize();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removed downloaded episodes outside of the queue if the episode cache is full. Episodes with a smaller
|
||||
* 'playbackCompletionDate'-value will be deleted first.
|
||||
* <p/>
|
||||
* This method should NOT be executed on the GUI thread.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
*/
|
||||
public static void performAutoCleanup(final Context context) {
|
||||
performAutoCleanup(context, getPerformAutoCleanupArgs(context, 0));
|
||||
}
|
||||
|
||||
private static int performAutoCleanup(final Context context,
|
||||
final int episodeNumber) {
|
||||
List<FeedItem> candidates = DBReader.getDownloadedItems(context);
|
||||
List<FeedItem> queue = DBReader.getQueue(context);
|
||||
List<FeedItem> delete;
|
||||
for (FeedItem item : candidates) {
|
||||
if (item.hasMedia() && item.getMedia().isDownloaded()
|
||||
&& !queue.contains(item) && item.isRead()) {
|
||||
candidates.add(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Collections.sort(candidates, new Comparator<FeedItem>() {
|
||||
@Override
|
||||
public int compare(FeedItem lhs, FeedItem rhs) {
|
||||
Date l = lhs.getMedia().getPlaybackCompletionDate();
|
||||
Date r = rhs.getMedia().getPlaybackCompletionDate();
|
||||
|
||||
if (l == null) {
|
||||
l = new Date(0);
|
||||
}
|
||||
if (r == null) {
|
||||
r = new Date(0);
|
||||
}
|
||||
return l.compareTo(r);
|
||||
}
|
||||
});
|
||||
|
||||
if (candidates.size() > episodeNumber) {
|
||||
delete = candidates.subList(0, episodeNumber);
|
||||
} else {
|
||||
delete = candidates;
|
||||
}
|
||||
|
||||
for (FeedItem item : delete) {
|
||||
DBWriter.deleteFeedMediaOfItem(context, item.getId());
|
||||
}
|
||||
|
||||
int counter = delete.size();
|
||||
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, String.format(
|
||||
"Auto-delete deleted %d episodes (%d requested)", counter,
|
||||
episodeNumber));
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all FeedItem objects whose 'read'-attribute is false to the queue in a separate thread.
|
||||
*/
|
||||
public static void enqueueAllNewItems(final Context context) {
|
||||
long[] unreadItems = DBReader.getUnreadItemIds(context);
|
||||
DBWriter.addQueueItem(context, unreadItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the successor of a FeedItem in the queue.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
* @param itemId ID of the FeedItem
|
||||
* @param queue Used for determining the successor of the item. If this parameter is null, the method will load
|
||||
* the queue from the database in the same thread.
|
||||
* @return Successor of the FeedItem or null if the FeedItem is not in the queue or has no successor.
|
||||
*/
|
||||
public static FeedItem getQueueSuccessorOfItem(Context context,
|
||||
final long itemId, List<FeedItem> queue) {
|
||||
FeedItem result = null;
|
||||
if (queue == null) {
|
||||
queue = DBReader.getQueue(context);
|
||||
}
|
||||
if (queue != null) {
|
||||
Iterator<FeedItem> iterator = queue.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
FeedItem item = iterator.next();
|
||||
if (item.getId() == itemId) {
|
||||
if (iterator.hasNext()) {
|
||||
result = iterator.next();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the queue from the database and checks if the specified FeedItem is in the queue.
|
||||
* This method should NOT be executed in the GUI thread.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
* @param feedItemId ID of the FeedItem
|
||||
*/
|
||||
public static boolean isInQueue(Context context, final long feedItemId) {
|
||||
List<Long> queue = DBReader.getQueueIDList(context);
|
||||
return QueueAccess.IDListAccess(queue).contains(feedItemId);
|
||||
}
|
||||
|
||||
private static Feed searchFeedByIdentifyingValue(Context context,
|
||||
String identifier) {
|
||||
List<Feed> feeds = DBReader.getFeedList(context);
|
||||
for (Feed feed : feeds) {
|
||||
if (feed.getIdentifyingValue().equals(identifier)) {
|
||||
return feed;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a FeedItem by its identifying value.
|
||||
*/
|
||||
private static FeedItem searchFeedItemByIdentifyingValue(Feed feed,
|
||||
String identifier) {
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
if (item.getIdentifyingValue().equals(identifier)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new Feed to the database or updates the old version if it already exists. If another Feed with the same
|
||||
* identifying value already exists, this method will add new FeedItems from the new Feed to the existing Feed.
|
||||
* These FeedItems will be marked as unread.
|
||||
* This method should NOT be executed on the GUI thread.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
* @param newFeed The new Feed object.
|
||||
* @return The updated Feed from the database if it already existed, or the new Feed from the parameters otherwise.
|
||||
*/
|
||||
public static synchronized Feed updateFeed(final Context context,
|
||||
final Feed newFeed) {
|
||||
// Look up feed in the feedslist
|
||||
final Feed savedFeed = searchFeedByIdentifyingValue(context,
|
||||
newFeed.getIdentifyingValue());
|
||||
if (savedFeed == null) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"Found no existing Feed with title "
|
||||
+ newFeed.getTitle() + ". Adding as new one.");
|
||||
// Add a new Feed
|
||||
try {
|
||||
DBWriter.addNewFeed(context, newFeed).get();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return newFeed;
|
||||
} else {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Feed with title " + newFeed.getTitle()
|
||||
+ " already exists. Syncing new with existing one.");
|
||||
|
||||
savedFeed.setItems(DBReader.getFeedItemList(context, savedFeed));
|
||||
if (savedFeed.compareWithOther(newFeed)) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"Feed has updated attribute values. Updating old feed's attributes");
|
||||
savedFeed.updateFromOther(newFeed);
|
||||
}
|
||||
// Look for new or updated Items
|
||||
for (int idx = 0; idx < newFeed.getItems().size(); idx++) {
|
||||
final FeedItem item = newFeed.getItems().get(idx);
|
||||
FeedItem oldItem = searchFeedItemByIdentifyingValue(savedFeed,
|
||||
item.getIdentifyingValue());
|
||||
if (oldItem == null) {
|
||||
// item is new
|
||||
final int i = idx;
|
||||
item.setFeed(savedFeed);
|
||||
savedFeed.getItems().add(i, item);
|
||||
DBWriter.markItemRead(context, item.getId(), false);
|
||||
} else {
|
||||
oldItem.updateFromOther(item);
|
||||
}
|
||||
}
|
||||
// update attributes
|
||||
savedFeed.setLastUpdate(newFeed.getLastUpdate());
|
||||
savedFeed.setType(newFeed.getType());
|
||||
try {
|
||||
DBWriter.setCompleteFeed(context, savedFeed).get();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
autodownloadUndownloadedItems(context);
|
||||
}
|
||||
}.start();
|
||||
return savedFeed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the titles of FeedItems of a specific Feed for a given
|
||||
* string.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
* @param feedID The id of the feed whose items should be searched.
|
||||
* @param query The search string.
|
||||
* @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
|
||||
*/
|
||||
public static FutureTask<List<FeedItem>> searchFeedItemTitle(final Context context,
|
||||
final long feedID, final String query) {
|
||||
return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
|
||||
@Override
|
||||
public void execute(PodDBAdapter adapter) {
|
||||
Cursor searchResult = adapter.searchItemTitles(feedID,
|
||||
query);
|
||||
List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
|
||||
DBReader.loadFeedDataOfFeedItemlist(context, items);
|
||||
setResult(items);
|
||||
searchResult.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the descriptions of FeedItems of a specific Feed for a given
|
||||
* string.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
* @param feedID The id of the feed whose items should be searched.
|
||||
* @param query The search string
|
||||
* @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
|
||||
*/
|
||||
public static FutureTask<List<FeedItem>> searchFeedItemDescription(final Context context,
|
||||
final long feedID, final String query) {
|
||||
return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
|
||||
@Override
|
||||
public void execute(PodDBAdapter adapter) {
|
||||
Cursor searchResult = adapter.searchItemDescriptions(feedID,
|
||||
query);
|
||||
List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
|
||||
DBReader.loadFeedDataOfFeedItemlist(context, items);
|
||||
setResult(items);
|
||||
searchResult.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the contentEncoded-value of FeedItems of a specific Feed for a given
|
||||
* string.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
* @param feedID The id of the feed whose items should be searched.
|
||||
* @param query The search string
|
||||
* @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
|
||||
*/
|
||||
public static FutureTask<List<FeedItem>> searchFeedItemContentEncoded(final Context context,
|
||||
final long feedID, final String query) {
|
||||
return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
|
||||
@Override
|
||||
public void execute(PodDBAdapter adapter) {
|
||||
Cursor searchResult = adapter.searchItemContentEncoded(feedID,
|
||||
query);
|
||||
List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
|
||||
DBReader.loadFeedDataOfFeedItemlist(context, items);
|
||||
setResult(items);
|
||||
searchResult.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches chapters of the FeedItems of a specific Feed for a given string.
|
||||
*
|
||||
* @param context Used for accessing the DB.
|
||||
* @param feedID The id of the feed whose items should be searched.
|
||||
* @param query The search string
|
||||
* @return A FutureTask object that executes the search request and returns the search result as a List of FeedItems.
|
||||
*/
|
||||
public static FutureTask<List<FeedItem>> searchFeedItemChapters(final Context context,
|
||||
final long feedID, final String query) {
|
||||
return new FutureTask<List<FeedItem>>(new QueryTask<List<FeedItem>>(context) {
|
||||
@Override
|
||||
public void execute(PodDBAdapter adapter) {
|
||||
Cursor searchResult = adapter.searchItemChapters(feedID,
|
||||
query);
|
||||
List<FeedItem> items = DBReader.extractItemlistFromCursor(context, searchResult);
|
||||
DBReader.loadFeedDataOfFeedItemlist(context, items);
|
||||
setResult(items);
|
||||
searchResult.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A runnable which should be used for database queries. The onCompletion
|
||||
* method is executed on the database executor to handle Cursors correctly.
|
||||
* This class automatically creates a PodDBAdapter object and closes it when
|
||||
* it is no longer in use.
|
||||
*/
|
||||
static abstract class QueryTask<T> implements Callable<T> {
|
||||
private T result;
|
||||
private Context context;
|
||||
|
||||
public QueryTask(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call() throws Exception {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
execute(adapter);
|
||||
adapter.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
public abstract void execute(PodDBAdapter adapter);
|
||||
|
||||
protected void setResult(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
724
src/de/danoeh/antennapod/storage/DBWriter.java
Normal file
724
src/de/danoeh/antennapod/storage/DBWriter.java
Normal file
@ -0,0 +1,724 @@
|
||||
package de.danoeh.antennapod.storage;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.feed.*;
|
||||
import de.danoeh.antennapod.preferences.PlaybackPreferences;
|
||||
import de.danoeh.antennapod.service.PlaybackService;
|
||||
import de.danoeh.antennapod.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.util.QueueAccess;
|
||||
|
||||
/**
|
||||
* Provides methods for writing data to AntennaPod's database.
|
||||
* In general, DBWriter-methods will be executed on an internal ExecutorService.
|
||||
* Some methods return a Future-object which the caller can use for waiting for the method's completion. The returned Future's
|
||||
* will NOT contain any results.
|
||||
* The caller can also use the {@link EventDistributor} in order to be notified about the method's completion asynchronously.
|
||||
* This class will use the {@link EventDistributor} to notify listeners about changes in the database.
|
||||
*/
|
||||
public class DBWriter {
|
||||
private static final String TAG = "DBWriter";
|
||||
|
||||
private static final ExecutorService dbExec;
|
||||
|
||||
static {
|
||||
dbExec = Executors.newSingleThreadExecutor(new ThreadFactory() {
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
return t;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private DBWriter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a downloaded FeedMedia file from the storage device.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param mediaId ID of the FeedMedia object whose downloaded file should be deleted.
|
||||
*/
|
||||
public static Future<?> deleteFeedMediaOfItem(final Context context,
|
||||
final long mediaId) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
final FeedMedia media = DBReader.getFeedMedia(context, mediaId);
|
||||
if (media != null) {
|
||||
boolean result = false;
|
||||
if (media.isDownloaded()) {
|
||||
// delete downloaded media file
|
||||
File mediaFile = new File(media.getFile_url());
|
||||
if (mediaFile.exists()) {
|
||||
result = mediaFile.delete();
|
||||
}
|
||||
media.setDownloaded(false);
|
||||
media.setFile_url(null);
|
||||
setFeedMedia(context, media);
|
||||
|
||||
// If media is currently being played, change playback
|
||||
// type to 'stream' and shutdown playback service
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(context);
|
||||
if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA) {
|
||||
if (media.getId() == PlaybackPreferences
|
||||
.getCurrentlyPlayingFeedMediaId()) {
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(
|
||||
PlaybackPreferences.PREF_CURRENT_EPISODE_IS_STREAM,
|
||||
true);
|
||||
editor.commit();
|
||||
}
|
||||
if (PlaybackPreferences
|
||||
.getCurrentlyPlayingFeedMediaId() == media
|
||||
.getId()) {
|
||||
context.sendBroadcast(new Intent(
|
||||
PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Deleting File. Result: " + result);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a Feed and all downloaded files of its components like images and downloaded episodes.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param feedId ID of the Feed that should be deleted.
|
||||
*/
|
||||
public static Future<?> deleteFeed(final Context context, final long feedId) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DownloadRequester requester = DownloadRequester.getInstance();
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(context
|
||||
.getApplicationContext());
|
||||
final Feed feed = DBReader.getFeed(context, feedId);
|
||||
if (feed != null) {
|
||||
if (PlaybackPreferences.getCurrentlyPlayingMedia() == FeedMedia.PLAYABLE_TYPE_FEEDMEDIA
|
||||
&& PlaybackPreferences.getLastPlayedFeedId() == feed
|
||||
.getId()) {
|
||||
context.sendBroadcast(new Intent(
|
||||
PlaybackService.ACTION_SHUTDOWN_PLAYBACK_SERVICE));
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putLong(
|
||||
PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID,
|
||||
-1);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
// delete image file
|
||||
if (feed.getImage() != null) {
|
||||
if (feed.getImage().isDownloaded()
|
||||
&& feed.getImage().getFile_url() != null) {
|
||||
File imageFile = new File(feed.getImage()
|
||||
.getFile_url());
|
||||
imageFile.delete();
|
||||
} else if (requester.isDownloadingFile(feed.getImage())) {
|
||||
requester.cancelDownload(context, feed.getImage());
|
||||
}
|
||||
}
|
||||
// delete stored media files and mark them as read
|
||||
List<FeedItem> queue = DBReader.getQueue(context);
|
||||
boolean queueWasModified = false;
|
||||
if (feed.getItems() == null) {
|
||||
DBReader.getFeedItemList(context, feed);
|
||||
}
|
||||
|
||||
for (FeedItem item : feed.getItems()) {
|
||||
queueWasModified |= queue.remove(item);
|
||||
if (item.getMedia() != null
|
||||
&& item.getMedia().isDownloaded()) {
|
||||
File mediaFile = new File(item.getMedia()
|
||||
.getFile_url());
|
||||
mediaFile.delete();
|
||||
} else if (item.getMedia() != null
|
||||
&& requester.isDownloadingFile(item.getMedia())) {
|
||||
requester.cancelDownload(context, item.getMedia());
|
||||
}
|
||||
}
|
||||
if (queueWasModified) {
|
||||
adapter.setQueue(queue);
|
||||
}
|
||||
adapter.removeFeed(feed);
|
||||
adapter.close();
|
||||
EventDistributor.getInstance().sendFeedUpdateBroadcast();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the entire playback history.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
*/
|
||||
public static Future<?> clearPlaybackHistory(final Context context) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
adapter.clearPlaybackHistory();
|
||||
adapter.close();
|
||||
EventDistributor.getInstance()
|
||||
.sendPlaybackHistoryUpdateBroadcast();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a FeedMedia object to the playback history. A FeedMedia object is in the playback history if
|
||||
* its playback completion date is set to a non-null value. This method will set the playback completion date to the
|
||||
* current date regardless of the current value.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param media FeedMedia that should be added to the playback history.
|
||||
*/
|
||||
public static Future<?> addItemToPlaybackHistory(final Context context,
|
||||
final FeedMedia media) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Adding new item to playback history");
|
||||
media.setPlaybackCompletionDate(new Date());
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
adapter.setMedia(media);
|
||||
adapter.close();
|
||||
EventDistributor.getInstance().sendPlaybackHistoryUpdateBroadcast();
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void cleanupDownloadLog(final PodDBAdapter adapter) {
|
||||
final long logSize = adapter.getDownloadLogSize();
|
||||
if (logSize > DBReader.DOWNLOAD_LOG_SIZE) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Cleaning up download log");
|
||||
adapter.removeDownloadLogItems(logSize - DBReader.DOWNLOAD_LOG_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Download status object to the download log.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param status The DownloadStatus object.
|
||||
*/
|
||||
public static Future<?> addDownloadStatus(final Context context,
|
||||
final DownloadStatus status) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
|
||||
adapter.setDownloadStatus(status);
|
||||
cleanupDownloadLog(adapter);
|
||||
adapter.close();
|
||||
EventDistributor.getInstance().sendDownloadLogUpdateBroadcast();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a FeedItem in the queue at the specified index. The 'read'-attribute of the FeedItem will be set to
|
||||
* true. If the FeedItem is already in the queue, the queue will not be modified.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param itemId ID of the FeedItem that should be added to the queue.
|
||||
* @param index Destination index. Must be in range 0..queue.size()
|
||||
* @param performAutoDownload True if an auto-download process should be started after the operation
|
||||
* @throws IndexOutOfBoundsException if index < 0 || index >= queue.size()
|
||||
*/
|
||||
public static Future<?> addQueueItemAt(final Context context, final long itemId,
|
||||
final int index, final boolean performAutoDownload) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
final List<FeedItem> queue = DBReader
|
||||
.getQueue(context, adapter);
|
||||
FeedItem item = null;
|
||||
|
||||
if (queue != null) {
|
||||
boolean queueModified = false;
|
||||
boolean unreadItemsModified = false;
|
||||
|
||||
if (!itemListContains(queue, itemId)) {
|
||||
item = DBReader.getFeedItem(context, itemId);
|
||||
if (item != null) {
|
||||
queue.add(index, item);
|
||||
queueModified = true;
|
||||
if (!item.isRead()) {
|
||||
item.setRead(true);
|
||||
unreadItemsModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (queueModified) {
|
||||
adapter.setQueue(queue);
|
||||
EventDistributor.getInstance()
|
||||
.sendQueueUpdateBroadcast();
|
||||
}
|
||||
if (unreadItemsModified && item != null) {
|
||||
adapter.setSingleFeedItem(item);
|
||||
EventDistributor.getInstance()
|
||||
.sendUnreadItemsUpdateBroadcast();
|
||||
}
|
||||
}
|
||||
adapter.close();
|
||||
if (performAutoDownload) {
|
||||
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
DBTasks.autodownloadUndownloadedItems(context);
|
||||
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends FeedItem objects to the end of the queue. The 'read'-attribute of all items will be set to true.
|
||||
* If a FeedItem is already in the queue, the FeedItem will not change its position in the queue.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param itemIds IDs of the FeedItem objects that should be added to the queue.
|
||||
*/
|
||||
public static Future<?> addQueueItem(final Context context,
|
||||
final long... itemIds) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (itemIds.length > 0) {
|
||||
final PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
final List<FeedItem> queue = DBReader.getQueue(context,
|
||||
adapter);
|
||||
|
||||
if (queue != null) {
|
||||
boolean queueModified = false;
|
||||
boolean unreadItemsModified = false;
|
||||
List<FeedItem> itemsToSave = new LinkedList<FeedItem>();
|
||||
for (int i = 0; i < itemIds.length; i++) {
|
||||
if (!itemListContains(queue, itemIds[i])) {
|
||||
final FeedItem item = DBReader.getFeedItem(
|
||||
context, itemIds[i]);
|
||||
|
||||
if (item != null) {
|
||||
queue.add(item);
|
||||
queueModified = true;
|
||||
if (!item.isRead()) {
|
||||
item.setRead(true);
|
||||
itemsToSave.add(item);
|
||||
unreadItemsModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (queueModified) {
|
||||
adapter.setQueue(queue);
|
||||
EventDistributor.getInstance()
|
||||
.sendQueueUpdateBroadcast();
|
||||
}
|
||||
if (unreadItemsModified) {
|
||||
adapter.setFeedItemlist(itemsToSave);
|
||||
EventDistributor.getInstance()
|
||||
.sendUnreadItemsUpdateBroadcast();
|
||||
}
|
||||
}
|
||||
adapter.close();
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
DBTasks.autodownloadUndownloadedItems(context);
|
||||
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all FeedItem objects from the queue.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
*/
|
||||
public static Future<?> clearQueue(final Context context) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
adapter.clearQueue();
|
||||
adapter.close();
|
||||
|
||||
EventDistributor.getInstance().sendQueueUpdateBroadcast();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a FeedItem object from the queue.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param itemId ID of the FeedItem that should be removed.
|
||||
* @param performAutoDownload true if an auto-download process should be started after the operation.
|
||||
*/
|
||||
public static Future<?> removeQueueItem(final Context context,
|
||||
final long itemId, final boolean performAutoDownload) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
final List<FeedItem> queue = DBReader
|
||||
.getQueue(context, adapter);
|
||||
FeedItem item = null;
|
||||
|
||||
if (queue != null) {
|
||||
boolean queueModified = false;
|
||||
QueueAccess queueAccess = QueueAccess.ItemListAccess(queue);
|
||||
if (queueAccess.contains(itemId)) {
|
||||
item = DBReader.getFeedItem(context, itemId);
|
||||
if (item != null) {
|
||||
queueModified = queueAccess.remove(itemId);
|
||||
}
|
||||
}
|
||||
if (queueModified) {
|
||||
adapter.setQueue(queue);
|
||||
EventDistributor.getInstance()
|
||||
.sendQueueUpdateBroadcast();
|
||||
} else {
|
||||
Log.w(TAG, "Queue was not modified by call to removeQueueItem");
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "removeQueueItem: Could not load queue");
|
||||
}
|
||||
adapter.close();
|
||||
if (performAutoDownload) {
|
||||
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
DBTasks.autodownloadUndownloadedItems(context);
|
||||
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the position of a FeedItem in the queue.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param from Source index. Must be in range 0..queue.size()-1.
|
||||
* @param to Destination index. Must be in range 0..queue.size()-1.
|
||||
* @param broadcastUpdate true if this operation should trigger a QueueUpdateBroadcast. This option should be set to
|
||||
* false if the caller wants to avoid unexpected updates of the GUI.
|
||||
* @throws IndexOutOfBoundsException if (to < 0 || to >= queue.size()) || (from < 0 || from >= queue.size())
|
||||
*/
|
||||
public static Future<?> moveQueueItem(final Context context, final int from,
|
||||
final int to, final boolean broadcastUpdate) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
final List<FeedItem> queue = DBReader
|
||||
.getQueue(context, adapter);
|
||||
|
||||
if (queue != null) {
|
||||
if (from >= 0 && from < queue.size() && to >= 0
|
||||
&& to < queue.size()) {
|
||||
|
||||
final FeedItem item = queue.remove(from);
|
||||
queue.add(to, item);
|
||||
|
||||
adapter.setQueue(queue);
|
||||
if (broadcastUpdate) {
|
||||
EventDistributor.getInstance()
|
||||
.sendQueueUpdateBroadcast();
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "moveQueueItem: Could not load queue");
|
||||
}
|
||||
adapter.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the 'read'-attribute of a FeedItem to the specified value.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param item The FeedItem object
|
||||
* @param read New value of the 'read'-attribute
|
||||
* @param resetMediaPosition true if this method should also reset the position of the FeedItem's FeedMedia object.
|
||||
* If the FeedItem has no FeedMedia object, this parameter will be ignored.
|
||||
*/
|
||||
public static Future<?> markItemRead(Context context, FeedItem item, boolean read, boolean resetMediaPosition) {
|
||||
long mediaId = (item.hasMedia()) ? item.getMedia().getId() : 0;
|
||||
return markItemRead(context, item.getId(), read, mediaId, resetMediaPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the 'read'-attribute of a FeedItem to the specified value.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param itemId ID of the FeedItem
|
||||
* @param read New value of the 'read'-attribute
|
||||
*/
|
||||
public static Future<?> markItemRead(final Context context, final long itemId,
|
||||
final boolean read) {
|
||||
return markItemRead(context, itemId, read, 0, false);
|
||||
}
|
||||
|
||||
private static Future<?> markItemRead(final Context context, final long itemId,
|
||||
final boolean read, final long mediaId,
|
||||
final boolean resetMediaPosition) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
adapter.setFeedItemRead(read, itemId, mediaId,
|
||||
resetMediaPosition);
|
||||
adapter.close();
|
||||
|
||||
EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the 'read'-attribute of all FeedItems of a specific Feed to true.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param feedId ID of the Feed.
|
||||
*/
|
||||
public static Future<?> markFeedRead(final Context context, final long feedId) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
Cursor itemCursor = adapter.getAllItemsOfFeedCursor(feedId);
|
||||
long[] itemIds = new long[itemCursor.getCount()];
|
||||
itemCursor.moveToFirst();
|
||||
for (int i = 0; i < itemIds.length; i++) {
|
||||
itemIds[i] = itemCursor.getLong(PodDBAdapter.KEY_ID_INDEX);
|
||||
}
|
||||
itemCursor.close();
|
||||
adapter.setFeedItemRead(true, itemIds);
|
||||
adapter.close();
|
||||
|
||||
EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the 'read'-attribute of all FeedItems to true.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
*/
|
||||
public static Future<?> markAllItemsRead(final Context context) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
Cursor itemCursor = adapter.getUnreadItemsCursor();
|
||||
long[] itemIds = new long[itemCursor.getCount()];
|
||||
itemCursor.moveToFirst();
|
||||
for (int i = 0; i < itemIds.length; i++) {
|
||||
itemIds[i] = itemCursor.getLong(PodDBAdapter.KEY_ID_INDEX);
|
||||
}
|
||||
itemCursor.close();
|
||||
adapter.setFeedItemRead(true, itemIds);
|
||||
adapter.close();
|
||||
|
||||
EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
static Future<?> addNewFeed(final Context context, final Feed feed) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
adapter.setCompleteFeed(feed);
|
||||
adapter.close();
|
||||
|
||||
EventDistributor.getInstance().sendFeedUpdateBroadcast();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static Future<?> setCompleteFeed(final Context context, final Feed feed) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
adapter.setCompleteFeed(feed);
|
||||
adapter.close();
|
||||
|
||||
EventDistributor.getInstance().sendFeedUpdateBroadcast();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a FeedMedia object in the database. This method will save all attributes of the FeedMedia object. The
|
||||
* contents of FeedComponent-attributes (e.g. the FeedMedia's 'item'-attribute) will not be saved.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param media The FeedMedia object.
|
||||
*/
|
||||
public static Future<?> setFeedMedia(final Context context,
|
||||
final FeedMedia media) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
adapter.setMedia(media);
|
||||
adapter.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves only value of the 'position'-attribute of a FeedMedia object.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param media The FeedMedia object.
|
||||
*/
|
||||
public static Future<?> setFeedMediaPosition(final Context context, final FeedMedia media) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
adapter.setFeedMediaPosition(media);
|
||||
adapter.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a FeedItem object in the database. This method will save all attributes of the FeedItem object including
|
||||
* the content of FeedComponent-attributes.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param item The FeedItem object.
|
||||
*/
|
||||
public static Future<?> setFeedItem(final Context context,
|
||||
final FeedItem item) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
adapter.setSingleFeedItem(item);
|
||||
adapter.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a FeedImage object in the database. This method will save all attributes of the FeedImage object. The
|
||||
* contents of FeedComponent-attributes (e.g. the FeedImages's 'feed'-attribute) will not be saved.
|
||||
*
|
||||
* @param context A context that is used for opening a database connection.
|
||||
* @param image The FeedImage object.
|
||||
*/
|
||||
public static Future<?> setFeedImage(final Context context,
|
||||
final FeedImage image) {
|
||||
return dbExec.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||
adapter.open();
|
||||
adapter.setImage(image);
|
||||
adapter.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean itemListContains(List<FeedItem> items, long itemId) {
|
||||
for (FeedItem item : items) {
|
||||
if (item.getId() == itemId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.text.ExtendedMessageFormat;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -18,301 +18,283 @@ 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.DownloadRequest;
|
||||
import de.danoeh.antennapod.service.download.DownloadService;
|
||||
import de.danoeh.antennapod.util.FileNameGenerator;
|
||||
import de.danoeh.antennapod.util.URLChecker;
|
||||
|
||||
public class DownloadRequester {
|
||||
private static final String TAG = "DownloadRequester";
|
||||
private static final String TAG = "DownloadRequester";
|
||||
|
||||
public static String IMAGE_DOWNLOADPATH = "images/";
|
||||
public static String FEED_DOWNLOADPATH = "cache/";
|
||||
public static String MEDIA_DOWNLOADPATH = "media/";
|
||||
public static String IMAGE_DOWNLOADPATH = "images/";
|
||||
public static String FEED_DOWNLOADPATH = "cache/";
|
||||
public static String MEDIA_DOWNLOADPATH = "media/";
|
||||
|
||||
private static DownloadRequester downloader;
|
||||
private static DownloadRequester downloader;
|
||||
|
||||
Map<String, FeedFile> downloads;
|
||||
Map<String, DownloadRequest> downloads;
|
||||
|
||||
private DownloadRequester() {
|
||||
downloads = new ConcurrentHashMap<String, FeedFile>();
|
||||
}
|
||||
private DownloadRequester() {
|
||||
downloads = new ConcurrentHashMap<String, DownloadRequest>();
|
||||
}
|
||||
|
||||
public static DownloadRequester getInstance() {
|
||||
if (downloader == null) {
|
||||
downloader = new DownloadRequester();
|
||||
}
|
||||
return downloader;
|
||||
}
|
||||
public static DownloadRequester getInstance() {
|
||||
if (downloader == null) {
|
||||
downloader = new DownloadRequester();
|
||||
}
|
||||
return downloader;
|
||||
}
|
||||
|
||||
private void download(Context context, FeedFile item, File dest,
|
||||
boolean overwriteIfExists) {
|
||||
if (!isDownloadingFile(item)) {
|
||||
if (!isFilenameAvailable(dest.toString()) || dest.exists()) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Filename already used.");
|
||||
if (isFilenameAvailable(dest.toString()) && overwriteIfExists) {
|
||||
boolean result = dest.delete();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Deleting file. Result: " + result);
|
||||
} else {
|
||||
// find different name
|
||||
File newDest = null;
|
||||
for (int i = 1; i < Integer.MAX_VALUE; i++) {
|
||||
String newName = FilenameUtils.getBaseName(dest
|
||||
.getName())
|
||||
+ "-"
|
||||
+ i
|
||||
+ FilenameUtils.EXTENSION_SEPARATOR
|
||||
+ FilenameUtils.getExtension(dest.getName());
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Testing filename " + newName);
|
||||
newDest = new File(dest.getParent(), newName);
|
||||
if (!newDest.exists()
|
||||
&& isFilenameAvailable(newDest.toString())) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "File doesn't exist yet. Using "
|
||||
+ newName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newDest != null) {
|
||||
dest = newDest;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"Requesting download of url " + item.getDownload_url());
|
||||
item.setDownload_url(URLChecker.prepareURL(item.getDownload_url()));
|
||||
item.setFile_url(dest.toString());
|
||||
downloads.put(item.getDownload_url(), item);
|
||||
private void download(Context context, FeedFile item, File dest,
|
||||
boolean overwriteIfExists) {
|
||||
if (!isDownloadingFile(item)) {
|
||||
if (!isFilenameAvailable(dest.toString()) || dest.exists()) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Filename already used.");
|
||||
if (isFilenameAvailable(dest.toString()) && overwriteIfExists) {
|
||||
boolean result = dest.delete();
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Deleting file. Result: " + result);
|
||||
} else {
|
||||
// find different name
|
||||
File newDest = null;
|
||||
for (int i = 1; i < Integer.MAX_VALUE; i++) {
|
||||
String newName = FilenameUtils.getBaseName(dest
|
||||
.getName())
|
||||
+ "-"
|
||||
+ i
|
||||
+ "."
|
||||
+ FilenameUtils.getExtension(dest.getName());
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Testing filename " + newName);
|
||||
newDest = new File(dest.getParent(), newName);
|
||||
if (!newDest.exists()
|
||||
&& isFilenameAvailable(newDest.toString())) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "File doesn't exist yet. Using "
|
||||
+ newName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newDest != null) {
|
||||
dest = newDest;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG,
|
||||
"Requesting download of url " + item.getDownload_url());
|
||||
item.setDownload_url(URLChecker.prepareURL(item.getDownload_url()));
|
||||
|
||||
DownloadService.Request request = new DownloadService.Request(
|
||||
item.getFile_url(), item.getDownload_url());
|
||||
DownloadRequest request = new DownloadRequest(dest.toString(),
|
||||
item.getDownload_url(), item.getHumanReadableIdentifier(),
|
||||
item.getId(), item.getTypeAsInt());
|
||||
|
||||
if (!DownloadService.isRunning) {
|
||||
Intent launchIntent = new Intent(context, DownloadService.class);
|
||||
launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request);
|
||||
context.startService(launchIntent);
|
||||
} else {
|
||||
Intent queueIntent = new Intent(
|
||||
DownloadService.ACTION_ENQUEUE_DOWNLOAD);
|
||||
queueIntent.putExtra(DownloadService.EXTRA_REQUEST, request);
|
||||
context.sendBroadcast(queueIntent);
|
||||
}
|
||||
EventDistributor.getInstance().sendDownloadQueuedBroadcast();
|
||||
} else {
|
||||
Log.e(TAG, "URL " + item.getDownload_url()
|
||||
+ " is already being downloaded");
|
||||
}
|
||||
}
|
||||
downloads.put(request.getSource(), request);
|
||||
|
||||
/**
|
||||
* Returns true if a filename is available and false if it has already been
|
||||
* taken by another requested download.
|
||||
*/
|
||||
private boolean isFilenameAvailable(String path) {
|
||||
for (String key : downloads.keySet()) {
|
||||
FeedFile f = downloads.get(key);
|
||||
if (f.getFile_url() != null && f.getFile_url().equals(path)) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, path
|
||||
+ " is already used by another requested download");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, path + " is available as a download destination");
|
||||
return true;
|
||||
}
|
||||
Intent launchIntent = new Intent(context, DownloadService.class);
|
||||
launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request);
|
||||
context.startService(launchIntent);
|
||||
EventDistributor.getInstance().sendDownloadQueuedBroadcast();
|
||||
} else {
|
||||
Log.e(TAG, "URL " + item.getDownload_url()
|
||||
+ " is already being downloaded");
|
||||
}
|
||||
}
|
||||
|
||||
public void downloadFeed(Context context, Feed feed)
|
||||
throws DownloadRequestException {
|
||||
if (feedFileValid(feed)) {
|
||||
download(context, feed, new File(getFeedfilePath(context),
|
||||
getFeedfileName(feed)), true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Returns true if a filename is available and false if it has already been
|
||||
* taken by another requested download.
|
||||
*/
|
||||
private boolean isFilenameAvailable(String path) {
|
||||
for (String key : downloads.keySet()) {
|
||||
DownloadRequest r = downloads.get(key);
|
||||
if (StringUtils.equals(r.getDestination(), path)) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, path
|
||||
+ " is already used by another requested download");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, path + " is available as a download destination");
|
||||
return true;
|
||||
}
|
||||
|
||||
public void downloadImage(Context context, FeedImage image)
|
||||
throws DownloadRequestException {
|
||||
if (feedFileValid(image)) {
|
||||
download(context, image, new File(getImagefilePath(context),
|
||||
getImagefileName(image)), true);
|
||||
}
|
||||
}
|
||||
public void downloadFeed(Context context, Feed feed)
|
||||
throws DownloadRequestException {
|
||||
if (feedFileValid(feed)) {
|
||||
download(context, feed, new File(getFeedfilePath(context),
|
||||
getFeedfileName(feed)), true);
|
||||
}
|
||||
}
|
||||
|
||||
public void downloadMedia(Context context, FeedMedia feedmedia)
|
||||
throws DownloadRequestException {
|
||||
if (feedFileValid(feedmedia)) {
|
||||
download(context, feedmedia,
|
||||
new File(getMediafilePath(context, feedmedia),
|
||||
getMediafilename(feedmedia)), false);
|
||||
}
|
||||
}
|
||||
public void downloadImage(Context context, FeedImage image)
|
||||
throws DownloadRequestException {
|
||||
if (feedFileValid(image)) {
|
||||
download(context, image, new File(getImagefilePath(context),
|
||||
getImagefileName(image)), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a DownloadRequestException if the feedfile or the download url of
|
||||
* the feedfile is null.
|
||||
*
|
||||
* @throws DownloadRequestException
|
||||
*/
|
||||
private boolean feedFileValid(FeedFile f) throws DownloadRequestException {
|
||||
if (f == null) {
|
||||
throw new DownloadRequestException("Feedfile was null");
|
||||
} else if (f.getDownload_url() == null) {
|
||||
throw new DownloadRequestException("File has no download URL");
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public void downloadMedia(Context context, FeedMedia feedmedia)
|
||||
throws DownloadRequestException {
|
||||
if (feedFileValid(feedmedia)) {
|
||||
download(context, feedmedia,
|
||||
new File(getMediafilePath(context, feedmedia),
|
||||
getMediafilename(feedmedia)), false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a running download.
|
||||
* */
|
||||
public void cancelDownload(final Context context, final FeedFile f) {
|
||||
cancelDownload(context, f.getDownload_url());
|
||||
}
|
||||
/**
|
||||
* Throws a DownloadRequestException if the feedfile or the download url of
|
||||
* the feedfile is null.
|
||||
*
|
||||
* @throws DownloadRequestException
|
||||
*/
|
||||
private boolean feedFileValid(FeedFile f) throws DownloadRequestException {
|
||||
if (f == null) {
|
||||
throw new DownloadRequestException("Feedfile was null");
|
||||
} else if (f.getDownload_url() == null) {
|
||||
throw new DownloadRequestException("File has no download URL");
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a running download.
|
||||
* */
|
||||
public void cancelDownload(final Context context, final String downloadUrl) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Cancelling download with url " + downloadUrl);
|
||||
Intent cancelIntent = new Intent(DownloadService.ACTION_CANCEL_DOWNLOAD);
|
||||
cancelIntent.putExtra(DownloadService.EXTRA_DOWNLOAD_URL, downloadUrl);
|
||||
context.sendBroadcast(cancelIntent);
|
||||
}
|
||||
/**
|
||||
* Cancels a running download.
|
||||
*/
|
||||
public void cancelDownload(final Context context, final FeedFile f) {
|
||||
cancelDownload(context, f.getDownload_url());
|
||||
}
|
||||
|
||||
/** Cancels all running downloads */
|
||||
public void cancelAllDownloads(Context context) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Cancelling all running downloads");
|
||||
context.sendBroadcast(new Intent(
|
||||
DownloadService.ACTION_CANCEL_ALL_DOWNLOADS));
|
||||
}
|
||||
/**
|
||||
* Cancels a running download.
|
||||
*/
|
||||
public void cancelDownload(final Context context, final String downloadUrl) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Cancelling download with url " + downloadUrl);
|
||||
Intent cancelIntent = new Intent(DownloadService.ACTION_CANCEL_DOWNLOAD);
|
||||
cancelIntent.putExtra(DownloadService.EXTRA_DOWNLOAD_URL, downloadUrl);
|
||||
context.sendBroadcast(cancelIntent);
|
||||
}
|
||||
|
||||
/** Returns true if there is at least one Feed in the downloads queue. */
|
||||
public boolean isDownloadingFeeds() {
|
||||
for (FeedFile f : downloads.values()) {
|
||||
if (f.getClass() == Feed.class) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Cancels all running downloads
|
||||
*/
|
||||
public void cancelAllDownloads(Context context) {
|
||||
if (AppConfig.DEBUG)
|
||||
Log.d(TAG, "Cancelling all running downloads");
|
||||
context.sendBroadcast(new Intent(
|
||||
DownloadService.ACTION_CANCEL_ALL_DOWNLOADS));
|
||||
}
|
||||
|
||||
/** Checks if feedfile is in the downloads list */
|
||||
public boolean isDownloadingFile(FeedFile item) {
|
||||
if (item.getDownload_url() != null) {
|
||||
return downloads.containsKey(item.getDownload_url());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns true if there is at least one Feed in the downloads queue.
|
||||
*/
|
||||
public boolean isDownloadingFeeds() {
|
||||
for (DownloadRequest r : downloads.values()) {
|
||||
if (r.getFeedfileType() == Feed.FEEDFILETYPE_FEED) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public FeedFile getDownload(String downloadUrl) {
|
||||
return downloads.get(downloadUrl);
|
||||
}
|
||||
/**
|
||||
* Checks if feedfile is in the downloads list
|
||||
*/
|
||||
public boolean isDownloadingFile(FeedFile item) {
|
||||
if (item.getDownload_url() != null) {
|
||||
return downloads.containsKey(item.getDownload_url());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Checks if feedfile with the given download url is in the downloads list */
|
||||
public boolean isDownloadingFile(String downloadUrl) {
|
||||
return downloads.get(downloadUrl) != null;
|
||||
}
|
||||
public DownloadRequest getDownload(String downloadUrl) {
|
||||
return downloads.get(downloadUrl);
|
||||
}
|
||||
|
||||
public boolean hasNoDownloads() {
|
||||
return downloads.isEmpty();
|
||||
}
|
||||
/**
|
||||
* Checks if feedfile with the given download url is in the downloads list
|
||||
*/
|
||||
public boolean isDownloadingFile(String downloadUrl) {
|
||||
return downloads.get(downloadUrl) != null;
|
||||
}
|
||||
|
||||
public FeedFile getDownloadAt(int index) {
|
||||
return downloads.get(index);
|
||||
}
|
||||
public boolean hasNoDownloads() {
|
||||
return downloads.isEmpty();
|
||||
}
|
||||
|
||||
/** Remove an object from the downloads-list of the requester. */
|
||||
public void removeDownload(FeedFile f) {
|
||||
if (downloads.remove(f.getDownload_url()) == null) {
|
||||
Log.e(TAG,
|
||||
"Could not remove object with url " + f.getDownload_url());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Remove an object from the downloads-list of the requester.
|
||||
*/
|
||||
public void removeDownload(DownloadRequest r) {
|
||||
if (downloads.remove(r.getSource()) == null) {
|
||||
Log.e(TAG,
|
||||
"Could not remove object with url " + r.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
/** Get the number of uncompleted Downloads */
|
||||
public int getNumberOfDownloads() {
|
||||
return downloads.size();
|
||||
}
|
||||
/**
|
||||
* Get the number of uncompleted Downloads
|
||||
*/
|
||||
public int getNumberOfDownloads() {
|
||||
return downloads.size();
|
||||
}
|
||||
|
||||
public String getFeedfilePath(Context context)
|
||||
throws DownloadRequestException {
|
||||
return getExternalFilesDirOrThrowException(context, FEED_DOWNLOADPATH)
|
||||
.toString() + "/";
|
||||
}
|
||||
public String getFeedfilePath(Context context)
|
||||
throws DownloadRequestException {
|
||||
return getExternalFilesDirOrThrowException(context, FEED_DOWNLOADPATH)
|
||||
.toString() + "/";
|
||||
}
|
||||
|
||||
public String getFeedfileName(Feed feed) {
|
||||
String filename = feed.getDownload_url();
|
||||
if (feed.getTitle() != null && !feed.getTitle().isEmpty()) {
|
||||
filename = feed.getTitle();
|
||||
}
|
||||
return "feed-" + FileNameGenerator.generateFileName(filename);
|
||||
}
|
||||
public String getFeedfileName(Feed feed) {
|
||||
String filename = feed.getDownload_url();
|
||||
if (feed.getTitle() != null && !feed.getTitle().isEmpty()) {
|
||||
filename = feed.getTitle();
|
||||
}
|
||||
return "feed-" + FileNameGenerator.generateFileName(filename);
|
||||
}
|
||||
|
||||
public String getImagefilePath(Context context)
|
||||
throws DownloadRequestException {
|
||||
return getExternalFilesDirOrThrowException(context, IMAGE_DOWNLOADPATH)
|
||||
.toString() + "/";
|
||||
}
|
||||
public String getImagefilePath(Context context)
|
||||
throws DownloadRequestException {
|
||||
return getExternalFilesDirOrThrowException(context, IMAGE_DOWNLOADPATH)
|
||||
.toString() + "/";
|
||||
}
|
||||
|
||||
public String getImagefileName(FeedImage image) {
|
||||
String filename = image.getDownload_url();
|
||||
if (image.getFeed() != null && image.getFeed().getTitle() != null) {
|
||||
filename = image.getFeed().getTitle();
|
||||
}
|
||||
return "image-" + FileNameGenerator.generateFileName(filename);
|
||||
}
|
||||
public String getImagefileName(FeedImage image) {
|
||||
String filename = image.getDownload_url();
|
||||
if (image.getFeed() != null && image.getFeed().getTitle() != null) {
|
||||
filename = image.getFeed().getTitle();
|
||||
}
|
||||
return "image-" + FileNameGenerator.generateFileName(filename);
|
||||
}
|
||||
|
||||
public String getMediafilePath(Context context, FeedMedia media)
|
||||
throws DownloadRequestException {
|
||||
File externalStorage = getExternalFilesDirOrThrowException(
|
||||
context,
|
||||
MEDIA_DOWNLOADPATH
|
||||
+ FileNameGenerator.generateFileName(media.getItem()
|
||||
.getFeed().getTitle()) + "/");
|
||||
return externalStorage.toString();
|
||||
}
|
||||
public String getMediafilePath(Context context, FeedMedia media)
|
||||
throws DownloadRequestException {
|
||||
File externalStorage = getExternalFilesDirOrThrowException(
|
||||
context,
|
||||
MEDIA_DOWNLOADPATH
|
||||
+ FileNameGenerator.generateFileName(media.getItem()
|
||||
.getFeed().getTitle()) + "/");
|
||||
return externalStorage.toString();
|
||||
}
|
||||
|
||||
private File getExternalFilesDirOrThrowException(Context context,
|
||||
String type) throws DownloadRequestException {
|
||||
File result = UserPreferences.getDataFolder(context, type);
|
||||
if (result == null) {
|
||||
throw new DownloadRequestException(
|
||||
"Failed to access external storage");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private File getExternalFilesDirOrThrowException(Context context,
|
||||
String type) throws DownloadRequestException {
|
||||
File result = UserPreferences.getDataFolder(context, type);
|
||||
if (result == null) {
|
||||
throw new DownloadRequestException(
|
||||
"Failed to access external storage");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getMediafilename(FeedMedia media) {
|
||||
String filename;
|
||||
String titleBaseFilename = "";
|
||||
|
||||
// Try to generate the filename by the item title
|
||||
if (media.getItem() != null && media.getItem().getTitle() != null) {
|
||||
String title = media.getItem().getTitle();
|
||||
// Delete reserved characters
|
||||
titleBaseFilename = title.replaceAll("[\\\\/%\\?\\*:|<>\"\\p{Cntrl}]", "");
|
||||
titleBaseFilename = titleBaseFilename.trim();
|
||||
}
|
||||
|
||||
String URLBaseFilename = URLUtil.guessFileName(media.getDownload_url(),
|
||||
null, media.getMime_type());;
|
||||
|
||||
if (titleBaseFilename != "") {
|
||||
// Append extension
|
||||
filename = titleBaseFilename + FilenameUtils.EXTENSION_SEPARATOR +
|
||||
FilenameUtils.getExtension(URLBaseFilename);
|
||||
} else {
|
||||
// Fall back on URL file name
|
||||
filename = URLBaseFilename;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
public String getMediafilename(FeedMedia media) {
|
||||
return URLUtil.guessFileName(media.getDownload_url(), null,
|
||||
media.getMime_type());
|
||||
}
|
||||
|
||||
}
|
||||
|
42
src/de/danoeh/antennapod/storage/FeedItemStatistics.java
Normal file
42
src/de/danoeh/antennapod/storage/FeedItemStatistics.java
Normal file
@ -0,0 +1,42 @@
|
||||
package de.danoeh.antennapod.storage;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Contains information about a feed's items.
|
||||
*/
|
||||
public class FeedItemStatistics {
|
||||
private long feedID;
|
||||
private int numberOfItems;
|
||||
private int numberOfNewItems;
|
||||
private int numberOfInProgressItems;
|
||||
private Date lastUpdate;
|
||||
|
||||
public FeedItemStatistics(long feedID, int numberOfItems, int numberOfNewItems, int numberOfInProgressItems, Date lastUpdate) {
|
||||
this.feedID = feedID;
|
||||
this.numberOfItems = numberOfItems;
|
||||
this.numberOfNewItems = numberOfNewItems;
|
||||
this.numberOfInProgressItems = numberOfInProgressItems;
|
||||
this.lastUpdate = lastUpdate;
|
||||
}
|
||||
|
||||
public long getFeedID() {
|
||||
return feedID;
|
||||
}
|
||||
|
||||
public int getNumberOfItems() {
|
||||
return numberOfItems;
|
||||
}
|
||||
|
||||
public int getNumberOfNewItems() {
|
||||
return numberOfNewItems;
|
||||
}
|
||||
|
||||
public int getNumberOfInProgressItems() {
|
||||
return numberOfInProgressItems;
|
||||
}
|
||||
|
||||
public Date getLastUpdate() {
|
||||
return lastUpdate;
|
||||
}
|
||||
}
|
57
src/de/danoeh/antennapod/storage/FeedSearcher.java
Normal file
57
src/de/danoeh/antennapod/storage/FeedSearcher.java
Normal file
@ -0,0 +1,57 @@
|
||||
package de.danoeh.antennapod.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.feed.FeedItem;
|
||||
import de.danoeh.antennapod.feed.SearchResult;
|
||||
import de.danoeh.antennapod.util.comparator.SearchResultValueComparator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
/**
|
||||
* Performs search on Feeds and FeedItems
|
||||
*/
|
||||
public class FeedSearcher {
|
||||
private static final String TAG = "FeedSearcher";
|
||||
|
||||
|
||||
/**
|
||||
* Performs a search in all feeds or one specific feed.
|
||||
*/
|
||||
public static List<SearchResult> performSearch(final Context context,
|
||||
final String query, final long selectedFeed) {
|
||||
final int values[] = {0, 0, 1, 2};
|
||||
final String[] subtitles = {context.getString(R.string.found_in_shownotes_label),
|
||||
context.getString(R.string.found_in_shownotes_label),
|
||||
context.getString(R.string.found_in_chapters_label),
|
||||
context.getString(R.string.found_in_title_label)};
|
||||
|
||||
List<SearchResult> result = new ArrayList<SearchResult>();
|
||||
|
||||
FutureTask<List<FeedItem>>[] tasks = new FutureTask[4];
|
||||
(tasks[0] = DBTasks.searchFeedItemContentEncoded(context, selectedFeed, query)).run();
|
||||
(tasks[1] = DBTasks.searchFeedItemDescription(context, selectedFeed, query)).run();
|
||||
(tasks[2] = DBTasks.searchFeedItemChapters(context, selectedFeed, query)).run();
|
||||
(tasks[3] = DBTasks.searchFeedItemTitle(context, selectedFeed, query)).run();
|
||||
try {
|
||||
for (int i = 0; i < tasks.length; i++) {
|
||||
FutureTask task = tasks[i];
|
||||
List<FeedItem> items = (List<FeedItem>) task.get();
|
||||
for (FeedItem item : items) {
|
||||
result.add(new SearchResult(item, values[i], subtitles[i]));
|
||||
}
|
||||
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Collections.sort(result, new SearchResultValueComparator());
|
||||
return result;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
92
src/de/danoeh/antennapod/util/QueueAccess.java
Normal file
92
src/de/danoeh/antennapod/util/QueueAccess.java
Normal file
@ -0,0 +1,92 @@
|
||||
package de.danoeh.antennapod.util;
|
||||
|
||||
import de.danoeh.antennapod.feed.FeedItem;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides methods for accessing the queue. It is possible to load only a part of the information about the queue that
|
||||
* is stored in the database (e.g. sometimes the user just has to test if a specific item is contained in the List.
|
||||
* QueueAccess provides an interface for accessing the queue without having to care about the type of the queue
|
||||
* representation.
|
||||
*/
|
||||
public abstract class QueueAccess {
|
||||
/**
|
||||
* Returns true if the item is in the queue, false otherwise.
|
||||
*/
|
||||
public abstract boolean contains(long id);
|
||||
|
||||
/**
|
||||
* Removes the item from the queue.
|
||||
*
|
||||
* @return true if the queue was modified by this operation.
|
||||
*/
|
||||
public abstract boolean remove(long id);
|
||||
|
||||
private QueueAccess() {
|
||||
|
||||
}
|
||||
|
||||
public static QueueAccess IDListAccess(final List<Long> ids) {
|
||||
return new QueueAccess() {
|
||||
@Override
|
||||
public boolean contains(long id) {
|
||||
return (ids != null) && ids.contains(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(long id) {
|
||||
return ids.remove(id);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static QueueAccess ItemListAccess(final List<FeedItem> items) {
|
||||
return new QueueAccess() {
|
||||
@Override
|
||||
public boolean contains(long id) {
|
||||
if (items == null) {
|
||||
return false;
|
||||
}
|
||||
Iterator<FeedItem> it = items.iterator();
|
||||
for (FeedItem i = it.next(); it.hasNext(); i = it.next()) {
|
||||
if (i.getId() == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(long id) {
|
||||
Iterator<FeedItem> it = items.iterator();
|
||||
for (FeedItem i = it.next(); it.hasNext(); i = it.next()) {
|
||||
if (i.getId() == id) {
|
||||
it.remove();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static QueueAccess NotInQueueAccess() {
|
||||
return new QueueAccess() {
|
||||
@Override
|
||||
public boolean contains(long id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(long id) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
17
src/de/danoeh/antennapod/util/ShownotesProvider.java
Normal file
17
src/de/danoeh/antennapod/util/ShownotesProvider.java
Normal file
@ -0,0 +1,17 @@
|
||||
package de.danoeh.antennapod.util;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
/**
|
||||
* Created by daniel on 04.08.13.
|
||||
*/
|
||||
public interface ShownotesProvider {
|
||||
/**
|
||||
* 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 Callable<String> loadShownotes();
|
||||
|
||||
}
|
@ -2,7 +2,7 @@ package de.danoeh.antennapod.util.comparator;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
||||
import de.danoeh.antennapod.service.download.*;
|
||||
|
||||
/** Compares the completion date of two Downloadstatus objects. */
|
||||
public class DownloadStatusComparator implements Comparator<DownloadStatus> {
|
||||
|
@ -7,12 +7,16 @@ import de.danoeh.antennapod.AppConfig;
|
||||
import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.asynctask.FlattrClickWorker;
|
||||
import de.danoeh.antennapod.feed.FeedItem;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.service.PlaybackService;
|
||||
import de.danoeh.antennapod.storage.DBTasks;
|
||||
import de.danoeh.antennapod.storage.DBWriter;
|
||||
import de.danoeh.antennapod.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.util.QueueAccess;
|
||||
import de.danoeh.antennapod.util.ShareUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Handles interactions with the FeedItemMenu. */
|
||||
public class FeedItemMenuHandler {
|
||||
private FeedItemMenuHandler() {
|
||||
@ -45,11 +49,12 @@ public class FeedItemMenuHandler {
|
||||
* True if MenuItems that let the user share information about
|
||||
* the FeedItem and visit its website should be set visible. This
|
||||
* parameter should be set to false if the menu space is limited.
|
||||
* @param queueAccess
|
||||
* Used for testing if the queue contains the selected item
|
||||
* @return Always returns true
|
||||
* */
|
||||
public static boolean onPrepareMenu(MenuInterface mi,
|
||||
FeedItem selectedItem, boolean showExtendedMenu) {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
FeedItem selectedItem, boolean showExtendedMenu, QueueAccess queueAccess) {
|
||||
DownloadRequester requester = DownloadRequester.getInstance();
|
||||
boolean hasMedia = selectedItem.getMedia() != null;
|
||||
boolean downloaded = hasMedia && selectedItem.getMedia().isDownloaded();
|
||||
@ -79,7 +84,7 @@ public class FeedItemMenuHandler {
|
||||
mi.setItemVisibility(R.id.cancel_download_item, false);
|
||||
}
|
||||
|
||||
boolean isInQueue = manager.isInQueue(selectedItem);
|
||||
boolean isInQueue = queueAccess.contains(selectedItem.getId());
|
||||
if (!isInQueue || isPlaying) {
|
||||
mi.setItemVisibility(R.id.remove_from_queue_item, false);
|
||||
}
|
||||
@ -111,39 +116,38 @@ public class FeedItemMenuHandler {
|
||||
public static boolean onMenuItemClicked(Context context, int menuItemId,
|
||||
FeedItem selectedItem) throws DownloadRequestException {
|
||||
DownloadRequester requester = DownloadRequester.getInstance();
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
switch (menuItemId) {
|
||||
case R.id.skip_episode_item:
|
||||
context.sendBroadcast(new Intent(
|
||||
PlaybackService.ACTION_SKIP_CURRENT_EPISODE));
|
||||
break;
|
||||
case R.id.download_item:
|
||||
manager.downloadFeedItem(context, selectedItem);
|
||||
DBTasks.downloadFeedItems(context, selectedItem);
|
||||
break;
|
||||
case R.id.play_item:
|
||||
manager.playMedia(context, selectedItem.getMedia(), true, true,
|
||||
DBTasks.playMedia(context, selectedItem.getMedia(), true, true,
|
||||
false);
|
||||
break;
|
||||
case R.id.remove_item:
|
||||
manager.deleteFeedMedia(context, selectedItem.getMedia());
|
||||
DBWriter.deleteFeedMediaOfItem(context, selectedItem.getId());
|
||||
break;
|
||||
case R.id.cancel_download_item:
|
||||
requester.cancelDownload(context, selectedItem.getMedia());
|
||||
break;
|
||||
case R.id.mark_read_item:
|
||||
manager.markItemRead(context, selectedItem, true, true);
|
||||
DBWriter.markItemRead(context, selectedItem, true, true);
|
||||
break;
|
||||
case R.id.mark_unread_item:
|
||||
manager.markItemRead(context, selectedItem, false, true);
|
||||
DBWriter.markItemRead(context, selectedItem, false, true);
|
||||
break;
|
||||
case R.id.add_to_queue_item:
|
||||
manager.addQueueItem(context, selectedItem);
|
||||
DBWriter.addQueueItem(context, selectedItem.getId());
|
||||
break;
|
||||
case R.id.remove_from_queue_item:
|
||||
manager.removeQueueItem(context, selectedItem, true);
|
||||
DBWriter.removeQueueItem(context, selectedItem.getId(), true);
|
||||
break;
|
||||
case R.id.stream_item:
|
||||
manager.playMedia(context, selectedItem.getMedia(), true, true,
|
||||
DBTasks.playMedia(context, selectedItem.getMedia(), true, true,
|
||||
true);
|
||||
break;
|
||||
case R.id.visit_website_item:
|
||||
|
@ -13,8 +13,9 @@ import de.danoeh.antennapod.R;
|
||||
import de.danoeh.antennapod.activity.FeedInfoActivity;
|
||||
import de.danoeh.antennapod.asynctask.FlattrClickWorker;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
import de.danoeh.antennapod.feed.FeedManager;
|
||||
import de.danoeh.antennapod.service.download.DownloadService;
|
||||
import de.danoeh.antennapod.storage.DBTasks;
|
||||
import de.danoeh.antennapod.storage.DBWriter;
|
||||
import de.danoeh.antennapod.storage.DownloadRequestException;
|
||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||
import de.danoeh.antennapod.util.ShareUtils;
|
||||
@ -55,7 +56,6 @@ public class FeedMenuHandler {
|
||||
*/
|
||||
public static boolean onOptionsItemClicked(Context context, MenuItem item,
|
||||
Feed selectedFeed) throws DownloadRequestException {
|
||||
FeedManager manager = FeedManager.getInstance();
|
||||
switch (item.getItemId()) {
|
||||
case R.id.show_info_item:
|
||||
Intent startIntent = new Intent(context, FeedInfoActivity.class);
|
||||
@ -64,10 +64,10 @@ public class FeedMenuHandler {
|
||||
context.startActivity(startIntent);
|
||||
break;
|
||||
case R.id.refresh_item:
|
||||
manager.refreshFeed(context, selectedFeed);
|
||||
DBTasks.refreshFeed(context, selectedFeed);
|
||||
break;
|
||||
case R.id.mark_all_read_item:
|
||||
manager.markFeedRead(context, selectedFeed);
|
||||
DBWriter.markFeedRead(context, selectedFeed.getId());
|
||||
break;
|
||||
case R.id.visit_website_item:
|
||||
Uri uri = Uri.parse(selectedFeed.getLink());
|
||||
|
@ -2,6 +2,7 @@ package de.danoeh.antennapod.util.playback;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
@ -95,8 +96,13 @@ public class ExternalMedia implements Playable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadShownotes(ShownoteLoaderCallback callback) {
|
||||
callback.onShownotesLoaded(null);
|
||||
public Callable<String> loadShownotes() {
|
||||
return new Callable<String>() {
|
||||
@Override
|
||||
public String call() throws Exception {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3,7 +3,11 @@ package de.danoeh.antennapod.util.playback;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import android.content.Context;
|
||||
import de.danoeh.antennapod.storage.DBReader;
|
||||
import de.danoeh.antennapod.util.ShownotesProvider;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
@ -12,262 +16,263 @@ import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
import de.danoeh.antennapod.asynctask.ImageLoader;
|
||||
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. */
|
||||
/**
|
||||
* Interface for objects that can be played by the PlaybackService.
|
||||
*/
|
||||
public interface Playable extends Parcelable,
|
||||
ImageLoader.ImageWorkerTaskResource {
|
||||
ImageLoader.ImageWorkerTaskResource, ShownotesProvider {
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* 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. This method
|
||||
* should execute as quickly as possible and NOT load chapter marks if no
|
||||
* local file is available.
|
||||
*/
|
||||
public void loadMetadata() throws PlayableException;
|
||||
/**
|
||||
* This method is called from a separate thread by the PlaybackService.
|
||||
* Playable objects should load their metadata in this method. This method
|
||||
* should execute as quickly as possible and NOT load chapter marks if no
|
||||
* local file is available.
|
||||
*/
|
||||
public void loadMetadata() throws PlayableException;
|
||||
|
||||
/**
|
||||
* This method is called from a separate thread by the PlaybackService.
|
||||
* Playable objects should load their chapter marks in this method if no
|
||||
* local file was available when loadMetadata() was called.
|
||||
*/
|
||||
public void loadChapterMarks();
|
||||
/**
|
||||
* This method is called from a separate thread by the PlaybackService.
|
||||
* Playable objects should load their chapter marks in this method if no
|
||||
* local file was available when loadMetadata() was called.
|
||||
*/
|
||||
public void loadChapterMarks();
|
||||
|
||||
/** Returns the title of the episode that this playable represents */
|
||||
public String getEpisodeTitle();
|
||||
/**
|
||||
* 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 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();
|
||||
|
||||
/** Returns a link to a website that is meant to be shown in a browser */
|
||||
public String getWebsiteLink();
|
||||
public String getPaymentLink();
|
||||
|
||||
public String getPaymentLink();
|
||||
/**
|
||||
* Returns the title of the feed this Playable belongs to.
|
||||
*/
|
||||
public String getFeedTitle();
|
||||
|
||||
/** Returns the title of the feed this Playable belongs to. */
|
||||
public String getFeedTitle();
|
||||
/**
|
||||
* Returns a unique identifier, for example a file url or an ID from a
|
||||
* database.
|
||||
*/
|
||||
public Object getIdentifier();
|
||||
|
||||
/**
|
||||
* 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 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();
|
||||
|
||||
/** 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 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 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 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 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();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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 setPosition(int newPosition);
|
||||
public void setDuration(int newDuration);
|
||||
|
||||
public void setDuration(int newDuration);
|
||||
/**
|
||||
* Is called by the PlaybackService when playback starts.
|
||||
*/
|
||||
public void onPlaybackStart();
|
||||
|
||||
/** Is called by the PlaybackService when playback starts. */
|
||||
public void onPlaybackStart();
|
||||
/**
|
||||
* Is called by the PlaybackService when playback is completed.
|
||||
*/
|
||||
public void onPlaybackCompleted();
|
||||
|
||||
/** 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();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
public void setChapters(List<Chapter> chapters);
|
||||
/**
|
||||
* Provides utility methods for Playable objects.
|
||||
*/
|
||||
public static class PlayableUtils {
|
||||
private static final String TAG = "PlayableUtils";
|
||||
|
||||
/** Provides utility methods for Playable objects. */
|
||||
public static class PlayableUtils {
|
||||
private static final String TAG = "PlayableUtils";
|
||||
/**
|
||||
* Restores a playable object from a sharedPreferences file. This method might load data from the database,
|
||||
* depending on the type of playable that was restored.
|
||||
*
|
||||
* @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(Context context, int type,
|
||||
SharedPreferences pref) {
|
||||
// ADD new Playable types here:
|
||||
switch (type) {
|
||||
case FeedMedia.PLAYABLE_TYPE_FEEDMEDIA:
|
||||
long mediaId = pref.getLong(FeedMedia.PREF_MEDIA_ID, -1);
|
||||
if (mediaId != -1) {
|
||||
return DBReader.getFeedMedia(context, mediaId);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 static class PlayableException extends Exception {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public PlayableException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PlayableException() {
|
||||
super();
|
||||
}
|
||||
public PlayableException(String detailMessage, Throwable throwable) {
|
||||
super(detailMessage, throwable);
|
||||
}
|
||||
|
||||
public PlayableException(String detailMessage, Throwable throwable) {
|
||||
super(detailMessage, throwable);
|
||||
}
|
||||
public PlayableException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
|
||||
public PlayableException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
public PlayableException(Throwable throwable) {
|
||||
super(throwable);
|
||||
}
|
||||
|
||||
public PlayableException(Throwable throwable) {
|
||||
super(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Uses local file as image resource if it is available.
|
||||
*/
|
||||
public static class DefaultPlayableImageLoader implements
|
||||
ImageLoader.ImageWorkerTaskResource {
|
||||
private Playable playable;
|
||||
|
||||
public static interface ShownoteLoaderCallback {
|
||||
void onShownotesLoaded(String shownotes);
|
||||
}
|
||||
public DefaultPlayableImageLoader(Playable playable) {
|
||||
if (playable == null) {
|
||||
throw new IllegalArgumentException("Playable must not be null");
|
||||
}
|
||||
this.playable = playable;
|
||||
}
|
||||
|
||||
/** Uses local file as image resource if it is available. */
|
||||
public static class DefaultPlayableImageLoader implements
|
||||
ImageLoader.ImageWorkerTaskResource {
|
||||
private Playable playable;
|
||||
@Override
|
||||
public InputStream openImageInputStream() {
|
||||
if (playable.localFileAvailable()
|
||||
&& playable.getLocalMediaUrl() != null) {
|
||||
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||
try {
|
||||
mmr.setDataSource(playable.getLocalMediaUrl());
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
byte[] imgData = mmr.getEmbeddedPicture();
|
||||
if (imgData != null) {
|
||||
return new PublicByteArrayInputStream(imgData);
|
||||
|
||||
public DefaultPlayableImageLoader(Playable playable) {
|
||||
if (playable == null) {
|
||||
throw new IllegalArgumentException("Playable must not be null");
|
||||
}
|
||||
this.playable = playable;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream openImageInputStream() {
|
||||
if (playable.localFileAvailable()
|
||||
&& playable.getLocalMediaUrl() != null) {
|
||||
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||
try {
|
||||
mmr.setDataSource(playable.getLocalMediaUrl());
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
byte[] imgData = mmr.getEmbeddedPicture();
|
||||
if (imgData != null) {
|
||||
return new PublicByteArrayInputStream(imgData);
|
||||
@Override
|
||||
public String getImageLoaderCacheKey() {
|
||||
return playable.getLocalMediaUrl();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public InputStream reopenImageInputStream(InputStream input) {
|
||||
if (input instanceof PublicByteArrayInputStream) {
|
||||
IOUtils.closeQuietly(input);
|
||||
byte[] imgData = ((PublicByteArrayInputStream) input)
|
||||
.getByteArray();
|
||||
if (imgData != null) {
|
||||
ByteArrayInputStream out = new ByteArrayInputStream(imgData);
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getImageLoaderCacheKey() {
|
||||
return playable.getLocalMediaUrl();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream reopenImageInputStream(InputStream input) {
|
||||
if (input instanceof PublicByteArrayInputStream) {
|
||||
IOUtils.closeQuietly(input);
|
||||
byte[] imgData = ((PublicByteArrayInputStream) input)
|
||||
.getByteArray();
|
||||
if (imgData != null) {
|
||||
ByteArrayInputStream out = new ByteArrayInputStream(imgData);
|
||||
return out;
|
||||
}
|
||||
private static class PublicByteArrayInputStream extends
|
||||
ByteArrayInputStream {
|
||||
public PublicByteArrayInputStream(byte[] buf) {
|
||||
super(buf);
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class PublicByteArrayInputStream extends
|
||||
ByteArrayInputStream {
|
||||
public PublicByteArrayInputStream(byte[] buf) {
|
||||
super(buf);
|
||||
}
|
||||
|
||||
public byte[] getByteArray() {
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
public byte[] getByteArray() {
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,8 +6,8 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
||||
import de.danoeh.antennapod.feed.Feed;
|
||||
import de.danoeh.antennapod.service.download.DownloadStatus;
|
||||
import de.danoeh.antennapod.service.download.Downloader;
|
||||
import de.danoeh.antennapod.service.download.DownloaderCallback;
|
||||
import de.danoeh.antennapod.service.download.HttpDownloader;
|
||||
|
Loading…
x
Reference in New Issue
Block a user