Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import android.Manifest;
- import android.app.IntentService;
- import android.content.Intent;
- import android.content.Context;
- import android.content.pm.PackageManager;
- import android.os.AsyncTask;
- import android.os.Environment;
- import android.os.StatFs;
- import android.support.annotation.NonNull;
- import android.support.v4.content.ContextCompat;
- import android.util.Log;
- import android.widget.Toast;
- import java.io.File;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.Iterator;
- import java.util.List;
- import io.realm.Realm;
- import io.realm.RealmResults;
- import io.realm.Sort;
- /**
- * An {@link IntentService} subclass for handling asynchronous task requests in
- * a service on a separate handler thread.
- * <p>
- * TODO: Customize class - update intent actions, extra parameters and static
- * helper methods.
- */
- public class DownloadIntentService extends IntentService {
- // TODO: Rename actions, choose action names that describe tasks that this
- // IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
- private static final String ACTION_DOWNLOAD = "com.vibhinna.sreni.action.ADD_DOWNLOAD";
- private static final String ACTION_PAUSE_DOWNLOAD = "com.vibhinna.sreni.action.PAUSE_DOWNLOAD";
- // TODO: Rename parameters
- private static final String EXTRA_ID = "com.vibhinna.sreni.extra.ID";
- private static final String EXTRA_URL = "com.vibhinna.sreni.extra.URL";
- private static final String EXTRA_TITLE = "com.vibhinna.sreni.extra.TITLE";
- private static final String EXTRA_VIDEO_ID = "com.vibhinna.sreni.extra.VIDEO_ID";
- private static final String EXTRA_FORMAT_ID = "com.vibhinna.sreni.extra.FORMAT_ID";
- private static final String EXTRA_EXTENSION = "com.vibhinna.sreni.extra.EXTENSION";
- private static final String EXTRA_THUMBNAIL = "com.vibhinna.sreni.extra.THUMBNAIL";
- private static final String EXTRA_PARAM2 = "com.vibhinna.sreni.extra.PARAM2";
- private static final int QUEUE_SIZE = 3;
- private static final String TAG = "DownloadIntentService";
- private final List<Downloader> downloadQueue
- = Collections.synchronizedList(new ArrayList<Downloader>());
- public DownloadIntentService() {
- super(TAG);
- }
- /**
- * Starts this service to perform action Foo with the given parameters. If
- * the service is already performing a task this action will be queued.
- *
- * @see IntentService
- */
- public static void addActionDownload(Context context,
- String id,
- String url,
- String title,
- String videoId,
- String formatId,
- String extension,
- String thumbnail) {
- Intent intent = new Intent(context, DownloadIntentService.class);
- intent.setAction(ACTION_DOWNLOAD);
- intent.putExtra(EXTRA_ID, id);
- intent.putExtra(EXTRA_URL, url);
- intent.putExtra(EXTRA_TITLE, title);
- intent.putExtra(EXTRA_VIDEO_ID, videoId);
- intent.putExtra(EXTRA_FORMAT_ID, formatId);
- intent.putExtra(EXTRA_EXTENSION, extension);
- intent.putExtra(EXTRA_THUMBNAIL, thumbnail);
- context.startService(intent);
- }
- public static void startActionPauseDownload(Context context, String... ids) {
- Intent intent = new Intent(context, DownloadIntentService.class);
- intent.setAction(ACTION_PAUSE_DOWNLOAD);
- intent.putExtra(EXTRA_ID, ids);
- context.startService(intent);
- }
- @Override
- protected void onHandleIntent(Intent intent) {
- if (intent != null) {
- final String action = intent.getAction();
- if (ACTION_DOWNLOAD.equals(action)) {
- final String id = intent.getStringExtra(EXTRA_ID);
- final String url = intent.getStringExtra(EXTRA_URL);
- final String title = intent.getStringExtra(EXTRA_TITLE);
- final String videoId = intent.getStringExtra(EXTRA_VIDEO_ID);
- final String formatId = intent.getStringExtra(EXTRA_FORMAT_ID);
- final String extension = intent.getStringExtra(EXTRA_EXTENSION);
- final String thumb = intent.getStringExtra(EXTRA_THUMBNAIL);
- handleActionAddDownload(id, url, title, videoId, formatId, extension, thumb);
- } else if (ACTION_PAUSE_DOWNLOAD.equals(action)) {
- final String[] ids = intent.getStringArrayExtra(EXTRA_ID);
- handleActionBaz(ids);
- }
- }
- }
- /**
- * Handle action Foo in the provided background thread with the provided
- * parameters.
- */
- private void handleActionAddDownload(final String id,
- final String url,
- final String title,
- final String videoId,
- final String formatId,
- final String extension,
- final String thumb) {
- Realm realm = Realm.getDefaultInstance();
- final RealmResults<Download> resultSet = realm
- .where(Download.class)
- .findAll()
- .sort("position", Sort.DESCENDING);
- final Download old = Utils.getDownloadById(realm, id);
- if (old != null && old.getDestination() != null) {
- // There's and old record with same id.
- File oldFile = new File(old.getDestination());
- if (oldFile.exists() && old.getStatus() == Download.DONE
- && oldFile.length() != old.getLength()) {
- // The old download isn't complete.
- if (oldFile.length() > 0 && oldFile.length() < old.getLength()) {
- // Partly downloaded?
- Log.d(TAG, "handleActionAddDownload: Detected partly downloaded file: "
- + oldFile.getAbsolutePath());
- } else {
- if (oldFile.exists()) {
- // Bigger than remote file. Shouldn't happen. Try to delete.
- Log.d(TAG, "handleActionAddDownload: Deleting corrupted download: "
- + oldFile.getAbsolutePath());
- if (!oldFile.delete())
- Log.e(TAG, "handleActionAddDownload: " +
- "Couldn't delete corrupted download: "
- + oldFile.getAbsolutePath());;
- } else {
- Log.d(TAG, "handleActionAddDownload: Missing download: "
- + oldFile.getAbsolutePath());
- }
- }
- } else if (oldFile.exists()){
- Log.w(TAG, "handleActionAddDownload: download is probably complete. Cancelling!");
- // TODO: 24/8/16 Download is probably complete.
- // TODO Show a dialog perhaps for a force download option?
- return;
- }
- }
- realm.executeTransaction(new Realm.Transaction() {
- @Override
- public void execute(Realm realm) {
- Download download = new Download(id);
- download.setUrl(url);
- // TODO: 24/8/16 This should occur in the UI.
- if (old == null || (old.getDestination() == null)) {
- // Try to download to old location. We don't need it probably.
- download.setDestination(Environment.getExternalStorageDirectory()
- + "/Download/" + Utils.toValidFileName(title) + "." + id
- + "." + extension);
- }
- download.setTitle(title);
- download.setVideoId(videoId);
- download.setFormatId(formatId);
- download.setExtension(extension);
- download.setThumbnail(thumb);
- long position = 0;
- if (resultSet.size() > 0) {
- position = resultSet.get(0).getPosition() + 1;
- }
- download.setPosition(position);
- Log.d(TAG, "execute: " + download.toString());
- realm.copyToRealmOrUpdate(download);
- }
- });
- resumeDownload(id);
- realm.close();
- }
- /**
- * Takes a download id, adds it to the queue if possible and resumes the download.
- *
- * @param id The id.
- */
- private void resumeDownload(String id) {
- //noinspection StatementWithEmptyBody
- if (isQueueOpen()) {
- // URL already exists, try to resume it.
- // FIXME: 21/8/16
- if (!isInQueue(id)) {
- synchronized (downloadQueue) {
- downloadQueue.add(new Downloader(id));
- }
- } else {
- // Download is already there in the queue. Multiple clicks?
- Log.e(TAG, "resumeDownload: Download is already there in the queue. " +
- "Multiple clicks?");
- }
- if (!ensureSdCard()) {
- Log.e(TAG, "resumeDownload: " + "Cannot ensure sdcard" );
- Toast.makeText(this, R.string.sd_not_available,
- Toast.LENGTH_LONG).show();
- return;
- }
- checkDownloadQueue();
- } else {
- // do nothing.
- }
- }
- private boolean ensureSdCard() {
- if (!(ContextCompat.checkSelfPermission(this,
- Manifest.permission.WRITE_EXTERNAL_STORAGE)
- == PackageManager.PERMISSION_GRANTED)) {
- Log.e(TAG, "ensureSdCard: no sdcard write permission!");
- return false;
- }
- if (!(ContextCompat.checkSelfPermission(this,
- Manifest.permission.READ_EXTERNAL_STORAGE)
- == PackageManager.PERMISSION_GRANTED)) {
- Log.e(TAG, "ensureSdCard: no sdcard read permission!");
- return false;
- }
- if (!(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))) {
- Log.e(TAG, "ensureSdCard: sdcard not mounted!");
- return false;
- }
- StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
- double sdAvailSize = (double)stat.getAvailableBlocks()
- * (double)stat.getBlockSize();
- double mbAvailable = sdAvailSize / (1024 * 1024);
- if (mbAvailable < 256) {
- Log.e(TAG, "ensureSdCard: sdcard is running out of space!");
- return false;
- }
- return true;
- }
- /**
- * Check the database and clean queue, add downloads to queue if possible, start downloads in
- * queue if not already started.
- */
- private void checkDownloadQueue() {
- Realm realm = Realm.getDefaultInstance();
- // Clean queue
- synchronized (downloadQueue) {
- for (Iterator<Downloader> it = downloadQueue.iterator(); it.hasNext();) {
- Downloader downloader = it.next();
- final Download download = Utils.getDownloadById(realm, downloader.getId());
- switch (download.getStatus()) {
- case Download.DONE:
- case Download.FAILED:
- case Download.PAUSED:
- // Remove processed downloads
- if (!downloader.isCancelled()) {
- downloader.cancel(true);
- }
- downloadQueue.remove(downloader);
- break;
- case Download.WAITING_FOR_QUEUE:
- // Start pending downloads.
- realm.executeTransaction(new Realm.Transaction() {
- @Override
- public void execute(Realm realm) {
- download.setStatus(Download.DOWNLOADING);
- realm.copyToRealmOrUpdate(download);
- }
- });
- startDownloaderInQueue(downloader.getId());
- break;
- case Download.DOWNLOADING:
- if (downloader.getStatus().equals(AsyncTask.Status.PENDING)) {
- startDownloaderInQueue(downloader.getId());
- } else if (downloader.getStatus().equals(AsyncTask.Status.FINISHED)) {
- if (!downloader.isCancelled()) {
- downloader.cancel(true);
- }
- realm.executeTransaction(new Realm.Transaction() {
- @Override
- public void execute(Realm realm) {
- download.setStatus(Download.FAILED);
- realm.copyToRealmOrUpdate(download);
- }
- });
- downloadQueue.remove(downloader);
- } else {
- // Do nothing, task is running.
- }
- break;
- }
- }
- // Add new downloads to queue if any.
- if (isQueueOpen()) {
- int diff = QUEUE_SIZE - downloadQueue.size();
- RealmResults<Download> downloads = realm
- .where(Download.class)
- .findAll()
- .sort("position", Sort.ASCENDING);
- for (int i = 0; (diff > 0 && i < downloads.size()); i++) {
- final Download download = downloads.get(i);
- if (download.getStatus() == Download.WAITING_FOR_QUEUE) {
- realm.executeTransaction(new Realm.Transaction() {
- @Override
- public void execute(Realm realm) {
- download.setStatus(Download.DOWNLOADING);
- realm.copyToRealmOrUpdate(download);
- }
- });
- Downloader downloader = new Downloader(download.getId());
- downloadQueue.add(downloader);
- startDownloaderInQueue(download.getId());
- diff--;
- } else if (download.getStatus() == Download.DOWNLOADING) {
- if (isInQueue(download.getId())) {
- Downloader downloader = new Downloader(download.getId());
- downloadQueue.add(downloader);
- startDownloaderInQueue(download.getId());
- diff--;
- }
- }
- }
- }
- }
- realm.close();
- }
- /**
- * Start a download in queue
- *
- * @param id an id that exists in download queue.
- */
- private void startDownloaderInQueue(@NonNull String id) {
- if (!isInQueue(id)) throw new IllegalArgumentException("URL is not in queue");
- Downloader downloader = getDownloaderFromQueue(id);
- Log.d(TAG, "startDownloaderInQueue: " + downloader.getStatus());
- if (AsyncTask.Status.PENDING.equals(downloader.getStatus())) {
- downloader.execute();
- } else if (AsyncTask.Status.FINISHED.equals(downloader.getStatus())) {
- throw new IllegalStateException("Downloader already executed");
- }
- }
- private Downloader getDownloaderFromQueue(String id) {
- synchronized (downloadQueue) {
- for (Downloader downloader : downloadQueue) {
- if (id.equals(downloader.getId())) return downloader;
- }
- }
- throw new IllegalArgumentException(id + "wasn't found in queue.");
- }
- /**
- * Check if a url is in the queue.
- *
- * @param id The id.
- * @return weather a id is in the queue or not.
- */
- private boolean isInQueue(@NonNull String id) {
- synchronized (downloadQueue) {
- for (Downloader downloader : downloadQueue) {
- if (id.equals(downloader.getId()))
- return true;
- }
- }
- return false;
- }
- private boolean isQueueOpen() {
- synchronized (downloadQueue) {
- return downloadQueue.size() < QUEUE_SIZE;
- }
- }
- /**
- * Handle action Baz in the provided background thread with the provided
- * parameters.
- */
- private void handleActionBaz(String... ids) {
- Realm realm = Realm.getDefaultInstance();
- for (String id : ids) {
- Download download = Utils.getDownloadById(realm, id);
- download.setStatus(Download.PAUSED);
- }
- checkDownloadQueue();
- realm.close();
- }
- private class Downloader extends BaseDownloader {
- public Downloader(String id) {
- super(id);
- }
- @Override
- protected void onPostExecute(final Integer status) {
- super.onPostExecute(status);
- Realm realm = Realm.getDefaultInstance();
- final Download download = Utils.getDownloadById(realm, getId());
- realm.executeTransaction(new Realm.Transaction() {
- @Override
- public void execute(Realm realm) {
- download.setStatus(status);
- realm.copyToRealmOrUpdate(download);
- }
- });
- realm.close();
- checkDownloadQueue();
- }
- @Override
- protected void onProgressUpdate(DownloadProgress... values) {
- super.onProgressUpdate(values);
- Realm realm = Realm.getDefaultInstance();
- final DownloadProgress progress = values[0];
- final Download download = Utils.getDownloadById(realm, getId());
- Log.d(TAG, "onProgressUpdate: " + progress);
- realm.executeTransaction(new Realm.Transaction() {
- @Override
- public void execute(Realm realm) {
- download.updateProgress(progress);
- realm.copyToRealmOrUpdate(download);
- }
- });
- realm.close();
- }
- }
- }
Add Comment
Please, Sign In to add comment