Merge branch 'downloadmanager' into develop
This commit is contained in:
commit
fdb9a296ad
@ -11,8 +11,6 @@
|
|||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="10"
|
android:minSdkVersion="10"
|
||||||
android:targetSdkVersion="14" />
|
android:targetSdkVersion="14" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
<supports-screens
|
<supports-screens
|
||||||
@ -74,7 +72,7 @@
|
|||||||
android:theme="@style/Theme.MediaPlayer" android:screenOrientation="portrait"/>
|
android:theme="@style/Theme.MediaPlayer" android:screenOrientation="portrait"/>
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name="de.danoeh.antennapod.service.DownloadService"
|
android:name=".service.download.DownloadService"
|
||||||
android:enabled="true" />
|
android:enabled="true" />
|
||||||
<service
|
<service
|
||||||
android:name="de.danoeh.antennapod.service.PlaybackService"
|
android:name="de.danoeh.antennapod.service.PlaybackService"
|
||||||
|
@ -87,7 +87,7 @@
|
|||||||
<string name="pref_pauseOnHeadsetDisconnect_title">Headphones disconnect</string>
|
<string name="pref_pauseOnHeadsetDisconnect_title">Headphones disconnect</string>
|
||||||
<string name="pref_mobileUpdate_title">Mobile updates</string>
|
<string name="pref_mobileUpdate_title">Mobile updates</string>
|
||||||
<string name="pref_mobileUpdate_sum">Allow updates over the mobile data connection</string>
|
<string name="pref_mobileUpdate_sum">Allow updates over the mobile data connection</string>
|
||||||
<string name="download_report_title">All downloads completed</string>
|
<string name="download_report_title">Downloads completed</string>
|
||||||
<string name="refresh_label">Refresh</string>
|
<string name="refresh_label">Refresh</string>
|
||||||
<string name="external_storage_error_msg">No external storage is available. Please make sure that external storage is mounted so that the app can work properly.</string>
|
<string name="external_storage_error_msg">No external storage is available. Please make sure that external storage is mounted so that the app can work properly.</string>
|
||||||
<string name="share_link_label">Share link</string>
|
<string name="share_link_label">Share link</string>
|
||||||
@ -176,6 +176,9 @@
|
|||||||
<string name="user_interface_label">User Interface</string>
|
<string name="user_interface_label">User Interface</string>
|
||||||
<string name="feed_delete_confirmation_msg">Please confirm that you want to delete this feed and ALL episodes of this feed that you have downloaded.</string>
|
<string name="feed_delete_confirmation_msg">Please confirm that you want to delete this feed and ALL episodes of this feed that you have downloaded.</string>
|
||||||
<string name="image_of_prefix">Image of:\u0020</string>
|
<string name="image_of_prefix">Image of:\u0020</string>
|
||||||
|
<string name="download_error_malformed_url">Malformed URL</string>
|
||||||
|
<string name="download_error_io_error">IO Error</string>
|
||||||
|
<string name="download_error_device_not_found">External storage unavailable</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -23,7 +23,7 @@ import de.danoeh.antennapod.R;
|
|||||||
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
||||||
import de.danoeh.antennapod.feed.Feed;
|
import de.danoeh.antennapod.feed.Feed;
|
||||||
import de.danoeh.antennapod.feed.FeedManager;
|
import de.danoeh.antennapod.feed.FeedManager;
|
||||||
import de.danoeh.antennapod.service.DownloadService;
|
import de.danoeh.antennapod.service.download.DownloadService;
|
||||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||||
import de.danoeh.antennapod.util.ConnectionTester;
|
import de.danoeh.antennapod.util.ConnectionTester;
|
||||||
import de.danoeh.antennapod.util.DownloadError;
|
import de.danoeh.antennapod.util.DownloadError;
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
package de.danoeh.antennapod.activity;
|
package de.danoeh.antennapod.activity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@ -18,9 +25,9 @@ import com.actionbarsherlock.view.MenuItem;
|
|||||||
import de.danoeh.antennapod.AppConfig;
|
import de.danoeh.antennapod.AppConfig;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import de.danoeh.antennapod.adapter.DownloadlistAdapter;
|
import de.danoeh.antennapod.adapter.DownloadlistAdapter;
|
||||||
import de.danoeh.antennapod.asynctask.DownloadObserver;
|
|
||||||
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
||||||
import de.danoeh.antennapod.service.DownloadService;
|
import de.danoeh.antennapod.service.download.DownloadService;
|
||||||
|
import de.danoeh.antennapod.service.download.Downloader;
|
||||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,7 +35,7 @@ import de.danoeh.antennapod.storage.DownloadRequester;
|
|||||||
* objects created by a DownloadObserver.
|
* objects created by a DownloadObserver.
|
||||||
*/
|
*/
|
||||||
public class DownloadActivity extends SherlockListActivity implements
|
public class DownloadActivity extends SherlockListActivity implements
|
||||||
ActionMode.Callback, DownloadObserver.Callback {
|
ActionMode.Callback {
|
||||||
|
|
||||||
private static final String TAG = "DownloadActivity";
|
private static final String TAG = "DownloadActivity";
|
||||||
private static final int MENU_SHOW_LOG = 0;
|
private static final int MENU_SHOW_LOG = 0;
|
||||||
@ -38,7 +45,11 @@ public class DownloadActivity extends SherlockListActivity implements
|
|||||||
|
|
||||||
private ActionMode mActionMode;
|
private ActionMode mActionMode;
|
||||||
private DownloadStatus selectedDownload;
|
private DownloadStatus selectedDownload;
|
||||||
private DownloadObserver downloadObserver;
|
|
||||||
|
private DownloadService downloadService = null;
|
||||||
|
boolean mIsBound;
|
||||||
|
|
||||||
|
private AsyncTask<Void, Void, Void> contentRefresher;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@ -47,24 +58,25 @@ public class DownloadActivity extends SherlockListActivity implements
|
|||||||
Log.d(TAG, "Creating Activity");
|
Log.d(TAG, "Creating Activity");
|
||||||
requester = DownloadRequester.getInstance();
|
requester = DownloadRequester.getInstance();
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
unbindService(mConnection);
|
unbindService(mConnection);
|
||||||
if (downloadObserver != null) {
|
unregisterReceiver(contentChanged);
|
||||||
downloadObserver.unregisterCallback(DownloadActivity.this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume() {
|
protected void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
if (AppConfig.DEBUG)
|
registerReceiver(contentChanged, new IntentFilter(
|
||||||
Log.d(TAG, "Trying to bind service");
|
DownloadService.ACTION_DOWNLOADS_CONTENT_CHANGED));
|
||||||
bindService(new Intent(this, DownloadService.class), mConnection, 0);
|
bindService(new Intent(this, DownloadService.class), mConnection, 0);
|
||||||
|
startContentRefresher();
|
||||||
|
if (dla != null) {
|
||||||
|
dla.notifyDataSetChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -72,6 +84,71 @@ public class DownloadActivity extends SherlockListActivity implements
|
|||||||
super.onStop();
|
super.onStop();
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Stopping Activity");
|
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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
setListAdapter(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;
|
||||||
|
|
||||||
|
@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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopContentRefresher() {
|
||||||
|
if (contentRefresher != null) {
|
||||||
|
contentRefresher.cancel(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -82,7 +159,7 @@ public class DownloadActivity extends SherlockListActivity implements
|
|||||||
@Override
|
@Override
|
||||||
public boolean onItemLongClick(AdapterView<?> arg0, View view,
|
public boolean onItemLongClick(AdapterView<?> arg0, View view,
|
||||||
int position, long id) {
|
int position, long id) {
|
||||||
DownloadStatus selection = dla.getItem(position);
|
DownloadStatus selection = dla.getItem(position).getStatus();
|
||||||
if (selection != null && mActionMode != null) {
|
if (selection != null && mActionMode != null) {
|
||||||
mActionMode.finish();
|
mActionMode.finish();
|
||||||
}
|
}
|
||||||
@ -142,8 +219,7 @@ public class DownloadActivity extends SherlockListActivity implements
|
|||||||
boolean handled = false;
|
boolean handled = false;
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.cancel_download_item:
|
case R.id.cancel_download_item:
|
||||||
requester.cancelDownload(this, selectedDownload.getFeedFile()
|
requester.cancelDownload(this, selectedDownload.getFeedFile());
|
||||||
.getDownloadId());
|
|
||||||
handled = true;
|
handled = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -158,53 +234,16 @@ public class DownloadActivity extends SherlockListActivity implements
|
|||||||
dla.setSelectedItemIndex(DownloadlistAdapter.SELECTION_NONE);
|
dla.setSelectedItemIndex(DownloadlistAdapter.SELECTION_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DownloadService downloadService = null;
|
private BroadcastReceiver contentChanged = new BroadcastReceiver() {
|
||||||
boolean mIsBound;
|
|
||||||
|
|
||||||
private ServiceConnection mConnection = new ServiceConnection() {
|
@Override
|
||||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
downloadService = ((DownloadService.LocalBinder) service)
|
if (dla != null) {
|
||||||
.getService();
|
if (AppConfig.DEBUG)
|
||||||
if (AppConfig.DEBUG)
|
Log.d(TAG, "Refreshing content");
|
||||||
Log.d(TAG, "Connection to service established");
|
dla.notifyDataSetChanged();
|
||||||
dla = new DownloadlistAdapter(DownloadActivity.this, 0,
|
}
|
||||||
downloadService.getDownloadObserver().getStatusList());
|
|
||||||
setListAdapter(dla);
|
|
||||||
downloadObserver = downloadService.getDownloadObserver();
|
|
||||||
downloadObserver.registerCallback(DownloadActivity.this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onServiceDisconnected(ComponentName className) {
|
|
||||||
downloadService = null;
|
|
||||||
mIsBound = false;
|
|
||||||
Log.i(TAG, "Closed connection with DownloadService.");
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onProgressUpdate() {
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
dla.notifyDataSetChanged();
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFinish() {
|
|
||||||
if (AppConfig.DEBUG)
|
|
||||||
Log.d(TAG, "Observer has finished, clearing adapter");
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
dla.clear();
|
|
||||||
dla.notifyDataSetInvalidated();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package de.danoeh.antennapod.activity;
|
package de.danoeh.antennapod.activity;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import com.actionbarsherlock.app.SherlockListActivity;
|
import com.actionbarsherlock.app.SherlockListActivity;
|
||||||
@ -9,7 +13,10 @@ import com.actionbarsherlock.view.MenuItem;
|
|||||||
import de.danoeh.antennapod.adapter.DownloadLogAdapter;
|
import de.danoeh.antennapod.adapter.DownloadLogAdapter;
|
||||||
import de.danoeh.antennapod.feed.FeedManager;
|
import de.danoeh.antennapod.feed.FeedManager;
|
||||||
|
|
||||||
/** Displays completed and failed downloads in a list. The data comes from the FeedManager. */
|
/**
|
||||||
|
* Displays completed and failed downloads in a list. The data comes from the
|
||||||
|
* FeedManager.
|
||||||
|
*/
|
||||||
public class DownloadLogActivity extends SherlockListActivity {
|
public class DownloadLogActivity extends SherlockListActivity {
|
||||||
private static final String TAG = "DownloadLogActivity";
|
private static final String TAG = "DownloadLogActivity";
|
||||||
|
|
||||||
@ -26,6 +33,20 @@ public class DownloadLogActivity extends SherlockListActivity {
|
|||||||
setListAdapter(dla);
|
setListAdapter(dla);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
unregisterReceiver(contentUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
registerReceiver(contentUpdate, new IntentFilter(
|
||||||
|
FeedManager.ACTION_DOWNLOADLOG_UPDATE));
|
||||||
|
dla.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
return true;
|
return true;
|
||||||
@ -43,4 +64,15 @@ public class DownloadLogActivity extends SherlockListActivity {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BroadcastReceiver contentUpdate = new BroadcastReceiver() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (intent.getAction()
|
||||||
|
.equals(FeedManager.ACTION_DOWNLOADLOG_UPDATE)) {
|
||||||
|
dla.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,8 @@ import de.danoeh.antennapod.feed.FeedManager;
|
|||||||
import de.danoeh.antennapod.fragment.FeedlistFragment;
|
import de.danoeh.antennapod.fragment.FeedlistFragment;
|
||||||
import de.danoeh.antennapod.fragment.QueueFragment;
|
import de.danoeh.antennapod.fragment.QueueFragment;
|
||||||
import de.danoeh.antennapod.fragment.UnreadItemlistFragment;
|
import de.danoeh.antennapod.fragment.UnreadItemlistFragment;
|
||||||
import de.danoeh.antennapod.service.DownloadService;
|
|
||||||
import de.danoeh.antennapod.service.PlaybackService;
|
import de.danoeh.antennapod.service.PlaybackService;
|
||||||
|
import de.danoeh.antennapod.service.download.DownloadService;
|
||||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||||
import de.danoeh.antennapod.util.StorageUtils;
|
import de.danoeh.antennapod.util.StorageUtils;
|
||||||
import de.danoeh.antennapod.AppConfig;
|
import de.danoeh.antennapod.AppConfig;
|
||||||
|
@ -14,16 +14,17 @@ import de.danoeh.antennapod.feed.Feed;
|
|||||||
import de.danoeh.antennapod.feed.FeedFile;
|
import de.danoeh.antennapod.feed.FeedFile;
|
||||||
import de.danoeh.antennapod.feed.FeedImage;
|
import de.danoeh.antennapod.feed.FeedImage;
|
||||||
import de.danoeh.antennapod.feed.FeedMedia;
|
import de.danoeh.antennapod.feed.FeedMedia;
|
||||||
|
import de.danoeh.antennapod.service.download.Downloader;
|
||||||
import de.danoeh.antennapod.util.Converter;
|
import de.danoeh.antennapod.util.Converter;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
|
|
||||||
public class DownloadlistAdapter extends ArrayAdapter<DownloadStatus> {
|
public class DownloadlistAdapter extends ArrayAdapter<Downloader> {
|
||||||
private int selectedItemIndex;
|
private int selectedItemIndex;
|
||||||
|
|
||||||
public static final int SELECTION_NONE = -1;
|
public static final int SELECTION_NONE = -1;
|
||||||
|
|
||||||
public DownloadlistAdapter(Context context, int textViewResourceId,
|
public DownloadlistAdapter(Context context, int textViewResourceId,
|
||||||
List<DownloadStatus> objects) {
|
List<Downloader> objects) {
|
||||||
super(context, textViewResourceId, objects);
|
super(context, textViewResourceId, objects);
|
||||||
this.selectedItemIndex = SELECTION_NONE;
|
this.selectedItemIndex = SELECTION_NONE;
|
||||||
}
|
}
|
||||||
@ -31,7 +32,7 @@ public class DownloadlistAdapter extends ArrayAdapter<DownloadStatus> {
|
|||||||
@Override
|
@Override
|
||||||
public View getView(int position, View convertView, ViewGroup parent) {
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
Holder holder;
|
Holder holder;
|
||||||
DownloadStatus status = getItem(position);
|
DownloadStatus status = getItem(position).getStatus();
|
||||||
FeedFile feedFile = status.getFeedFile();
|
FeedFile feedFile = status.getFeedFile();
|
||||||
// Inflate layout
|
// Inflate layout
|
||||||
if (convertView == null) {
|
if (convertView == null) {
|
||||||
@ -77,7 +78,9 @@ public class DownloadlistAdapter extends ArrayAdapter<DownloadStatus> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
holder.title.setText(titleText);
|
holder.title.setText(titleText);
|
||||||
holder.message.setText(status.getStatusMsg());
|
if (status.getStatusMsg() != 0) {
|
||||||
|
holder.message.setText(status.getStatusMsg());
|
||||||
|
}
|
||||||
holder.downloaded.setText(Converter.byteToString(status.getSoFar())
|
holder.downloaded.setText(Converter.byteToString(status.getSoFar())
|
||||||
+ " / " + Converter.byteToString(status.getSize()));
|
+ " / " + Converter.byteToString(status.getSize()));
|
||||||
holder.percent.setText(status.getProgressPercent() + "%");
|
holder.percent.setText(status.getProgressPercent() + "%");
|
||||||
|
@ -5,6 +5,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import de.danoeh.antennapod.feed.FeedItem;
|
import de.danoeh.antennapod.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.feed.FeedManager;
|
import de.danoeh.antennapod.feed.FeedManager;
|
||||||
|
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||||
import de.danoeh.antennapod.util.Converter;
|
import de.danoeh.antennapod.util.Converter;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
@ -121,7 +122,8 @@ public class FeedItemlistAdapter extends ArrayAdapter<FeedItem> {
|
|||||||
holder.downloaded.setVisibility(View.GONE);
|
holder.downloaded.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.getMedia().isDownloading()) {
|
if (DownloadRequester.getInstance().isDownloadingFile(
|
||||||
|
item.getMedia())) {
|
||||||
holder.downloading.setVisibility(View.VISIBLE);
|
holder.downloading.setVisibility(View.VISIBLE);
|
||||||
} else {
|
} else {
|
||||||
holder.downloading.setVisibility(View.GONE);
|
holder.downloading.setVisibility(View.GONE);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package de.danoeh.antennapod.asynctask;
|
/*package de.danoeh.antennapod.asynctask;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -16,16 +16,17 @@ import de.danoeh.antennapod.storage.DownloadRequester;
|
|||||||
import de.danoeh.antennapod.AppConfig;
|
import de.danoeh.antennapod.AppConfig;
|
||||||
import de.danoeh.antennapod.R;
|
import de.danoeh.antennapod.R;
|
||||||
|
|
||||||
/** Observes the status of a specific Download */
|
*//** Observes the status of a specific Download *//*
|
||||||
public class DownloadObserver extends AsyncTask<Void, Void, Void> {
|
public class DownloadObserver{
|
||||||
|
*//******
|
||||||
private static final String TAG = "DownloadObserver";
|
private static final String TAG = "DownloadObserver";
|
||||||
|
|
||||||
/** Types of downloads to observe. */
|
/** Types of downloads to observe. *//*
|
||||||
public static final int TYPE_FEED = 0;
|
public static final int TYPE_FEED = 0;
|
||||||
public static final int TYPE_IMAGE = 1;
|
public static final int TYPE_IMAGE = 1;
|
||||||
public static final int TYPE_MEDIA = 2;
|
public static final int TYPE_MEDIA = 2;
|
||||||
|
|
||||||
/** Error codes */
|
*//** Error codes *//*
|
||||||
public static final int ALREADY_DOWNLOADED = 1;
|
public static final int ALREADY_DOWNLOADED = 1;
|
||||||
public static final int NO_DOWNLOAD_FOUND = 2;
|
public static final int NO_DOWNLOAD_FOUND = 2;
|
||||||
|
|
||||||
@ -165,7 +166,7 @@ public class DownloadObserver extends AsyncTask<Void, Void, Void> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Request a cursor with all running Feedfile downloads */
|
*//** Request a cursor with all running Feedfile downloads *//*
|
||||||
private Cursor getDownloadCursor() {
|
private Cursor getDownloadCursor() {
|
||||||
// Collect download ids
|
// Collect download ids
|
||||||
|
|
||||||
@ -186,7 +187,7 @@ public class DownloadObserver extends AsyncTask<Void, Void, Void> {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return value of a specific column */
|
*//** Return value of a specific column *//*
|
||||||
private int getDownloadStatus(Cursor c, String column) {
|
private int getDownloadStatus(Cursor c, String column) {
|
||||||
int status = c.getInt(c.getColumnIndex(column));
|
int status = c.getInt(c.getColumnIndex(column));
|
||||||
return status;
|
return status;
|
||||||
@ -205,7 +206,7 @@ public class DownloadObserver extends AsyncTask<Void, Void, Void> {
|
|||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Find a DownloadStatus entry by its FeedFile */
|
*//** Find a DownloadStatus entry by its FeedFile *//*
|
||||||
public DownloadStatus findDownloadStatus(FeedFile f) {
|
public DownloadStatus findDownloadStatus(FeedFile f) {
|
||||||
for (DownloadStatus status : statusList) {
|
for (DownloadStatus status : statusList) {
|
||||||
if (status.feedfile == f) {
|
if (status.feedfile == f) {
|
||||||
@ -238,3 +239,4 @@ public class DownloadObserver extends AsyncTask<Void, Void, Void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
@ -14,6 +14,9 @@ public class DownloadStatus {
|
|||||||
/** Unique id for storing the object in database. */
|
/** Unique id for storing the object in database. */
|
||||||
protected long id;
|
protected long id;
|
||||||
|
|
||||||
|
/** Used by DownloadService to check if the status has been updated. */
|
||||||
|
protected volatile boolean updateAvailable;
|
||||||
|
|
||||||
protected FeedFile feedfile;
|
protected FeedFile feedfile;
|
||||||
protected int progressPercent;
|
protected int progressPercent;
|
||||||
protected long soFar;
|
protected long soFar;
|
||||||
@ -29,8 +32,8 @@ public class DownloadStatus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Constructor for restoring Download status entries from DB. */
|
/** Constructor for restoring Download status entries from DB. */
|
||||||
public DownloadStatus(long id, FeedFile feedfile, boolean successful, int reason,
|
public DownloadStatus(long id, FeedFile feedfile, boolean successful,
|
||||||
Date completionDate) {
|
int reason, Date completionDate) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.feedfile = feedfile;
|
this.feedfile = feedfile;
|
||||||
progressPercent = 100;
|
progressPercent = 100;
|
||||||
@ -42,10 +45,8 @@ public class DownloadStatus {
|
|||||||
this.completionDate = completionDate;
|
this.completionDate = completionDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Constructor for creating new completed downloads. */
|
/** Constructor for creating new completed downloads. */
|
||||||
public DownloadStatus(FeedFile feedfile, int reason,
|
public DownloadStatus(FeedFile feedfile, int reason, boolean successful) {
|
||||||
boolean successful) {
|
|
||||||
this(0, feedfile, successful, reason, new Date());
|
this(0, feedfile, successful, reason, new Date());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +90,48 @@ public class DownloadStatus {
|
|||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFeedfile(FeedFile feedfile) {
|
||||||
|
this.feedfile = feedfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 void setReason(int reason) {
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSuccessful(boolean successful) {
|
||||||
|
this.successful = successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDone(boolean done) {
|
||||||
|
this.done = done;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompletionDate(Date completionDate) {
|
||||||
|
this.completionDate = completionDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUpdateAvailable() {
|
||||||
|
return updateAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUpdateAvailable(boolean updateAvailable) {
|
||||||
|
this.updateAvailable = updateAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,10 +1,9 @@
|
|||||||
package de.danoeh.antennapod.feed;
|
package de.danoeh.antennapod.feed;
|
||||||
|
|
||||||
/** Represents a component of a Feed that has to be downloaded*/
|
/** Represents a component of a Feed that has to be downloaded */
|
||||||
public abstract class FeedFile extends FeedComponent {
|
public abstract class FeedFile extends FeedComponent {
|
||||||
protected String file_url;
|
protected String file_url;
|
||||||
protected String download_url;
|
protected String download_url;
|
||||||
protected long downloadId; // temporary id given by the Android DownloadManager
|
|
||||||
protected boolean downloaded;
|
protected boolean downloaded;
|
||||||
|
|
||||||
public FeedFile(String file_url, String download_url, boolean downloaded) {
|
public FeedFile(String file_url, String download_url, boolean downloaded) {
|
||||||
@ -21,24 +20,19 @@ public abstract class FeedFile extends FeedComponent {
|
|||||||
public String getFile_url() {
|
public String getFile_url() {
|
||||||
return file_url;
|
return file_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFile_url(String file_url) {
|
public void setFile_url(String file_url) {
|
||||||
this.file_url = file_url;
|
this.file_url = file_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDownload_url() {
|
public String getDownload_url() {
|
||||||
return download_url;
|
return download_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDownload_url(String download_url) {
|
public void setDownload_url(String download_url) {
|
||||||
this.download_url = download_url;
|
this.download_url = download_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getDownloadId() {
|
|
||||||
return downloadId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDownloadId(long downloadId) {
|
|
||||||
this.downloadId = downloadId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDownloaded() {
|
public boolean isDownloaded() {
|
||||||
return downloaded;
|
return downloaded;
|
||||||
}
|
}
|
||||||
@ -46,10 +40,4 @@ public abstract class FeedFile extends FeedComponent {
|
|||||||
public void setDownloaded(boolean downloaded) {
|
public void setDownloaded(boolean downloaded) {
|
||||||
this.downloaded = downloaded;
|
this.downloaded = downloaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDownloading() {
|
|
||||||
return downloadId != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ public class FeedManager {
|
|||||||
public static final String ACITON_FEED_LIST_UPDATE = "de.danoeh.antennapod.action.feed.feedlistUpdate";
|
public static final String ACITON_FEED_LIST_UPDATE = "de.danoeh.antennapod.action.feed.feedlistUpdate";
|
||||||
public static final String ACTION_UNREAD_ITEMS_UPDATE = "de.danoeh.antennapod.action.feed.unreadItemsUpdate";
|
public static final String ACTION_UNREAD_ITEMS_UPDATE = "de.danoeh.antennapod.action.feed.unreadItemsUpdate";
|
||||||
public static final String ACTION_QUEUE_UPDATE = "de.danoeh.antennapod.action.feed.queueUpdate";
|
public static final String ACTION_QUEUE_UPDATE = "de.danoeh.antennapod.action.feed.queueUpdate";
|
||||||
|
public static final String ACTION_DOWNLOADLOG_UPDATE = "de.danoeh.antennapod.action.feed.downloadLogUpdate";
|
||||||
public static final String EXTRA_FEED_ITEM_ID = "de.danoeh.antennapod.extra.feed.feedItemId";
|
public static final String EXTRA_FEED_ITEM_ID = "de.danoeh.antennapod.extra.feed.feedItemId";
|
||||||
public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feed.feedId";
|
public static final String EXTRA_FEED_ID = "de.danoeh.antennapod.extra.feed.feedId";
|
||||||
|
|
||||||
@ -167,8 +168,7 @@ public class FeedManager {
|
|||||||
imageFile.delete();
|
imageFile.delete();
|
||||||
}
|
}
|
||||||
} else if (requester.isDownloadingFile(feed.getImage())) {
|
} else if (requester.isDownloadingFile(feed.getImage())) {
|
||||||
requester.cancelDownload(context, feed.getImage()
|
requester.cancelDownload(context, feed.getImage());
|
||||||
.getDownloadId());
|
|
||||||
}
|
}
|
||||||
// delete stored media files and mark them as read
|
// delete stored media files and mark them as read
|
||||||
for (FeedItem item : feed.getItems()) {
|
for (FeedItem item : feed.getItems()) {
|
||||||
@ -184,8 +184,7 @@ public class FeedManager {
|
|||||||
mediaFile.delete();
|
mediaFile.delete();
|
||||||
} else if (item.getMedia() != null
|
} else if (item.getMedia() != null
|
||||||
&& requester.isDownloadingFile(item.getMedia())) {
|
&& requester.isDownloadingFile(item.getMedia())) {
|
||||||
requester.cancelDownload(context, item.getMedia()
|
requester.cancelDownload(context, item.getMedia());
|
||||||
.getDownloadId());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,20 +333,34 @@ public class FeedManager {
|
|||||||
|
|
||||||
public void addDownloadStatus(final Context context,
|
public void addDownloadStatus(final Context context,
|
||||||
final DownloadStatus status) {
|
final DownloadStatus status) {
|
||||||
downloadLog.add(status);
|
contentChanger.post(new Runnable() {
|
||||||
dbExec.execute(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
PodDBAdapter adapter = new PodDBAdapter(context);
|
downloadLog.add(status);
|
||||||
adapter.open();
|
final DownloadStatus removedStatus;
|
||||||
if (downloadLog.size() > DOWNLOAD_LOG_SIZE) {
|
if (downloadLog.size() > DOWNLOAD_LOG_SIZE) {
|
||||||
adapter.removeDownloadStatus(downloadLog.remove(0));
|
removedStatus = downloadLog.remove(0);
|
||||||
|
} else {
|
||||||
|
removedStatus = null;
|
||||||
}
|
}
|
||||||
adapter.setDownloadStatus(status);
|
context.sendBroadcast(new Intent(ACTION_DOWNLOADLOG_UPDATE));
|
||||||
adapter.close();
|
dbExec.execute(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
PodDBAdapter adapter = new PodDBAdapter(context);
|
||||||
|
adapter.open();
|
||||||
|
if (removedStatus != null) {
|
||||||
|
adapter.removeDownloadStatus(removedStatus);
|
||||||
|
}
|
||||||
|
adapter.setDownloadStatus(status);
|
||||||
|
adapter.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addQueueItem(final Context context, final FeedItem item) {
|
public void addQueueItem(final Context context, final FeedItem item) {
|
||||||
|
@ -5,7 +5,7 @@ import de.danoeh.antennapod.adapter.FeedlistAdapter;
|
|||||||
import de.danoeh.antennapod.asynctask.FeedRemover;
|
import de.danoeh.antennapod.asynctask.FeedRemover;
|
||||||
import de.danoeh.antennapod.dialog.ConfirmationDialog;
|
import de.danoeh.antennapod.dialog.ConfirmationDialog;
|
||||||
import de.danoeh.antennapod.feed.*;
|
import de.danoeh.antennapod.feed.*;
|
||||||
import de.danoeh.antennapod.service.DownloadService;
|
import de.danoeh.antennapod.service.download.DownloadService;
|
||||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||||
import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
|
import de.danoeh.antennapod.util.menuhandler.FeedMenuHandler;
|
||||||
import de.danoeh.antennapod.AppConfig;
|
import de.danoeh.antennapod.AppConfig;
|
||||||
@ -140,15 +140,7 @@ public class FeedlistFragment extends SherlockFragment implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (intent.getAction().equals(
|
fla.notifyDataSetChanged();
|
||||||
DownloadService.ACTION_DOWNLOAD_HANDLED)) {
|
|
||||||
int type = intent.getIntExtra(DownloadService.EXTRA_DOWNLOAD_TYPE, 0);
|
|
||||||
if (type == DownloadService.DOWNLOAD_TYPE_IMAGE) {
|
|
||||||
fla.notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fla.notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ import de.danoeh.antennapod.adapter.FeedItemlistAdapter;
|
|||||||
import de.danoeh.antennapod.feed.Feed;
|
import de.danoeh.antennapod.feed.Feed;
|
||||||
import de.danoeh.antennapod.feed.FeedItem;
|
import de.danoeh.antennapod.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.feed.FeedManager;
|
import de.danoeh.antennapod.feed.FeedManager;
|
||||||
import de.danoeh.antennapod.service.DownloadService;
|
import de.danoeh.antennapod.service.download.DownloadService;
|
||||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||||
import de.danoeh.antennapod.util.EpisodeFilter;
|
import de.danoeh.antennapod.util.EpisodeFilter;
|
||||||
import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
|
import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler;
|
||||||
|
@ -3,60 +3,60 @@
|
|||||||
* to complete, then stops
|
* to complete, then stops
|
||||||
* */
|
* */
|
||||||
|
|
||||||
package de.danoeh.antennapod.service;
|
package de.danoeh.antennapod.service.download;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.Thread.UncaughtExceptionHandler;
|
import java.lang.Thread.UncaughtExceptionHandler;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ThreadFactory;
|
import java.util.concurrent.ThreadFactory;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import de.danoeh.antennapod.AppConfig;
|
|
||||||
import de.danoeh.antennapod.PodcastApp;
|
|
||||||
import de.danoeh.antennapod.activity.DownloadActivity;
|
|
||||||
import de.danoeh.antennapod.activity.AudioplayerActivity;
|
|
||||||
import de.danoeh.antennapod.activity.MainActivity;
|
|
||||||
import de.danoeh.antennapod.asynctask.DownloadObserver;
|
|
||||||
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
|
||||||
import de.danoeh.antennapod.feed.*;
|
|
||||||
import de.danoeh.antennapod.service.PlaybackService.LocalBinder;
|
|
||||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
|
||||||
import de.danoeh.antennapod.syndication.handler.FeedHandler;
|
|
||||||
import de.danoeh.antennapod.syndication.handler.UnsupportedFeedtypeException;
|
|
||||||
import de.danoeh.antennapod.util.DownloadError;
|
|
||||||
import de.danoeh.antennapod.util.InvalidFeedException;
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.app.DownloadManager;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.media.MediaPlayer;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.media.MediaPlayer;
|
||||||
import android.util.Log;
|
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Debug;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.IBinder;
|
||||||
import android.os.Messenger;
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.webkit.URLUtil;
|
||||||
|
import de.danoeh.antennapod.AppConfig;
|
||||||
|
import de.danoeh.antennapod.PodcastApp;
|
||||||
|
import de.danoeh.antennapod.activity.DownloadActivity;
|
||||||
|
import de.danoeh.antennapod.activity.MainActivity;
|
||||||
|
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
||||||
|
import de.danoeh.antennapod.feed.Feed;
|
||||||
|
import de.danoeh.antennapod.feed.FeedFile;
|
||||||
|
import de.danoeh.antennapod.feed.FeedImage;
|
||||||
|
import de.danoeh.antennapod.feed.FeedManager;
|
||||||
|
import de.danoeh.antennapod.feed.FeedMedia;
|
||||||
|
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||||
|
import de.danoeh.antennapod.syndication.handler.FeedHandler;
|
||||||
|
import de.danoeh.antennapod.syndication.handler.UnsupportedFeedtypeException;
|
||||||
|
import de.danoeh.antennapod.util.DownloadError;
|
||||||
|
import de.danoeh.antennapod.util.InvalidFeedException;
|
||||||
|
|
||||||
public class DownloadService extends Service {
|
public class DownloadService extends Service {
|
||||||
private static final String TAG = "DownloadService";
|
private static final String TAG = "DownloadService";
|
||||||
@ -67,13 +67,27 @@ public class DownloadService extends Service {
|
|||||||
* If the DownloadService receives this intent, it will execute
|
* If the DownloadService receives this intent, it will execute
|
||||||
* queryDownloads()
|
* queryDownloads()
|
||||||
*/
|
*/
|
||||||
public static final String ACTION_NOTIFY_DOWNLOADS_CHANGED = "action.de.danoeh.antennapod.service.notifyDownloadsChanged";
|
public static final String ACTION_ENQUEUE_DOWNLOAD = "action.de.danoeh.antennapod.service.enqueueDownload";
|
||||||
|
public static final String ACTION_CANCEL_DOWNLOAD = "action.de.danoeh.antennapod.service.cancelDownload";
|
||||||
|
public static final String ACTION_CANCEL_ALL_DOWNLOADS = "action.de.danoeh.antennapod.service.cancelAllDownloads";
|
||||||
|
|
||||||
|
/** Is used for sending the delete intent for the report notification */
|
||||||
|
private static final String ACTION_REPORT_DELETED = "action.de.danoeh.antennapod.service.reportDeleted";
|
||||||
|
|
||||||
|
/** Extra for ACTION_CANCEL_DOWNLOAD */
|
||||||
|
public static final String EXTRA_DOWNLOAD_URL = "downloadUrl";
|
||||||
|
|
||||||
public static final String ACTION_DOWNLOAD_HANDLED = "action.de.danoeh.antennapod.service.download_handled";
|
public static final String ACTION_DOWNLOAD_HANDLED = "action.de.danoeh.antennapod.service.download_handled";
|
||||||
/** True if handled feed has an image. */
|
/**
|
||||||
public static final String EXTRA_FEED_HAS_IMAGE = "extra.de.danoeh.antennapod.service.feed_has_image";
|
* Sent by the DownloadService when the content of the downloads list
|
||||||
|
* changes.
|
||||||
|
*/
|
||||||
|
public static final String ACTION_DOWNLOADS_CONTENT_CHANGED = "action.de.danoeh.antennapod.service.downloadsContentChanged";
|
||||||
|
|
||||||
public static final String EXTRA_DOWNLOAD_ID = "extra.de.danoeh.antennapod.service.download_id";
|
public static final String EXTRA_DOWNLOAD_ID = "extra.de.danoeh.antennapod.service.download_id";
|
||||||
public static final String EXTRA_IMAGE_DOWNLOAD_ID = "extra.de.danoeh.antennapod.service.image_download_id";
|
|
||||||
|
/** Extra for ACTION_ENQUEUE_DOWNLOAD intent. */
|
||||||
|
public static final String EXTRA_REQUEST = "request";
|
||||||
|
|
||||||
// Download types for ACTION_DOWNLOAD_HANDLED
|
// Download types for ACTION_DOWNLOAD_HANDLED
|
||||||
public static final String EXTRA_DOWNLOAD_TYPE = "extra.de.danoeh.antennapod.service.downloadType";
|
public static final String EXTRA_DOWNLOAD_TYPE = "extra.de.danoeh.antennapod.service.downloadType";
|
||||||
@ -81,9 +95,11 @@ public class DownloadService extends Service {
|
|||||||
public static final int DOWNLOAD_TYPE_MEDIA = 2;
|
public static final int DOWNLOAD_TYPE_MEDIA = 2;
|
||||||
public static final int DOWNLOAD_TYPE_IMAGE = 3;
|
public static final int DOWNLOAD_TYPE_IMAGE = 3;
|
||||||
|
|
||||||
private ArrayList<DownloadStatus> completedDownloads;
|
private CopyOnWriteArrayList<DownloadStatus> completedDownloads;
|
||||||
|
|
||||||
private ExecutorService syncExecutor;
|
private ExecutorService syncExecutor;
|
||||||
|
private ExecutorService downloadExecutor;
|
||||||
|
|
||||||
private DownloadRequester requester;
|
private DownloadRequester requester;
|
||||||
private FeedManager manager;
|
private FeedManager manager;
|
||||||
private NotificationCompat.Builder notificationBuilder;
|
private NotificationCompat.Builder notificationBuilder;
|
||||||
@ -91,16 +107,14 @@ public class DownloadService extends Service {
|
|||||||
private int REPORT_ID = 3;
|
private int REPORT_ID = 3;
|
||||||
/** Needed to determine the duration of a media file */
|
/** Needed to determine the duration of a media file */
|
||||||
private MediaPlayer mediaplayer;
|
private MediaPlayer mediaplayer;
|
||||||
private DownloadManager downloadManager;
|
|
||||||
|
|
||||||
private DownloadObserver downloadObserver;
|
private List<Downloader> downloads;
|
||||||
|
|
||||||
private volatile boolean shutdownInitiated = false;
|
private volatile boolean shutdownInitiated = false;
|
||||||
/** True if service is running. */
|
/** True if service is running. */
|
||||||
public static boolean isRunning = false;
|
public static boolean isRunning = false;
|
||||||
|
|
||||||
/** Is started when service waits for shutdown. */
|
private Handler handler;
|
||||||
private Thread waiter;
|
|
||||||
|
|
||||||
private final IBinder mBinder = new LocalBinder();
|
private final IBinder mBinder = new LocalBinder();
|
||||||
|
|
||||||
@ -112,11 +126,10 @@ public class DownloadService extends Service {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
if (waiter != null) {
|
if (intent.getParcelableExtra(EXTRA_REQUEST) != null) {
|
||||||
waiter.interrupt();
|
onDownloadQueued(intent);
|
||||||
}
|
}
|
||||||
queryDownloads();
|
return Service.START_NOT_STICKY;
|
||||||
return super.onStartCommand(intent, flags, startId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
@ -125,10 +138,18 @@ public class DownloadService extends Service {
|
|||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Service started");
|
Log.d(TAG, "Service started");
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
completedDownloads = new ArrayList<DownloadStatus>();
|
handler = new Handler();
|
||||||
registerReceiver(downloadReceiver, createIntentFilter());
|
completedDownloads = new CopyOnWriteArrayList<DownloadStatus>(
|
||||||
registerReceiver(onDownloadsChanged, new IntentFilter(
|
new ArrayList<DownloadStatus>());
|
||||||
ACTION_NOTIFY_DOWNLOADS_CHANGED));
|
downloads = new ArrayList<Downloader>();
|
||||||
|
registerReceiver(downloadQueued, new IntentFilter(
|
||||||
|
ACTION_ENQUEUE_DOWNLOAD));
|
||||||
|
|
||||||
|
IntentFilter cancelDownloadReceiverFilter = new IntentFilter();
|
||||||
|
cancelDownloadReceiverFilter.addAction(ACTION_CANCEL_ALL_DOWNLOADS);
|
||||||
|
cancelDownloadReceiverFilter.addAction(ACTION_CANCEL_DOWNLOAD);
|
||||||
|
registerReceiver(cancelDownloadReceiver, cancelDownloadReceiverFilter);
|
||||||
|
registerReceiver(reportDeleted, new IntentFilter(ACTION_REPORT_DELETED));
|
||||||
syncExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
|
syncExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -147,17 +168,20 @@ public class DownloadService extends Service {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
downloadExecutor = Executors.newFixedThreadPool(2, new ThreadFactory() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread t = new Thread(r);
|
||||||
|
t.setPriority(Thread.MIN_PRIORITY);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
});
|
||||||
manager = FeedManager.getInstance();
|
manager = FeedManager.getInstance();
|
||||||
requester = DownloadRequester.getInstance();
|
requester = DownloadRequester.getInstance();
|
||||||
mediaplayer = new MediaPlayer();
|
mediaplayer = new MediaPlayer();
|
||||||
downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
downloadObserver = new DownloadObserver(this);
|
|
||||||
setupNotification();
|
setupNotification();
|
||||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
|
||||||
downloadObserver.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
|
||||||
} else {
|
|
||||||
downloadObserver.execute();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -171,46 +195,8 @@ public class DownloadService extends Service {
|
|||||||
Log.d(TAG, "Service shutting down");
|
Log.d(TAG, "Service shutting down");
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
mediaplayer.release();
|
mediaplayer.release();
|
||||||
unregisterReceiver(downloadReceiver);
|
unregisterReceiver(cancelDownloadReceiver);
|
||||||
unregisterReceiver(onDownloadsChanged);
|
unregisterReceiver(downloadQueued);
|
||||||
downloadObserver.cancel(true);
|
|
||||||
createReport();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IntentFilter createIntentFilter() {
|
|
||||||
IntentFilter filter = new IntentFilter();
|
|
||||||
filter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
|
|
||||||
return filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Shuts down Executor service and prepares for shutdown */
|
|
||||||
private void initiateShutdown() {
|
|
||||||
if (AppConfig.DEBUG)
|
|
||||||
Log.d(TAG, "Initiating shutdown");
|
|
||||||
// Wait until PoolExecutor is done
|
|
||||||
waiter = new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
syncExecutor.shutdown();
|
|
||||||
try {
|
|
||||||
if (AppConfig.DEBUG)
|
|
||||||
Log.d(TAG, "Starting to wait for termination");
|
|
||||||
boolean b = syncExecutor.awaitTermination(20L,
|
|
||||||
TimeUnit.SECONDS);
|
|
||||||
if (AppConfig.DEBUG)
|
|
||||||
Log.d(TAG,
|
|
||||||
"Stopping waiting for termination; Result : "
|
|
||||||
+ b);
|
|
||||||
stopForeground(true);
|
|
||||||
stopSelf();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
Log.i(TAG, "Service shutdown was interrupted.");
|
|
||||||
shutdownInitiated = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
waiter.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupNotification() {
|
private void setupNotification() {
|
||||||
@ -232,104 +218,164 @@ public class DownloadService extends Service {
|
|||||||
Log.d(TAG, "Notification set up");
|
Log.d(TAG, "Notification set up");
|
||||||
}
|
}
|
||||||
|
|
||||||
private BroadcastReceiver onDownloadsChanged = new BroadcastReceiver() {
|
private Downloader getDownloader(String downloadUrl) {
|
||||||
|
for (Downloader downloader : downloads) {
|
||||||
|
if (downloader.getStatus().getFeedFile().getDownload_url()
|
||||||
|
.equals(downloadUrl)) {
|
||||||
|
return downloader;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BroadcastReceiver cancelDownloadReceiver = new BroadcastReceiver() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (intent.getAction().equals(ACTION_NOTIFY_DOWNLOADS_CHANGED)) {
|
if (intent.getAction().equals(ACTION_CANCEL_DOWNLOAD)) {
|
||||||
queryDownloads();
|
String url = intent.getStringExtra(EXTRA_DOWNLOAD_URL);
|
||||||
}
|
if (url == null) {
|
||||||
}
|
throw new IllegalArgumentException(
|
||||||
};
|
"ACTION_CANCEL_DOWNLOAD intent needs download url extra");
|
||||||
|
|
||||||
private BroadcastReceiver downloadReceiver = new BroadcastReceiver() {
|
|
||||||
@SuppressLint("NewApi")
|
|
||||||
@Override
|
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
|
||||||
AsyncTask<Void, Void, Void> handler = new AsyncTask<Void, Void, Void>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... params) {
|
|
||||||
int status = -1;
|
|
||||||
String file_url = null;
|
|
||||||
boolean successful = false;
|
|
||||||
int reason = 0;
|
|
||||||
if (AppConfig.DEBUG)
|
|
||||||
Log.d(TAG, "Received 'Download Complete' - message.");
|
|
||||||
long downloadId = intent.getLongExtra(
|
|
||||||
DownloadManager.EXTRA_DOWNLOAD_ID, 0);
|
|
||||||
// get status
|
|
||||||
DownloadManager.Query q = new DownloadManager.Query();
|
|
||||||
q.setFilterById(downloadId);
|
|
||||||
Cursor c = downloadManager.query(q);
|
|
||||||
if (c.moveToFirst()) {
|
|
||||||
status = c.getInt(c
|
|
||||||
.getColumnIndex(DownloadManager.COLUMN_STATUS));
|
|
||||||
String uriString = c
|
|
||||||
.getString(c
|
|
||||||
.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
|
|
||||||
if (uriString != null) {
|
|
||||||
Uri file_uri = Uri.parse(uriString);
|
|
||||||
file_url = file_uri.getPath();
|
|
||||||
} else {
|
|
||||||
Log.w(TAG,
|
|
||||||
"DownloadManager didn't provide a destination URI for downloaded file");
|
|
||||||
}
|
|
||||||
if (AppConfig.DEBUG)
|
|
||||||
Log.d(TAG, "File url given by download manager is "
|
|
||||||
+ file_url);
|
|
||||||
}
|
|
||||||
if (downloadId == 0) {
|
|
||||||
Log.d(TAG, "Download ID was null");
|
|
||||||
}
|
|
||||||
FeedFile download = requester.getFeedFile(downloadId);
|
|
||||||
if (download != null) {
|
|
||||||
if (status == DownloadManager.STATUS_SUCCESSFUL) {
|
|
||||||
if (file_url != null) {
|
|
||||||
download.setFile_url(file_url);
|
|
||||||
}
|
|
||||||
if (download.getClass() == Feed.class) {
|
|
||||||
handleCompletedFeedDownload(context,
|
|
||||||
(Feed) download);
|
|
||||||
} else if (download.getClass() == FeedImage.class) {
|
|
||||||
handleCompletedImageDownload(context,
|
|
||||||
(FeedImage) download);
|
|
||||||
} else if (download.getClass() == FeedMedia.class) {
|
|
||||||
handleCompletedFeedMediaDownload(context,
|
|
||||||
(FeedMedia) download);
|
|
||||||
}
|
|
||||||
successful = true;
|
|
||||||
|
|
||||||
} else if (status == DownloadManager.STATUS_FAILED) {
|
|
||||||
reason = c
|
|
||||||
.getInt(c
|
|
||||||
.getColumnIndex(DownloadManager.COLUMN_REASON));
|
|
||||||
Log.e(TAG, "Download failed");
|
|
||||||
Log.e(TAG, "reason code is " + reason);
|
|
||||||
successful = false;
|
|
||||||
saveDownloadStatus(new DownloadStatus(download,
|
|
||||||
reason, successful));
|
|
||||||
requester.removeDownload(download);
|
|
||||||
sendDownloadHandledIntent(download.getDownloadId(),
|
|
||||||
false, 0, getDownloadType(download));
|
|
||||||
download.setDownloadId(0);
|
|
||||||
|
|
||||||
}
|
|
||||||
queryDownloads();
|
|
||||||
}
|
|
||||||
c.close();
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
};
|
if (AppConfig.DEBUG)
|
||||||
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
Log.d(TAG, "Cancelling download with url " + url);
|
||||||
handler.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
Downloader d = getDownloader(url);
|
||||||
} else {
|
if (d != null) {
|
||||||
handler.execute();
|
d.interrupt();
|
||||||
|
removeDownload(d);
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Could not cancel download with url " + url);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (intent.getAction().equals(ACTION_CANCEL_ALL_DOWNLOADS)) {
|
||||||
|
for (Downloader d : downloads) {
|
||||||
|
d.interrupt();
|
||||||
|
DownloadRequester.getInstance().removeDownload(
|
||||||
|
d.getStatus().getFeedFile());
|
||||||
|
d.getStatus().getFeedFile().setFile_url(null);
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "Cancelled all downloads");
|
||||||
|
}
|
||||||
|
downloads.clear();
|
||||||
|
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
queryDownloads();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private void onDownloadQueued(Intent intent) {
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "Received enqueue request");
|
||||||
|
Request request = intent.getParcelableExtra(EXTRA_REQUEST);
|
||||||
|
if (request == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"ACTION_ENQUEUE_DOWNLOAD intent needs request extra");
|
||||||
|
}
|
||||||
|
if (shutdownInitiated) {
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "Cancelling shutdown; new download was queued");
|
||||||
|
shutdownInitiated = false;
|
||||||
|
setupNotification();
|
||||||
|
}
|
||||||
|
|
||||||
|
DownloadRequester requester = DownloadRequester.getInstance();
|
||||||
|
FeedFile feedfile = requester.getDownload(request.source);
|
||||||
|
if (feedfile != null) {
|
||||||
|
|
||||||
|
DownloadStatus status = new DownloadStatus(feedfile);
|
||||||
|
Downloader downloader = getDownloader(status);
|
||||||
|
if (downloader != null) {
|
||||||
|
downloads.add(downloader);
|
||||||
|
downloadExecutor.submit(downloader);
|
||||||
|
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e(TAG,
|
||||||
|
"Could not find feedfile in download requester when trying to enqueue new download");
|
||||||
|
queryDownloads();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BroadcastReceiver downloadQueued = new BroadcastReceiver() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
onDownloadQueued(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private Downloader getDownloader(DownloadStatus status) {
|
||||||
|
if (URLUtil.isHttpUrl(status.getFeedFile().getDownload_url())) {
|
||||||
|
return new HttpDownloader(this, status);
|
||||||
|
}
|
||||||
|
Log.e(TAG, "Could not find appropriate downloader for "
|
||||||
|
+ status.getFeedFile().getDownload_url());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NewApi")
|
||||||
|
public void onDownloadCompleted(final Downloader downloader) {
|
||||||
|
final AsyncTask<Void, Void, Void> handlerTask = new AsyncTask<Void, Void, Void>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "Received 'Download Complete' - message.");
|
||||||
|
DownloadStatus status = downloader.getStatus();
|
||||||
|
status.setCompletionDate(new Date());
|
||||||
|
boolean successful = status.isSuccessful();
|
||||||
|
int reason = status.getReason();
|
||||||
|
|
||||||
|
FeedFile download = status.getFeedFile();
|
||||||
|
if (download != null) {
|
||||||
|
if (successful) {
|
||||||
|
if (download.getClass() == Feed.class) {
|
||||||
|
handleCompletedFeedDownload(status);
|
||||||
|
} else if (download.getClass() == FeedImage.class) {
|
||||||
|
handleCompletedImageDownload(status);
|
||||||
|
} else if (download.getClass() == FeedMedia.class) {
|
||||||
|
handleCompletedFeedMediaDownload(status);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!successful
|
||||||
|
&& reason != DownloadError.ERROR_DOWNLOAD_CANCELLED) {
|
||||||
|
Log.e(TAG, "Download failed");
|
||||||
|
}
|
||||||
|
saveDownloadStatus(status);
|
||||||
|
sendDownloadHandledIntent(getDownloadType(download));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeDownload(downloader);
|
||||||
|
if (!successful) {
|
||||||
|
queryDownloads();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||||
|
handlerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||||
|
} else {
|
||||||
|
handlerTask.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove download from the DownloadRequester list and from the
|
||||||
|
* DownloadService list.
|
||||||
|
*/
|
||||||
|
private void removeDownload(final Downloader d) {
|
||||||
|
downloads.remove(d);
|
||||||
|
DownloadRequester.getInstance().removeDownload(
|
||||||
|
d.getStatus().getFeedFile());
|
||||||
|
sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new DownloadStatus object to the list of completed downloads and
|
* Adds a new DownloadStatus object to the list of completed downloads and
|
||||||
* saves it in the database
|
* saves it in the database
|
||||||
@ -355,41 +401,32 @@ public class DownloadService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendDownloadHandledIntent(long downloadId,
|
private void sendDownloadHandledIntent(int type) {
|
||||||
boolean feedHasImage, long imageDownloadId, int type) {
|
|
||||||
Intent intent = new Intent(ACTION_DOWNLOAD_HANDLED);
|
Intent intent = new Intent(ACTION_DOWNLOAD_HANDLED);
|
||||||
intent.putExtra(EXTRA_DOWNLOAD_ID, downloadId);
|
|
||||||
intent.putExtra(EXTRA_FEED_HAS_IMAGE, feedHasImage);
|
|
||||||
intent.putExtra(EXTRA_DOWNLOAD_TYPE, type);
|
intent.putExtra(EXTRA_DOWNLOAD_TYPE, type);
|
||||||
if (feedHasImage) {
|
|
||||||
intent.putExtra(EXTRA_IMAGE_DOWNLOAD_ID, imageDownloadId);
|
|
||||||
}
|
|
||||||
sendBroadcast(intent);
|
sendBroadcast(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BroadcastReceiver reportDeleted = new BroadcastReceiver() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
if (intent.getAction().equals(ACTION_REPORT_DELETED)) {
|
||||||
|
completedDownloads.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a notification at the end of the service lifecycle to notify the
|
* Creates a notification at the end of the service lifecycle to notify the
|
||||||
* user about the number of completed downloads. A report will only be
|
* user about the number of completed downloads. A report will only be
|
||||||
* created if the number of feeds is > 1 or if at least one media file was
|
* created if the number of feeds is > 1 or if at least one media file was
|
||||||
* downloaded.
|
* downloaded.
|
||||||
*/
|
*/
|
||||||
private void createReport() {
|
private void updateReport() {
|
||||||
// check if report should be created
|
// check if report should be created
|
||||||
boolean createReport = false;
|
if (!completedDownloads.isEmpty()) {
|
||||||
int feedCount = 0;
|
|
||||||
for (DownloadStatus status : completedDownloads) {
|
|
||||||
if (status.getFeedFile().getClass() == Feed.class) {
|
|
||||||
feedCount++;
|
|
||||||
if (feedCount > 1) {
|
|
||||||
createReport = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (status.getFeedFile().getClass() == FeedMedia.class) {
|
|
||||||
createReport = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (createReport) {
|
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Creating report");
|
Log.d(TAG, "Creating report");
|
||||||
int successfulDownloads = 0;
|
int successfulDownloads = 0;
|
||||||
@ -417,7 +454,12 @@ public class DownloadService extends Service {
|
|||||||
.setContentIntent(
|
.setContentIntent(
|
||||||
PendingIntent.getActivity(this, 0, new Intent(this,
|
PendingIntent.getActivity(this, 0, new Intent(this,
|
||||||
MainActivity.class), 0))
|
MainActivity.class), 0))
|
||||||
.setAutoCancel(true).getNotification();
|
.setAutoCancel(true)
|
||||||
|
.setDeleteIntent(
|
||||||
|
PendingIntent.getBroadcast(this, 0, new Intent(
|
||||||
|
ACTION_REPORT_DELETED),
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT))
|
||||||
|
.getNotification();
|
||||||
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
nm.notify(REPORT_ID, notification);
|
nm.notify(REPORT_ID, notification);
|
||||||
|
|
||||||
@ -428,11 +470,18 @@ public class DownloadService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Check if there's something else to download, otherwise stop */
|
/** Check if there's something else to download, otherwise stop */
|
||||||
private void queryDownloads() {
|
void queryDownloads() {
|
||||||
int numOfDownloads = requester.getNumberOfDownloads();
|
int numOfDownloads = downloads.size();
|
||||||
if (!shutdownInitiated && numOfDownloads == 0) {
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, numOfDownloads + " downloads left");
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "ShutdownInitiated: " + shutdownInitiated);
|
||||||
|
|
||||||
|
if (numOfDownloads == 0) {
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "Starting shutdown");
|
||||||
shutdownInitiated = true;
|
shutdownInitiated = true;
|
||||||
initiateShutdown();
|
stopForeground(true);
|
||||||
} else {
|
} else {
|
||||||
// update notification
|
// update notification
|
||||||
notificationBuilder.setContentText(numOfDownloads
|
notificationBuilder.setContentText(numOfDownloads
|
||||||
@ -440,29 +489,29 @@ public class DownloadService extends Service {
|
|||||||
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
nm.notify(NOTIFICATION_ID, notificationBuilder.getNotification());
|
nm.notify(NOTIFICATION_ID, notificationBuilder.getNotification());
|
||||||
}
|
}
|
||||||
|
updateReport();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Is called whenever a Feed is downloaded */
|
/** Is called whenever a Feed is downloaded */
|
||||||
private void handleCompletedFeedDownload(Context context, Feed feed) {
|
private void handleCompletedFeedDownload(DownloadStatus status) {
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Handling completed Feed Download");
|
Log.d(TAG, "Handling completed Feed Download");
|
||||||
syncExecutor.execute(new FeedSyncThread(feed, this));
|
syncExecutor.execute(new FeedSyncThread(status));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Is called whenever a Feed-Image is downloaded */
|
/** Is called whenever a Feed-Image is downloaded */
|
||||||
private void handleCompletedImageDownload(Context context, FeedImage image) {
|
private void handleCompletedImageDownload(DownloadStatus status) {
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Handling completed Image Download");
|
Log.d(TAG, "Handling completed Image Download");
|
||||||
syncExecutor.execute(new ImageHandlerThread(image, this));
|
syncExecutor.execute(new ImageHandlerThread(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Is called whenever a FeedMedia is downloaded. */
|
/** Is called whenever a FeedMedia is downloaded. */
|
||||||
private void handleCompletedFeedMediaDownload(Context context,
|
private void handleCompletedFeedMediaDownload(DownloadStatus status) {
|
||||||
FeedMedia media) {
|
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Handling completed FeedMedia Download");
|
Log.d(TAG, "Handling completed FeedMedia Download");
|
||||||
syncExecutor.execute(new MediaHandlerThread(media, this));
|
syncExecutor.execute(new MediaHandlerThread(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -473,21 +522,18 @@ public class DownloadService extends Service {
|
|||||||
private static final String TAG = "FeedSyncThread";
|
private static final String TAG = "FeedSyncThread";
|
||||||
|
|
||||||
private Feed feed;
|
private Feed feed;
|
||||||
private DownloadService service;
|
private DownloadStatus status;
|
||||||
|
|
||||||
private int reason;
|
private int reason;
|
||||||
private boolean successful;
|
private boolean successful;
|
||||||
|
|
||||||
public FeedSyncThread(Feed feed, DownloadService service) {
|
public FeedSyncThread(DownloadStatus status) {
|
||||||
this.feed = feed;
|
this.feed = (Feed) status.getFeedFile();
|
||||||
this.service = service;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
Feed savedFeed = null;
|
Feed savedFeed = null;
|
||||||
long imageId = 0;
|
|
||||||
boolean hasImage = false;
|
|
||||||
long downloadId = feed.getDownloadId();
|
|
||||||
reason = 0;
|
reason = 0;
|
||||||
successful = true;
|
successful = true;
|
||||||
FeedManager manager = FeedManager.getInstance();
|
FeedManager manager = FeedManager.getInstance();
|
||||||
@ -501,18 +547,16 @@ public class DownloadService extends Service {
|
|||||||
if (checkFeedData(feed) == false) {
|
if (checkFeedData(feed) == false) {
|
||||||
throw new InvalidFeedException();
|
throw new InvalidFeedException();
|
||||||
}
|
}
|
||||||
feed.setDownloadId(0);
|
|
||||||
// Save information of feed in DB
|
// Save information of feed in DB
|
||||||
savedFeed = manager.updateFeed(service, feed);
|
savedFeed = manager.updateFeed(DownloadService.this, feed);
|
||||||
// Download Feed Image if provided and not downloaded
|
// Download Feed Image if provided and not downloaded
|
||||||
if (savedFeed.getImage() != null
|
if (savedFeed.getImage() != null
|
||||||
&& savedFeed.getImage().isDownloaded() == false) {
|
&& savedFeed.getImage().isDownloaded() == false) {
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Feed has image; Downloading....");
|
Log.d(TAG, "Feed has image; Downloading....");
|
||||||
savedFeed.getImage().setFeed(savedFeed);
|
savedFeed.getImage().setFeed(savedFeed);
|
||||||
imageId = requester.downloadImage(service,
|
requester.downloadImage(DownloadService.this,
|
||||||
savedFeed.getImage());
|
savedFeed.getImage());
|
||||||
hasImage = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (SAXException e) {
|
} catch (SAXException e) {
|
||||||
@ -537,14 +581,13 @@ public class DownloadService extends Service {
|
|||||||
reason = DownloadError.ERROR_PARSER_EXCEPTION;
|
reason = DownloadError.ERROR_PARSER_EXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
requester.removeDownload(feed);
|
|
||||||
// cleanup();
|
// cleanup();
|
||||||
if (savedFeed == null) {
|
if (savedFeed == null) {
|
||||||
savedFeed = feed;
|
savedFeed = feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveDownloadStatus(new DownloadStatus(savedFeed, reason, successful));
|
saveDownloadStatus(new DownloadStatus(savedFeed, reason, successful));
|
||||||
sendDownloadHandledIntent(downloadId, hasImage, imageId,
|
sendDownloadHandledIntent(DOWNLOAD_TYPE_FEED);
|
||||||
DOWNLOAD_TYPE_FEED);
|
|
||||||
queryDownloads();
|
queryDownloads();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -579,25 +622,22 @@ public class DownloadService extends Service {
|
|||||||
/** Handles a completed image download. */
|
/** Handles a completed image download. */
|
||||||
class ImageHandlerThread implements Runnable {
|
class ImageHandlerThread implements Runnable {
|
||||||
private FeedImage image;
|
private FeedImage image;
|
||||||
private DownloadService service;
|
private DownloadStatus status;
|
||||||
|
|
||||||
public ImageHandlerThread(FeedImage image, DownloadService service) {
|
public ImageHandlerThread(DownloadStatus status) {
|
||||||
this.image = image;
|
this.image = (FeedImage) status.getFeedFile();
|
||||||
this.service = service;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
image.setDownloaded(true);
|
image.setDownloaded(true);
|
||||||
requester.removeDownload(image);
|
|
||||||
|
|
||||||
saveDownloadStatus(new DownloadStatus(image, 0, true));
|
saveDownloadStatus(status);
|
||||||
sendDownloadHandledIntent(image.getDownloadId(), false, 0,
|
sendDownloadHandledIntent(DOWNLOAD_TYPE_IMAGE);
|
||||||
DOWNLOAD_TYPE_IMAGE);
|
manager.setFeedImage(DownloadService.this, image);
|
||||||
image.setDownloadId(0);
|
|
||||||
manager.setFeedImage(service, image);
|
|
||||||
if (image.getFeed() != null) {
|
if (image.getFeed() != null) {
|
||||||
manager.setFeed(service, image.getFeed());
|
manager.setFeed(DownloadService.this, image.getFeed());
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG,
|
Log.e(TAG,
|
||||||
"Image has no feed, image might not be saved correctly!");
|
"Image has no feed, image might not be saved correctly!");
|
||||||
@ -609,17 +649,16 @@ public class DownloadService extends Service {
|
|||||||
/** Handles a completed media download. */
|
/** Handles a completed media download. */
|
||||||
class MediaHandlerThread implements Runnable {
|
class MediaHandlerThread implements Runnable {
|
||||||
private FeedMedia media;
|
private FeedMedia media;
|
||||||
private DownloadService service;
|
private DownloadStatus status;
|
||||||
|
|
||||||
public MediaHandlerThread(FeedMedia media, DownloadService service) {
|
public MediaHandlerThread(DownloadStatus status) {
|
||||||
super();
|
super();
|
||||||
this.media = media;
|
this.media = (FeedMedia) status.getFeedFile();
|
||||||
this.service = service;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
requester.removeDownload(media);
|
|
||||||
media.setDownloaded(true);
|
media.setDownloaded(true);
|
||||||
// Get duration
|
// Get duration
|
||||||
try {
|
try {
|
||||||
@ -632,11 +671,10 @@ public class DownloadService extends Service {
|
|||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Duration of file is " + media.getDuration());
|
Log.d(TAG, "Duration of file is " + media.getDuration());
|
||||||
mediaplayer.reset();
|
mediaplayer.reset();
|
||||||
saveDownloadStatus(new DownloadStatus(media, 0, true));
|
|
||||||
sendDownloadHandledIntent(media.getDownloadId(), false, 0,
|
saveDownloadStatus(status);
|
||||||
DOWNLOAD_TYPE_MEDIA);
|
sendDownloadHandledIntent(DOWNLOAD_TYPE_MEDIA);
|
||||||
media.setDownloadId(0);
|
manager.setFeedMedia(DownloadService.this, media);
|
||||||
manager.setFeedMedia(service, media);
|
|
||||||
boolean autoQueue = PreferenceManager.getDefaultSharedPreferences(
|
boolean autoQueue = PreferenceManager.getDefaultSharedPreferences(
|
||||||
getApplicationContext()).getBoolean(
|
getApplicationContext()).getBoolean(
|
||||||
PodcastApp.PREF_AUTO_QUEUE, true);
|
PodcastApp.PREF_AUTO_QUEUE, true);
|
||||||
@ -655,13 +693,59 @@ public class DownloadService extends Service {
|
|||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Item is already in queue");
|
Log.d(TAG, "Item is already in queue");
|
||||||
}
|
}
|
||||||
|
|
||||||
queryDownloads();
|
queryDownloads();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadObserver getDownloadObserver() {
|
/** Is used to request a new download. */
|
||||||
return downloadObserver;
|
public static class Request implements Parcelable {
|
||||||
|
private String destination;
|
||||||
|
private String source;
|
||||||
|
|
||||||
|
public Request(String destination, String source) {
|
||||||
|
super();
|
||||||
|
this.destination = destination;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Request(Parcel in) {
|
||||||
|
destination = in.readString();
|
||||||
|
source = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeString(destination);
|
||||||
|
dest.writeString(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Parcelable.Creator<Request> CREATOR = new Parcelable.Creator<Request>() {
|
||||||
|
public Request createFromParcel(Parcel in) {
|
||||||
|
return new Request(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request[] newArray(int size) {
|
||||||
|
return new Request[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public String getDestination() {
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Downloader> getDownloads() {
|
||||||
|
return downloads;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
59
src/de/danoeh/antennapod/service/download/Downloader.java
Normal file
59
src/de/danoeh/antennapod/service/download/Downloader.java
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package de.danoeh.antennapod.service.download;
|
||||||
|
|
||||||
|
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.StatFs;
|
||||||
|
|
||||||
|
/** Downloads files */
|
||||||
|
public abstract class Downloader extends Thread {
|
||||||
|
private static final String TAG = "Downloader";
|
||||||
|
private Handler handler;
|
||||||
|
private DownloadService downloadService;
|
||||||
|
|
||||||
|
protected boolean finished;
|
||||||
|
|
||||||
|
protected volatile DownloadStatus status;
|
||||||
|
|
||||||
|
public Downloader(DownloadService downloadService, DownloadStatus status) {
|
||||||
|
super();
|
||||||
|
this.downloadService = downloadService;
|
||||||
|
this.status = status;
|
||||||
|
handler = new Handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method must be called when the download was completed, failed, or
|
||||||
|
* was cancelled
|
||||||
|
*/
|
||||||
|
protected void finish() {
|
||||||
|
if (!finished) {
|
||||||
|
finished = true;
|
||||||
|
handler.post(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
downloadService.onDownloadCompleted(Downloader.this);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void publishProgress() {
|
||||||
|
status.setUpdateAvailable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void download();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void run() {
|
||||||
|
download();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DownloadStatus getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
136
src/de/danoeh/antennapod/service/download/HttpDownloader.java
Normal file
136
src/de/danoeh/antennapod/service/download/HttpDownloader.java
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
package de.danoeh.antennapod.service.download;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.SocketTimeoutException;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import de.danoeh.antennapod.AppConfig;
|
||||||
|
import de.danoeh.antennapod.R;
|
||||||
|
import de.danoeh.antennapod.asynctask.DownloadStatus;
|
||||||
|
import de.danoeh.antennapod.util.DownloadError;
|
||||||
|
import de.danoeh.antennapod.util.StorageUtils;
|
||||||
|
|
||||||
|
public class HttpDownloader extends Downloader {
|
||||||
|
private static final String TAG = "HttpDownloader";
|
||||||
|
|
||||||
|
private static final int BUFFER_SIZE = 8 * 1024;
|
||||||
|
private static final int CONNECTION_TIMEOUT = 5000;
|
||||||
|
|
||||||
|
public HttpDownloader(DownloadService downloadService, DownloadStatus status) {
|
||||||
|
super(downloadService, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void download() {
|
||||||
|
HttpURLConnection connection = null;
|
||||||
|
OutputStream out = null;
|
||||||
|
try {
|
||||||
|
status.setStatusMsg(R.string.download_pending);
|
||||||
|
publishProgress();
|
||||||
|
URL url = new URL(status.getFeedFile().getDownload_url());
|
||||||
|
connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setConnectTimeout(CONNECTION_TIMEOUT);
|
||||||
|
if (AppConfig.DEBUG) {
|
||||||
|
Log.d(TAG, "Connected to resource");
|
||||||
|
}
|
||||||
|
if (StorageUtils.externalStorageMounted()) {
|
||||||
|
File destination = new File(status.getFeedFile().getFile_url());
|
||||||
|
if (!destination.exists()) {
|
||||||
|
InputStream in = new BufferedInputStream(
|
||||||
|
connection.getInputStream());
|
||||||
|
out = new BufferedOutputStream(new FileOutputStream(
|
||||||
|
destination));
|
||||||
|
byte[] buffer = new byte[BUFFER_SIZE];
|
||||||
|
int count = 0;
|
||||||
|
status.setStatusMsg(R.string.download_running);
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "Getting size of download");
|
||||||
|
status.setSize(connection.getContentLength());
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "Size is " + status.getSize());
|
||||||
|
if (status.getSize() == -1
|
||||||
|
|| status.getSize() <= StorageUtils
|
||||||
|
.getFreeSpaceAvailable()) {
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "Size is " + status.getSize());
|
||||||
|
publishProgress();
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "Starting download");
|
||||||
|
while ((count = in.read(buffer)) != -1
|
||||||
|
&& !isInterrupted()) {
|
||||||
|
out.write(buffer, 0, count);
|
||||||
|
status.setSoFar(status.getSoFar() + count);
|
||||||
|
status.setProgressPercent((int) (((double) status
|
||||||
|
.getSoFar() / (double) status.getSize()) * 100));
|
||||||
|
}
|
||||||
|
if (isInterrupted()) {
|
||||||
|
onCancelled();
|
||||||
|
} else {
|
||||||
|
onSuccess();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onFail(DownloadError.ERROR_NOT_ENOUGH_SPACE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onFail(DownloadError.ERROR_FILE_EXISTS);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onFail(DownloadError.ERROR_DEVICE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
onFail(DownloadError.ERROR_MALFORMED_URL);
|
||||||
|
} catch (SocketTimeoutException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
onFail(DownloadError.ERROR_CONNECTION_ERROR);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
onFail(DownloadError.ERROR_IO_ERROR);
|
||||||
|
} finally {
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
if (out != null) {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSuccess() {
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "Download was successful");
|
||||||
|
status.setSuccessful(true);
|
||||||
|
status.setDone(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onFail(int reason) {
|
||||||
|
if (AppConfig.DEBUG) {
|
||||||
|
Log.d(TAG, "Download failed");
|
||||||
|
}
|
||||||
|
status.setReason(reason);
|
||||||
|
status.setDone(true);
|
||||||
|
status.setSuccessful(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onCancelled() {
|
||||||
|
if (AppConfig.DEBUG)
|
||||||
|
Log.d(TAG, "Download was cancelled");
|
||||||
|
status.setReason(DownloadError.ERROR_DOWNLOAD_CANCELLED);
|
||||||
|
status.setDone(true);
|
||||||
|
status.setSuccessful(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,17 +1,11 @@
|
|||||||
package de.danoeh.antennapod.storage;
|
package de.danoeh.antennapod.storage;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
|
||||||
import android.app.DownloadManager;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.webkit.URLUtil;
|
import android.webkit.URLUtil;
|
||||||
import de.danoeh.antennapod.AppConfig;
|
import de.danoeh.antennapod.AppConfig;
|
||||||
@ -19,31 +13,28 @@ import de.danoeh.antennapod.feed.Feed;
|
|||||||
import de.danoeh.antennapod.feed.FeedFile;
|
import de.danoeh.antennapod.feed.FeedFile;
|
||||||
import de.danoeh.antennapod.feed.FeedImage;
|
import de.danoeh.antennapod.feed.FeedImage;
|
||||||
import de.danoeh.antennapod.feed.FeedMedia;
|
import de.danoeh.antennapod.feed.FeedMedia;
|
||||||
import de.danoeh.antennapod.service.DownloadService;
|
import de.danoeh.antennapod.service.download.DownloadService;
|
||||||
import de.danoeh.antennapod.util.NumberGenerator;
|
import de.danoeh.antennapod.util.NumberGenerator;
|
||||||
import de.danoeh.antennapod.util.URLChecker;
|
import de.danoeh.antennapod.util.URLChecker;
|
||||||
|
|
||||||
public class DownloadRequester {// TODO handle externalstorage missing
|
public class DownloadRequester {
|
||||||
private static final String TAG = "DownloadRequester";
|
private static final String TAG = "DownloadRequester";
|
||||||
private static final int currentApi = android.os.Build.VERSION.SDK_INT;
|
|
||||||
|
|
||||||
public static String EXTRA_DOWNLOAD_ID = "extra.de.danoeh.antennapod.storage.download_id";
|
public static String EXTRA_DOWNLOAD_ID = "extra.de.danoeh.antennapod.storage.download_id";
|
||||||
public static String EXTRA_ITEM_ID = "extra.de.danoeh.antennapod.storage.item_id";
|
public static String EXTRA_ITEM_ID = "extra.de.danoeh.antennapod.storage.item_id";
|
||||||
|
|
||||||
public static String ACTION_DOWNLOAD_QUEUED = "action.de.danoeh.antennapod.storage.downloadQueued";
|
public static String ACTION_DOWNLOAD_QUEUED = "action.de.danoeh.antennapod.storage.downloadQueued";
|
||||||
|
|
||||||
private static boolean STORE_ON_SD = true;
|
|
||||||
public static String IMAGE_DOWNLOADPATH = "images/";
|
public static String IMAGE_DOWNLOADPATH = "images/";
|
||||||
public static String FEED_DOWNLOADPATH = "cache/";
|
public static String FEED_DOWNLOADPATH = "cache/";
|
||||||
public static String MEDIA_DOWNLOADPATH = "media/";
|
public static String MEDIA_DOWNLOADPATH = "media/";
|
||||||
|
|
||||||
private static DownloadRequester downloader;
|
private static DownloadRequester downloader;
|
||||||
private DownloadManager manager;
|
|
||||||
|
|
||||||
private List<FeedFile> downloads;
|
Map<String, FeedFile> downloads;
|
||||||
|
|
||||||
private DownloadRequester() {
|
private DownloadRequester() {
|
||||||
downloads = new CopyOnWriteArrayList<FeedFile>();
|
downloads = new ConcurrentHashMap<String, FeedFile>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DownloadRequester getInstance() {
|
public static DownloadRequester getInstance() {
|
||||||
@ -53,8 +44,7 @@ public class DownloadRequester {// TODO handle externalstorage missing
|
|||||||
return downloader;
|
return downloader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
private void download(Context context, FeedFile item, File dest) {
|
||||||
private long download(Context context, FeedFile item, File dest) {
|
|
||||||
if (!isDownloadingFile(item)) {
|
if (!isDownloadingFile(item)) {
|
||||||
if (dest.exists()) {
|
if (dest.exists()) {
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
@ -64,106 +54,75 @@ public class DownloadRequester {// TODO handle externalstorage missing
|
|||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG,
|
Log.d(TAG,
|
||||||
"Requesting download of url " + item.getDownload_url());
|
"Requesting download of url " + item.getDownload_url());
|
||||||
downloads.add(item);
|
|
||||||
item.setDownload_url(URLChecker.prepareURL(item.getDownload_url()));
|
item.setDownload_url(URLChecker.prepareURL(item.getDownload_url()));
|
||||||
DownloadManager.Request request = new DownloadManager.Request(
|
|
||||||
Uri.parse(item.getDownload_url())).setDestinationUri(Uri
|
|
||||||
.fromFile(dest));
|
|
||||||
if (AppConfig.DEBUG)
|
|
||||||
Log.d(TAG, "Version is " + currentApi);
|
|
||||||
if (currentApi >= 11) {
|
|
||||||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
|
|
||||||
} else {
|
|
||||||
request.setVisibleInDownloadsUi(false);
|
|
||||||
request.setShowRunningNotification(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO Set Allowed Network Types
|
|
||||||
DownloadManager manager = (DownloadManager) context
|
|
||||||
.getSystemService(Context.DOWNLOAD_SERVICE);
|
|
||||||
|
|
||||||
long downloadId = manager.enqueue(request);
|
|
||||||
item.setDownloadId(downloadId);
|
|
||||||
item.setFile_url(dest.toString());
|
item.setFile_url(dest.toString());
|
||||||
context.startService(new Intent(context, DownloadService.class));
|
downloads.put(item.getDownload_url(), item);
|
||||||
|
|
||||||
|
DownloadService.Request request = new DownloadService.Request(
|
||||||
|
item.getFile_url(), item.getDownload_url());
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
context.sendBroadcast(new Intent(ACTION_DOWNLOAD_QUEUED));
|
context.sendBroadcast(new Intent(ACTION_DOWNLOAD_QUEUED));
|
||||||
return downloadId;
|
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "URL " + item.getDownload_url()
|
Log.e(TAG, "URL " + item.getDownload_url()
|
||||||
+ " is already being downloaded");
|
+ " is already being downloaded");
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long downloadFeed(Context context, Feed feed) {
|
public void downloadFeed(Context context, Feed feed) {
|
||||||
return download(context, feed, new File(getFeedfilePath(context),
|
download(context, feed, new File(getFeedfilePath(context),
|
||||||
getFeedfileName(feed)));
|
getFeedfileName(feed)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public long downloadImage(Context context, FeedImage image) {
|
public void downloadImage(Context context, FeedImage image) {
|
||||||
return download(context, image, new File(getImagefilePath(context),
|
download(context, image, new File(getImagefilePath(context),
|
||||||
getImagefileName(image)));
|
getImagefileName(image)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public long downloadMedia(Context context, FeedMedia feedmedia) {
|
public void downloadMedia(Context context, FeedMedia feedmedia) {
|
||||||
return download(context, feedmedia,
|
download(context, feedmedia,
|
||||||
new File(getMediafilePath(context, feedmedia),
|
new File(getMediafilePath(context, feedmedia),
|
||||||
getMediafilename(feedmedia)));
|
getMediafilename(feedmedia)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels a running download.
|
* Cancels a running download.
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* A context needed to get the DownloadManager service
|
|
||||||
* @param id
|
|
||||||
* ID of the download to cancel
|
|
||||||
* */
|
* */
|
||||||
public void cancelDownload(final Context context, final long id) {
|
public void cancelDownload(final Context context, final FeedFile f) {
|
||||||
|
cancelDownload(context, f.getDownload_url());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels a running download.
|
||||||
|
* */
|
||||||
|
public void cancelDownload(final Context context, final String downloadUrl) {
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Cancelling download with id " + id);
|
Log.d(TAG, "Cancelling download with url " + downloadUrl);
|
||||||
DownloadManager dm = (DownloadManager) context
|
Intent cancelIntent = new Intent(DownloadService.ACTION_CANCEL_DOWNLOAD);
|
||||||
.getSystemService(Context.DOWNLOAD_SERVICE);
|
cancelIntent.putExtra(DownloadService.EXTRA_DOWNLOAD_URL, downloadUrl);
|
||||||
int removed = dm.remove(id);
|
context.sendBroadcast(cancelIntent);
|
||||||
if (removed > 0) {
|
|
||||||
FeedFile f = getFeedFile(id);
|
|
||||||
if (f != null) {
|
|
||||||
downloads.remove(f);
|
|
||||||
f.setFile_url(null);
|
|
||||||
f.setDownloadId(0);
|
|
||||||
}
|
|
||||||
notifyDownloadService(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Cancels all running downloads */
|
/** Cancels all running downloads */
|
||||||
public void cancelAllDownloads(Context context) {
|
public void cancelAllDownloads(Context context) {
|
||||||
if (AppConfig.DEBUG)
|
if (AppConfig.DEBUG)
|
||||||
Log.d(TAG, "Cancelling all running downloads");
|
Log.d(TAG, "Cancelling all running downloads");
|
||||||
DownloadManager dm = (DownloadManager) context
|
context.sendBroadcast(new Intent(
|
||||||
.getSystemService(Context.DOWNLOAD_SERVICE);
|
DownloadService.ACTION_CANCEL_ALL_DOWNLOADS));
|
||||||
for (FeedFile f : downloads) {
|
|
||||||
dm.remove(f.getDownloadId());
|
|
||||||
f.setFile_url(null);
|
|
||||||
f.setDownloadId(0);
|
|
||||||
}
|
|
||||||
downloads.clear();
|
|
||||||
notifyDownloadService(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a feedfile by its download id */
|
|
||||||
public FeedFile getFeedFile(long id) {
|
|
||||||
for (FeedFile f : downloads) {
|
|
||||||
if (f.getDownloadId() == id) {
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns true if there is at least one Feed in the downloads queue. */
|
/** Returns true if there is at least one Feed in the downloads queue. */
|
||||||
public boolean isDownloadingFeeds() {
|
public boolean isDownloadingFeeds() {
|
||||||
for (FeedFile f : downloads) {
|
for (FeedFile f : downloads.values()) {
|
||||||
if (f.getClass() == Feed.class) {
|
if (f.getClass() == Feed.class) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -173,22 +132,19 @@ public class DownloadRequester {// TODO handle externalstorage missing
|
|||||||
|
|
||||||
/** Checks if feedfile is in the downloads list */
|
/** Checks if feedfile is in the downloads list */
|
||||||
public boolean isDownloadingFile(FeedFile item) {
|
public boolean isDownloadingFile(FeedFile item) {
|
||||||
for (FeedFile f : downloads) {
|
if (item.getDownload_url() != null) {
|
||||||
if (f.getDownload_url().equals(item.getDownload_url())) {
|
return downloads.containsKey(item.getDownload_url());
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FeedFile getDownload(String downloadUrl) {
|
||||||
|
return downloads.get(downloadUrl);
|
||||||
|
}
|
||||||
|
|
||||||
/** Checks if feedfile with the given download url is in the downloads list */
|
/** Checks if feedfile with the given download url is in the downloads list */
|
||||||
public boolean isDownloadingFile(String downloadUrl) {
|
public boolean isDownloadingFile(String downloadUrl) {
|
||||||
for (FeedFile f : downloads) {
|
return downloads.get(downloadUrl) != null;
|
||||||
if (f.getDownload_url().equals(downloadUrl)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasNoDownloads() {
|
public boolean hasNoDownloads() {
|
||||||
@ -201,11 +157,9 @@ public class DownloadRequester {// TODO handle externalstorage missing
|
|||||||
|
|
||||||
/** Remove an object from the downloads-list of the requester. */
|
/** Remove an object from the downloads-list of the requester. */
|
||||||
public void removeDownload(FeedFile f) {
|
public void removeDownload(FeedFile f) {
|
||||||
downloads.remove(f);
|
if (downloads.remove(f.getDownload_url()) == null) {
|
||||||
}
|
Log.e(TAG, "Could not remove object with url " + f.getDownload_url());
|
||||||
|
}
|
||||||
public List<FeedFile> getDownloads() {
|
|
||||||
return downloads;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the number of uncompleted Downloads */
|
/** Get the number of uncompleted Downloads */
|
||||||
@ -241,8 +195,4 @@ public class DownloadRequester {// TODO handle externalstorage missing
|
|||||||
media.getMime_type());
|
media.getMime_type());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Notifies the DownloadService to check if there are any Downloads left */
|
|
||||||
public void notifyDownloadService(Context context) {
|
|
||||||
context.sendBroadcast(new Intent(DownloadService.ACTION_NOTIFY_DOWNLOADS_CHANGED));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,12 @@ import android.util.Log;
|
|||||||
/** Parses several date formats. */
|
/** Parses several date formats. */
|
||||||
public class SyndDateUtils {
|
public class SyndDateUtils {
|
||||||
private static final String TAG = "DateUtils";
|
private static final String TAG = "DateUtils";
|
||||||
public static final String RFC822 = "dd MMM yyyy HH:mm:ss Z";
|
|
||||||
/** RFC 822 date format with day of the week. */
|
public static final String[] RFC822DATES = { "EEE, dd MMM yyyy HH:mm:ss Z",
|
||||||
public static final String RFC822DAY = "EEE, " + RFC822;
|
"dd MMM yyyy HH:mm:ss Z", "EEE, dd MMM yy HH:mm:ss Z",
|
||||||
|
"dd MMM yy HH:mm:ss Z", "EEE, dd MMM yyyy HH:mm:ss z",
|
||||||
|
"dd MMM yyyy HH:mm:ss z", "EEE, dd MMM yy HH:mm:ss z",
|
||||||
|
"dd MMM yy HH:mm:ss z" };
|
||||||
|
|
||||||
/** RFC 3339 date format for UTC dates. */
|
/** RFC 3339 date format for UTC dates. */
|
||||||
public static final String RFC3339UTC = "yyyy-MM-dd'T'HH:mm:ss'Z'";
|
public static final String RFC3339UTC = "yyyy-MM-dd'T'HH:mm:ss'Z'";
|
||||||
@ -23,7 +26,7 @@ public class SyndDateUtils {
|
|||||||
private static ThreadLocal<SimpleDateFormat> RFC822Formatter = new ThreadLocal<SimpleDateFormat>() {
|
private static ThreadLocal<SimpleDateFormat> RFC822Formatter = new ThreadLocal<SimpleDateFormat>() {
|
||||||
@Override
|
@Override
|
||||||
protected SimpleDateFormat initialValue() {
|
protected SimpleDateFormat initialValue() {
|
||||||
return new SimpleDateFormat(RFC822DAY, Locale.US);
|
return new SimpleDateFormat(RFC822DATES[0], Locale.US);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -36,23 +39,23 @@ public class SyndDateUtils {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public static Date parseRFC822Date(final String date) {
|
public static Date parseRFC822Date(String date) {
|
||||||
Date result = null;
|
Date result = null;
|
||||||
|
if (date.contains("PDT")) {
|
||||||
|
date = date.replace("PDT", "PST8PDT");
|
||||||
|
}
|
||||||
SimpleDateFormat format = RFC822Formatter.get();
|
SimpleDateFormat format = RFC822Formatter.get();
|
||||||
try {
|
for (int i = 0; i < RFC822DATES.length; i++) {
|
||||||
result = format.parse(date);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
format.applyPattern(RFC822);
|
|
||||||
try {
|
try {
|
||||||
result = format.parse(date);
|
result = format.parse(date);
|
||||||
} catch (ParseException e1) {
|
break;
|
||||||
e1.printStackTrace();
|
} catch (ParseException e) {
|
||||||
Log.e(TAG, "Unable to parse feed date correctly");
|
e.printStackTrace();
|
||||||
} finally {
|
|
||||||
format.applyPattern(RFC822DAY); // apply old pattern again
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (result == null) {
|
||||||
|
Log.e(TAG, "Unable to parse feed date correctly");
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -90,7 +93,11 @@ public class SyndDateUtils {
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
/** Takes a string of the form [HH:]MM:SS[.mmm] and converts it to milliseconds. */
|
|
||||||
|
/**
|
||||||
|
* Takes a string of the form [HH:]MM:SS[.mmm] and converts it to
|
||||||
|
* milliseconds.
|
||||||
|
*/
|
||||||
public static long parseTimeString(final String time) {
|
public static long parseTimeString(final String time) {
|
||||||
String[] parts = time.split(":");
|
String[] parts = time.split(":");
|
||||||
long result = 0;
|
long result = 0;
|
||||||
@ -102,7 +109,7 @@ public class SyndDateUtils {
|
|||||||
}
|
}
|
||||||
result += Integer.valueOf(parts[idx]) * 60000;
|
result += Integer.valueOf(parts[idx]) * 60000;
|
||||||
idx++;
|
idx++;
|
||||||
result += ( Float.valueOf(parts[idx])) * 1000;
|
result += (Float.valueOf(parts[idx])) * 1000;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,35 @@
|
|||||||
package de.danoeh.antennapod.util;
|
package de.danoeh.antennapod.util;
|
||||||
|
|
||||||
import de.danoeh.antennapod.R;
|
|
||||||
import android.app.DownloadManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import de.danoeh.antennapod.R;
|
||||||
|
|
||||||
/** Utility class for Download Errors. */
|
/** Utility class for Download Errors. */
|
||||||
public class DownloadError {
|
public class DownloadError {
|
||||||
public static final int ERROR_PARSER_EXCEPTION = 1;
|
public static final int ERROR_PARSER_EXCEPTION = 1;
|
||||||
public static final int ERROR_UNSUPPORTED_TYPE = 2;
|
public static final int ERROR_UNSUPPORTED_TYPE = 2;
|
||||||
public static final int ERROR_CONNECTION_ERROR = 3;
|
public static final int ERROR_CONNECTION_ERROR = 3;
|
||||||
|
public static final int ERROR_MALFORMED_URL = 4;
|
||||||
|
public static final int ERROR_IO_ERROR = 5;
|
||||||
|
public static final int ERROR_FILE_EXISTS = 6;
|
||||||
|
public static final int ERROR_DOWNLOAD_CANCELLED = 7;
|
||||||
|
public static final int ERROR_DEVICE_NOT_FOUND = 8;
|
||||||
|
public static final int ERROR_HTTP_DATA_ERROR = 9;
|
||||||
|
public static final int ERROR_NOT_ENOUGH_SPACE = 10;
|
||||||
|
|
||||||
/** Get a human-readable string for a specific error code. */
|
/** Get a human-readable string for a specific error code. */
|
||||||
public static String getErrorString(Context context, int code) {
|
public static String getErrorString(Context context, int code) {
|
||||||
int resId;
|
int resId;
|
||||||
switch(code) {
|
switch(code) {
|
||||||
case DownloadManager.ERROR_DEVICE_NOT_FOUND:
|
case ERROR_NOT_ENOUGH_SPACE:
|
||||||
resId = R.string.download_error_insufficient_space;
|
resId = R.string.download_error_insufficient_space;
|
||||||
break;
|
break;
|
||||||
case DownloadManager.ERROR_FILE_ERROR:
|
case ERROR_DEVICE_NOT_FOUND:
|
||||||
resId = R.string.download_error_file_error;
|
resId = R.string.download_error_device_not_found;
|
||||||
break;
|
break;
|
||||||
case DownloadManager.ERROR_HTTP_DATA_ERROR:
|
case ERROR_IO_ERROR:
|
||||||
|
resId = R.string.download_error_io_error;
|
||||||
|
break;
|
||||||
|
case ERROR_HTTP_DATA_ERROR:
|
||||||
resId = R.string.download_error_http_data_error;
|
resId = R.string.download_error_http_data_error;
|
||||||
break;
|
break;
|
||||||
case ERROR_PARSER_EXCEPTION:
|
case ERROR_PARSER_EXCEPTION:
|
||||||
|
@ -4,6 +4,7 @@ import de.danoeh.antennapod.activity.StorageErrorActivity;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.os.StatFs;
|
||||||
|
|
||||||
/** Utility functions for handling storage errors */
|
/** Utility functions for handling storage errors */
|
||||||
public class StorageUtils {
|
public class StorageUtils {
|
||||||
@ -25,4 +26,14 @@ public class StorageUtils {
|
|||||||
}
|
}
|
||||||
return storageAvailable;
|
return storageAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get the number of free bytes that are available on the external storage. */
|
||||||
|
public static int getFreeSpaceAvailable() {
|
||||||
|
StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
|
||||||
|
return stat.getAvailableBlocks() * stat.getBlockSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean externalStorageMounted() {
|
||||||
|
return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,8 +81,7 @@ public class FeedItemMenuHandler {
|
|||||||
manager.deleteFeedMedia(context, selectedItem.getMedia());
|
manager.deleteFeedMedia(context, selectedItem.getMedia());
|
||||||
break;
|
break;
|
||||||
case R.id.cancel_download_item:
|
case R.id.cancel_download_item:
|
||||||
requester.cancelDownload(context, selectedItem.getMedia()
|
requester.cancelDownload(context, selectedItem.getMedia());
|
||||||
.getDownloadId());
|
|
||||||
break;
|
break;
|
||||||
case R.id.mark_read_item:
|
case R.id.mark_read_item:
|
||||||
manager.markItemRead(context, selectedItem, true);
|
manager.markItemRead(context, selectedItem, true);
|
||||||
|
@ -15,7 +15,7 @@ import de.danoeh.antennapod.asynctask.FlattrClickWorker;
|
|||||||
import de.danoeh.antennapod.feed.Feed;
|
import de.danoeh.antennapod.feed.Feed;
|
||||||
import de.danoeh.antennapod.feed.FeedItem;
|
import de.danoeh.antennapod.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.feed.FeedManager;
|
import de.danoeh.antennapod.feed.FeedManager;
|
||||||
import de.danoeh.antennapod.service.DownloadService;
|
import de.danoeh.antennapod.service.download.DownloadService;
|
||||||
import de.danoeh.antennapod.storage.DownloadRequester;
|
import de.danoeh.antennapod.storage.DownloadRequester;
|
||||||
import de.danoeh.antennapod.util.ShareUtils;
|
import de.danoeh.antennapod.util.ShareUtils;
|
||||||
import de.danoeh.antennapod.AppConfig;
|
import de.danoeh.antennapod.AppConfig;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user