Java tutorial
/* 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); } }