package com.simplecity.amp_library.services;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.target.SimpleTarget;
import com.simplecity.amp_library.R;
import com.simplecity.amp_library.glide.loader.ArtworkModelLoader;
import com.simplecity.amp_library.model.ArtworkProvider;
import com.simplecity.amp_library.utils.DataManager;
import com.simplecity.amp_library.utils.ShuttleUtils;
import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;
/**
* A service which will download all artist & album artworkProvider, via an AsyncTask, and display the progress in a notification.
* The notification includes a 'cancel' button, and the AsyncTask & associated HttpRequests can be cancelled.
*/
public class ArtworkDownloadService extends Service {
private static final String TAG = "ArtworkDownloadService";
private static final String ACTION_CANCEL = "com.simplecity.shuttle.artwork_cancel";
private static final int NOTIFICATION_ID = 200;
private NotificationCompat.Builder notificationBuilder;
private NotificationManager notificationManager;
private int progress = 0;
private int max = 100;
private CompositeSubscription subscription;
@Override
public void onCreate() {
super.onCreate();
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
final ComponentName serviceName = new ComponentName(this, ArtworkDownloadService.class);
Intent intent = new Intent(ACTION_CANCEL);
intent.setComponent(serviceName);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
notificationBuilder = new NotificationCompat.Builder(this)
.setContentTitle(getResources().getString(R.string.notif_downloading_art))
.setSmallIcon(android.R.drawable.stat_sys_download)
.setOngoing(true)
.setProgress(100, 0, true)
.addAction(new NotificationCompat.Action(R.drawable.ic_action_navigation_close, getString(R.string.cancel), pendingIntent));
if (!ShuttleUtils.isOnline(false)) {
Toast toast = Toast.makeText(this, getResources().getString(R.string.connection_unavailable), Toast.LENGTH_SHORT);
toast.show();
stopSelf();
return;
}
if (notificationBuilder != null) {
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
subscription = new CompositeSubscription();
Observable<List<ArtworkProvider>> sharedItemsObservable = DataManager.getInstance()
.getAlbumArtistsRelay()
.first()
.<ArtworkProvider>flatMap(Observable::from)
.mergeWith(DataManager.getInstance().getAlbumsRelay()
.first()
.flatMap(Observable::from))
.toList()
.share();
subscription.add(sharedItemsObservable
.observeOn(AndroidSchedulers.mainThread())
.subscribe(list -> {
max = list.size();
updateProgress();
}));
subscription.add(sharedItemsObservable.flatMap(Observable::from)
.flatMap(artworkProvider -> Observable.just(artworkProvider)
.subscribeOn(Schedulers.computation())
.map(artwork -> {
FutureTarget<File> futureTarget = Glide.with(ArtworkDownloadService.this)
.using(new ArtworkModelLoader(true), InputStream.class)
.load(artwork)
.as(InputStream.class)
.downloadOnly(SimpleTarget.SIZE_ORIGINAL, SimpleTarget.SIZE_ORIGINAL);
try {
futureTarget.get(30, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Log.e(TAG, "Error downloading artworkProvider: " + e);
}
Glide.clear(futureTarget);
return null;
}))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(item -> {
updateProgress();
}));
}
@Override
public void onTaskRemoved(Intent rootIntent) {
// Some users like to crash the entire app and then wonder why the service stop working.
// If they remove the task, shut everything down.
stopSelf();
super.onTaskRemoved(rootIntent);
}
@Override
public void onDestroy() {
if (subscription != null) {
subscription.unsubscribe();
}
notificationManager.cancel(NOTIFICATION_ID);
super.onDestroy();
}
/**
* Increments the progress count and updates the notification with the new value.
* If the progress is equal to (or greater) than our count, then this task is finished.
* The notification is dismissed and this service is stopped.
*/
private void updateProgress() {
progress++;
if (notificationBuilder != null) {
notificationBuilder.setProgress(max, progress, false);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
if (progress >= max) {
notificationManager.cancel(NOTIFICATION_ID);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
final String action = intent.getAction();
if (action != null && action.equals(ACTION_CANCEL)) {
//Handle a notification cancel action click:
subscription.unsubscribe();
notificationBuilder = null;
notificationManager.cancel(NOTIFICATION_ID);
stopSelf();
}
}
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
//Nothing to do.
return null;
}
}