de.qspool.clementineremote.backend.downloader.DownloadManager.java Source code

Java tutorial

Introduction

Here is the source code for de.qspool.clementineremote.backend.downloader.DownloadManager.java

Source

/* This file is part of the Android Clementine Remote.
 * Copyright (C) 2013, Andreas Muttscheller <asfa194@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package de.qspool.clementineremote.backend.downloader;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.TaskStackBuilder;
import android.util.SparseArray;
import android.widget.Toast;

import java.io.File;
import java.util.LinkedList;
import java.util.List;

import de.qspool.clementineremote.R;
import de.qspool.clementineremote.SharedPreferencesKeys;
import de.qspool.clementineremote.backend.elements.DownloaderResult;
import de.qspool.clementineremote.backend.mediasession.ClementineMediaSessionNotification;
import de.qspool.clementineremote.backend.pb.ClementineMessage;
import de.qspool.clementineremote.ui.MainActivity;

public class DownloadManager {

    public final static int NOTIFICATION_ID_DOWNLOADS = 129312;

    public final static int NOTIFICATION_ID_DOWNLOADS_FINISHED = 129313;

    private Context mContext;

    private NotificationManager mNotifyManager;

    private NotificationCompat.Builder mActiveNofiticationBuilder;

    private SparseArray<ClementineSongDownloader> mActiveDownloads = new SparseArray<>();

    private SparseArray<ClementineSongDownloader> mFinishedDownloads = new SparseArray<>();

    private int mIds;

    private SharedPreferences mSharedPref;

    private static DownloadManager instance;

    public static DownloadManager getInstance() {
        if (instance == null) {
            throw new IllegalStateException(
                    "No DownloadManager instance found. Use getInstance(Context) to create one");
        }
        return DownloadManager.instance;
    }

    public static DownloadManager getInstance(Context context) {
        if (instance == null) {
            instance = new DownloadManager(context);
        }
        return instance;
    }

    private DownloadManager(Context context) {
        mContext = context;
        mNotifyManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);

        createNewActiveNotification();
    }

    @SuppressLint("InlinedApi")
    private void createNewActiveNotification() {
        mActiveNofiticationBuilder = new NotificationCompat.Builder(mContext)
                .setContentTitle(mContext.getString(R.string.download_noti_title))
                .setSmallIcon(R.drawable.ic_launcher).setOngoing(true)
                .setVisibility(Notification.VISIBILITY_PUBLIC);

        // Set the result intent
        mActiveNofiticationBuilder.setContentIntent(buildNotificationIntent());

        mActiveNofiticationBuilder.setPriority(NotificationCompat.PRIORITY_LOW);
    }

    private PendingIntent buildNotificationIntent() {
        Intent intent = new Intent(mContext, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        intent.putExtra(ClementineMediaSessionNotification.EXTRA_NOTIFICATION_ID, NOTIFICATION_ID_DOWNLOADS);

        // Create a TaskStack, so the app navigates correctly backwards
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(mContext);
        stackBuilder.addParentStack(MainActivity.class);
        stackBuilder.addNextIntent(intent);
        return stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    public boolean addJob(ClementineMessage clementineMessage) {
        ClementineSongDownloader songDownloader = new ClementineSongDownloader();
        songDownloader.setId(mIds);
        songDownloader.setSongDownloaderListener(new SongDownloaderListener() {

            @Override
            public void onProgress(DownloadStatus progress) {
                DownloadManager.this.onProgress(progress);
            }

            @SuppressLint("InlinedApi")
            @Override
            public void onDownloadResult(DownloaderResult result) {
                int id = result.getId();

                // Move the download to the finished list
                mFinishedDownloads.append(id, mActiveDownloads.get(id));
                mActiveDownloads.remove(id);

                // Remove the notification if this was the last download
                if (mActiveDownloads.size() == 0) {
                    mNotifyManager.cancel(NOTIFICATION_ID_DOWNLOADS);
                } else {
                    // Build a new active notification as the old one might be
                    // expanded and looks now strange
                    createNewActiveNotification();
                }

                //download_noti_n_finished
                String title = mContext.getResources().getQuantityString(R.plurals.download_noti_n_finished,
                        mFinishedDownloads.size(), mFinishedDownloads.size());
                NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mContext)
                        .setContentTitle(title).setContentText(mContext.getString(result.getMessageStringId()))
                        .setSmallIcon(R.drawable.ic_launcher).setPriority(NotificationCompat.PRIORITY_MIN)
                        .setAutoCancel(true).setContentIntent(buildNotificationIntent())
                        .setVisibility(Notification.VISIBILITY_PUBLIC);

                // Displays the progress bar for the first time.
                mNotifyManager.notify(NOTIFICATION_ID_DOWNLOADS_FINISHED, notificationBuilder.build());
            }
        });

        mSharedPref = PreferenceManager.getDefaultSharedPreferences(mContext);

        // Get preferences and set download settings
        String defaultPath;
        if (mContext.getExternalFilesDir(Environment.DIRECTORY_MUSIC) == null
                && !mSharedPref.contains(SharedPreferencesKeys.SP_DOWNLOAD_DIR)) {
            Toast.makeText(mContext, R.string.download_noti_not_mounted, Toast.LENGTH_LONG).show();
            return false;
        } else {
            File defaultFile = mContext.getExternalFilesDir(Environment.DIRECTORY_MUSIC);
            if (defaultFile != null)
                defaultPath = defaultFile.getAbsolutePath();
            else
                defaultPath = "";
        }

        songDownloader.setDownloadPath(mSharedPref.getString(SharedPreferencesKeys.SP_DOWNLOAD_DIR, defaultPath));
        songDownloader.setDownloadOnWifiOnly(mSharedPref.getBoolean(SharedPreferencesKeys.SP_WIFI_ONLY, false));
        songDownloader.setCreatePlaylistDir(
                mSharedPref.getBoolean(SharedPreferencesKeys.SP_DOWNLOAD_SAVE_OWN_DIR, false));
        songDownloader.setCreateArtistDir(
                mSharedPref.getBoolean(SharedPreferencesKeys.SP_DOWNLOAD_PLAYLIST_CRT_ARTIST_DIR, true));
        songDownloader.setCreateAlbumDir(
                mSharedPref.getBoolean(SharedPreferencesKeys.SP_DOWNLOAD_PLAYLIST_CRT_ALBUM_DIR, true));
        songDownloader.setOverrideExistingFiles(
                mSharedPref.getBoolean(SharedPreferencesKeys.SP_DOWNLOAD_OVERRIDE, false));

        // Show a toast that the download is starting
        Toast.makeText(mContext, R.string.player_download_started, Toast.LENGTH_SHORT).show();

        mActiveDownloads.append(mIds, songDownloader);

        mIds++;

        songDownloader.startDownload(clementineMessage);

        return true;
    }

    public List<ClementineSongDownloader> getAllDownloaders() {
        LinkedList<ClementineSongDownloader> downloaders = new LinkedList<>();

        for (int i = 0; i < mActiveDownloads.size(); ++i) {
            downloaders.add(mActiveDownloads.valueAt(i));
        }
        for (int i = 0; i < mFinishedDownloads.size(); ++i) {
            downloaders.add(mFinishedDownloads.valueAt(i));
        }

        return downloaders;
    }

    public void removeDownloader(int id) {
        mActiveDownloads.remove(id);
        mFinishedDownloads.remove(id);
    }

    public void shutdown() {
        for (int i = 0; i < mActiveDownloads.size(); ++i) {
            mActiveDownloads.valueAt(i).cancel(true);
        }

        mNotifyManager.cancel(NOTIFICATION_ID_DOWNLOADS);
        mNotifyManager.cancel(NOTIFICATION_ID_DOWNLOADS_FINISHED);
    }

    public String getTitleForItem(ClementineSongDownloader downloader) {
        DownloadStatus status = downloader.getDownloadStatus();

        StringBuilder sb = new StringBuilder();

        switch (status.getState()) {
        case IDLE:
            sb.append(mContext.getString(R.string.download_noti_title));
            break;
        case TRANSCODING:
            sb.append(mContext.getString(R.string.download_noti_transcoding));
            break;
        case DOWNLOADING:
        case FINISHED:
            switch (downloader.getItem()) {
            case APlaylist:
                sb.append(mContext.getString(R.string.download_noti_title_playlist));
                sb.append(" ");
                sb.append(downloader.getPlaylistName());
                break;
            case CurrentItem:
                sb.append(mContext.getString(R.string.download_noti_title_song));
                sb.append(" ");
                sb.append(status.getSong().getTitle());
                break;
            case Urls:
                sb.append(mContext.getString(R.string.download_noti_title_songs));
                sb.append(" ");
                sb.append(status.getSong().getArtist());
                sb.append(" - ");
                sb.append(status.getSong().getTitle());
                break;
            case ItemAlbum:
                sb.append(mContext.getString(R.string.download_noti_title_album));
                sb.append(" ");
                sb.append(status.getSong().getAlbum());
                break;
            }
        }

        return sb.toString();
    }

    public String getSubtitleForItem(ClementineSongDownloader downloader) {
        DownloadStatus status = downloader.getDownloadStatus();

        StringBuilder sb = new StringBuilder();
        switch (status.getState()) {

        case IDLE:
            break;
        case TRANSCODING:
            sb.append("(");
            sb.append(status.getTranscodingFinished());
            sb.append("/");
            sb.append(status.getTranscodingTotal());
            sb.append(") ");
            sb.append(mContext.getString(R.string.download_noti_transcoding_subtitle));
            break;
        case DOWNLOADING:
            sb.append("(");
            sb.append(status.getCurrentFileIndex());
            sb.append("/");
            sb.append(status.getTotalFiles());
            sb.append(") ");
            sb.append(status.getSong().getArtist());
            sb.append(" - ");
            sb.append(status.getSong().getTitle());
            break;
        case FINISHED:
            sb.append("(");
            sb.append(status.getCurrentFileIndex());
            sb.append("/");
            sb.append(status.getTotalFiles());
            sb.append(") ");
            sb.append(mContext.getString(downloader.getDownloaderResult().getMessageStringId()));
            break;
        }
        return sb.toString();
    }

    private void onProgress(DownloadStatus status) {
        switch (status.getState()) {
        case IDLE:
            mActiveNofiticationBuilder.setContentTitle(mContext.getString(R.string.download_noti_title));
            mActiveNofiticationBuilder.setContentText(mContext.getString(R.string.connectdialog_connecting));
            break;
        case TRANSCODING:
        case DOWNLOADING:
            if (mActiveDownloads.size() == 1) {
                setNotificationSingleDownload(mActiveNofiticationBuilder, status);
            } else {
                setNotificationMultipleDownloads(mActiveNofiticationBuilder);
            }
            break;
        }

        // Displays the progress bar for the first time.
        mNotifyManager.notify(NOTIFICATION_ID_DOWNLOADS, mActiveNofiticationBuilder.build());
    }

    private void setNotificationSingleDownload(NotificationCompat.Builder notificationBuilder,
            DownloadStatus status) {
        ClementineSongDownloader downloader = mActiveDownloads.get(status.getId());

        notificationBuilder.setProgress(100, (int) status.getProgress(), false);

        // Notification Title
        notificationBuilder.setContentTitle(getTitleForItem(downloader));

        // Notification subtitle
        notificationBuilder.setContentText(getSubtitleForItem(downloader));
    }

    private void setNotificationMultipleDownloads(NotificationCompat.Builder notificationBuilder) {
        NotificationCompat.InboxStyle downloadItems = new NotificationCompat.InboxStyle();

        // Title
        String title = mContext.getResources().getQuantityString(R.plurals.download_noti_n_downloads,
                mActiveDownloads.size(), mActiveDownloads.size());
        notificationBuilder.setContentTitle(title);

        // Total progress in subtitle
        int progress = 0;
        for (int i = 0; i < mActiveDownloads.size(); ++i) {
            ClementineSongDownloader downloader = mActiveDownloads.valueAt(i);
            DownloadStatus status = downloader.getDownloadStatus();
            progress += status.getProgress();

            downloadItems.addLine(getTitleForItem(downloader));
        }

        String subtitle = mContext.getString(R.string.download_noti_n_progress);
        subtitle = subtitle.replace("%d", String.valueOf(progress / mActiveDownloads.size()));
        notificationBuilder.setContentText(subtitle);
        downloadItems.setBigContentTitle(subtitle); // Show the status on expanded notification

        notificationBuilder.setStyle(downloadItems);
        notificationBuilder.setProgress(0, 0, false);
    }
}