com.aniruddhc.acemusic.player.AsyncTasks.AsyncPinSongsTask.java Source code

Java tutorial

Introduction

Here is the source code for com.aniruddhc.acemusic.player.AsyncTasks.AsyncPinSongsTask.java

Source

/*
 * Copyright (C) 2014 Saravan Pantham
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.aniruddhc.acemusic.player.AsyncTasks;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;

import org.json.JSONException;

import android.app.NotificationManager;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;

import com.aniruddhc.acemusic.player.R;
import com.aniruddhc.acemusic.player.DBHelpers.DBAccessHelper;
import com.aniruddhc.acemusic.player.GMusicHelpers.GMusicClientCalls;
import com.aniruddhc.acemusic.player.Services.PinGMusicSongsService;
import com.aniruddhc.acemusic.player.Utils.Common;

public class AsyncPinSongsTask extends AsyncTask<String, Integer, Boolean> {

    private Context mContext;
    private Common mApp;
    private String mSaveLocation;
    private String mFileName;
    private int fileSize;
    private int currentDownloadedSize = 0;

    private ArrayList<String> songIdsList;
    private ArrayList<String> songTitlesList;
    private int i;

    //File size/unit dividers
    private static final long kiloBytes = 1024;
    private static final long megaBytes = kiloBytes * kiloBytes;
    private static final long gigaBytes = megaBytes * kiloBytes;
    private static final long teraBytes = gigaBytes * kiloBytes;

    public AsyncPinSongsTask(Context context) {

        //Context.
        mContext = context;
        songIdsList = new ArrayList<String>();
        songTitlesList = new ArrayList<String>();

        //If the cache storage directory for local copies doesn't exist, go ahead and create it.
        File cacheFolder = null;
        try {
            cacheFolder = new File(mContext.getCacheDir().getCanonicalPath() + "/music");
            if (!cacheFolder.exists()) {
                cacheFolder.mkdirs();
            }
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            Toast.makeText(mContext, R.string.download_failed_to_initialize, Toast.LENGTH_LONG).show();
            return;
        }

        mApp = (Common) mContext.getApplicationContext();
        try {
            mSaveLocation = cacheFolder.getCanonicalPath();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    protected void onPreExecute() {
        super.onPreExecute();

        //The initial notification will display a "Starting download" message + indeterminate progress bar.
        PinGMusicSongsService.mBuilder
                .setContentTitle(mContext.getResources().getString(R.string.starting_download));
        PinGMusicSongsService.mBuilder.setTicker(mContext.getResources().getString(R.string.starting_download));
        PinGMusicSongsService.mBuilder.setSmallIcon(R.drawable.pin_light);
        PinGMusicSongsService.mBuilder.setProgress(0, 0, true);

        PinGMusicSongsService.mNotifyManager.notify(PinGMusicSongsService.notificationID,
                PinGMusicSongsService.mBuilder.build());
    }

    @Override
    protected Boolean doInBackground(String... params) {

        //Iterate through the cursor and download/cache the requested songs.
        boolean getAllPinnedTracks = false;
        if (mApp.getPinnedSongsCursor() == null) {
            //The user asked to get all pinned songs from the official GMusic app.
            getAllPinnedTracks = true;

            //Check to make sure that the official GMusic app exists.
            PackageManager pm = mContext.getPackageManager();
            boolean installed = false;
            try {
                pm.getPackageInfo("com.google.android.music", PackageManager.GET_ACTIVITIES);
                installed = true;
            } catch (NameNotFoundException e1) {
                //The app isn't installed.
                installed = false;
            }

            if (installed == false) {
                //The app isn't installed. Notify the user.
                publishProgress(new Integer[] { 2 });
                return false;
            }

            //Query GMusic's content mApp for pinned songs.
            Uri googlePlayMusicContentProviderUri = Uri
                    .parse("content://com.google.android.music.MusicContent/audio");
            String[] projection = { "title", "TrackType AS track_type", "LocalCopyPath AS local_copy_path",
                    "SourceType AS source_type", "SourceId" };

            /* source_type values:
             * 0: Local file (not used).
             * 1: Unknown.
             * 2: Personal, free GMusic library (used).
             * 3: All Access (not used).
             */
            String selection = "source_type=2 AND track_type=0 AND local_copy_path<>''";
            mApp.setPinnedSongsCursor(mContext.getContentResolver().query(googlePlayMusicContentProviderUri,
                    projection, selection, null, null));

        }

        /* Load the cursor data into a temp ArrayList. If the app is closed, the cursor 
         * will also be closed, so we need to preserve it.
         */
        mApp.getPinnedSongsCursor().moveToPosition(-1);
        while (mApp.getPinnedSongsCursor().moveToNext()) {
            //Download the song only if it's from GMusic.
            if (getAllPinnedTracks || mApp.getPinnedSongsCursor()
                    .getString(mApp.getPinnedSongsCursor().getColumnIndex(DBAccessHelper.SONG_SOURCE))
                    .equals(DBAccessHelper.GMUSIC)) {

                //Retrieve the song ID of current song and set it as the file name.
                String songID = "";
                String songTitle = "";
                if (mApp.getPinnedSongsCursor().getColumnIndex("SourceId") != -1) {
                    songID = mApp.getPinnedSongsCursor()
                            .getString(mApp.getPinnedSongsCursor().getColumnIndex("SourceId"));

                    songTitle = mApp.getPinnedSongsCursor()
                            .getString(mApp.getPinnedSongsCursor().getColumnIndex("title"));
                } else {
                    songID = mApp.getPinnedSongsCursor()
                            .getString(mApp.getPinnedSongsCursor().getColumnIndex(DBAccessHelper.SONG_ID));

                    songTitle = mApp.getPinnedSongsCursor()
                            .getString(mApp.getPinnedSongsCursor().getColumnIndex(DBAccessHelper.SONG_TITLE));
                }

                songIdsList.add(songID);
                songTitlesList.add(songTitle);
            }

        }

        //Clear out Common's cursor.
        if (mApp.getPinnedSongsCursor() != null) {
            mApp.getPinnedSongsCursor().close();
            mApp.setPinnedSongsCursor(null);
        }

        //Iterate through the songs and download them.
        for (i = 0; i < songIdsList.size(); i++) {
            downloadSong(songIdsList.get(i));
        }

        return true;
    }

    public void downloadSong(String songID) {

        //Update the notification.
        publishProgress(new Integer[] { 1 });

        //Check if the file already exists. If so, skip it.
        File tempFile = new File(mSaveLocation + "/" + songID + ".mp3");

        if (tempFile.exists()) {
            tempFile = null;
            return;
        }

        tempFile = null;
        mFileName = songID + ".mp3";

        //Get the url for the song file using the songID.
        URL url = null;
        try {
            url = GMusicClientCalls.getSongStream(songID).toURL();
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return;
        } catch (JSONException e) {
            e.printStackTrace();
            return;
        } catch (URISyntaxException e) {
            e.printStackTrace();
            return;
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }

        try {
            //Download the file to the specified location.
            //Create a new connection to the server.
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

            //Set the request method of the connection.
            urlConnection.setRequestMethod("GET");
            urlConnection.setDoOutput(true);

            //Aaaand connect!
            urlConnection.connect();

            //Set the destination path of the file.
            File SDCardRoot = new File(mSaveLocation);

            //Create the destination file.
            File file = new File(SDCardRoot, mFileName);

            //We'll use this to write the downloaded data into the file we created
            FileOutputStream fileOutput = new FileOutputStream(file);

            //Aaand we'll use this to read the data from the server.
            InputStream inputStream = urlConnection.getInputStream();

            //Total size of the file.
            fileSize = urlConnection.getContentLength();

            //Specifies how much of the total size has been downloaded.
            currentDownloadedSize = 0;

            //Buffers galore!
            byte[] buffer = new byte[1024];
            int bufferLength = 0; //Used to store a temporary size of the buffer.
            int updateValue = 0;

            //Read through the input buffer and write the destination file, piece by piece.
            while ((bufferLength = inputStream.read(buffer)) > 0) {
                fileOutput.write(buffer, 0, bufferLength);
                currentDownloadedSize += bufferLength;
                updateValue = updateValue + 1;

                //Update the notification for every 100 iterations.
                if (updateValue == 100) {
                    publishProgress(new Integer[] { 0 });
                    updateValue = 0;
                }

            }

            try {
                //Close the output stream.
                fileOutput.close();
            } catch (Exception e) {
                e.printStackTrace();
            }

            //And we're done!
        } catch (MalformedURLException e) {
            return;
        } catch (IOException e) {
            return;
        } catch (Exception e) {
            return;
        }

        //Insert the file path of the local copy into the DB.
        ContentValues values = new ContentValues();
        String selection = DBAccessHelper.SONG_ID + "=" + "'" + songID + "'";

        String localCopyPath = null;
        try {
            localCopyPath = mContext.getCacheDir().getCanonicalPath() + "/music/" + mFileName;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        values.put(DBAccessHelper.LOCAL_COPY_PATH, localCopyPath);
        mApp.getDBAccessHelper().getWritableDatabase().update(DBAccessHelper.MUSIC_LIBRARY_TABLE, values, selection,
                null);

    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        int updateCode = values[0];
        switch (updateCode) {
        case 0:
            String currentProgressText = getFormattedFileSize((long) currentDownloadedSize) + " of "
                    + getFormattedFileSize((long) fileSize);

            PinGMusicSongsService.mBuilder.setTicker(null);
            PinGMusicSongsService.mBuilder.setProgress(fileSize, currentDownloadedSize, false);
            PinGMusicSongsService.mBuilder.setContentText(currentProgressText);
            PinGMusicSongsService.mNotifyManager.notify(PinGMusicSongsService.notificationID,
                    PinGMusicSongsService.mBuilder.build());
            break;
        case 1:
            if (i < songTitlesList.size()) {

                //Create the notification that displays the download progress of the song.
                String title = mContext.getResources().getString(R.string.downloading_no_dot) + " "
                        + songTitlesList.get(i);

                PinGMusicSongsService.mNotifyManager = (NotificationManager) mContext
                        .getSystemService(Context.NOTIFICATION_SERVICE);
                PinGMusicSongsService.mBuilder = new NotificationCompat.Builder(mContext);
                PinGMusicSongsService.mBuilder.setContentTitle(title);
                PinGMusicSongsService.mBuilder
                        .setContentText(mContext.getResources().getString(R.string.starting_download));
                PinGMusicSongsService.mBuilder.setSmallIcon(R.drawable.pin_light);
                PinGMusicSongsService.mBuilder.setProgress(0, 0, true);
                PinGMusicSongsService.mNotifyManager.notify(PinGMusicSongsService.notificationID,
                        PinGMusicSongsService.mBuilder.build());
            }
            break;
        case 2:
            Toast.makeText(mContext, R.string.gmusic_app_not_installed_pin, Toast.LENGTH_SHORT).show();
            break;
        }

    }

    public static String getFormattedFileSize(final long value) {

        final long[] dividers = new long[] { teraBytes, gigaBytes, megaBytes, kiloBytes, 1 };
        final String[] units = new String[] { "TB", "GB", "MB", "KB", "bytes" };

        if (value < 1) {
            return "";
        }

        String result = null;
        for (int i = 0; i < dividers.length; i++) {
            final long divider = dividers[i];
            if (value >= divider) {
                result = format(value, divider, units[i]);
                break;
            }

        }

        return result;
    }

    private static String format(final long value, final long divider, final String unit) {
        final double result = divider > 1 ? (double) value / (double) divider : (double) value;
        return new DecimalFormat("#,##0.#").format(result) + " " + unit;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
        PinGMusicSongsService.mBuilder.setProgress(0, 0, false);
        PinGMusicSongsService.mBuilder.setContentText("");
        PinGMusicSongsService.mBuilder
                .setContentTitle(mContext.getResources().getString(R.string.done_pinning_songs));
        PinGMusicSongsService.mNotifyManager.notify(PinGMusicSongsService.notificationID,
                PinGMusicSongsService.mBuilder.build());

        //Notify the user.
        if (mApp.isFetchingPinnedSongs() == true) {
            Toast.makeText(mContext, R.string.done_pinning_songs_from_gmusic, Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(mContext, R.string.done_pinning_songs, Toast.LENGTH_LONG).show();
        }

        songTitlesList.clear();
        songTitlesList = null;
        songIdsList.clear();
        songIdsList = null;

        mApp.setIsFetchingPinnedSongs(false);

        //Stop the service.
        mContext.stopService(new Intent(mContext, PinGMusicSongsService.class));

    }

}