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

Java tutorial

Introduction

Here is the source code for com.aniruddhc.acemusic.player.AsyncTasks.AsyncAutoGetAlbumArtTask.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.URL;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.audio.exceptions.CannotReadException;
import org.jaudiotagger.audio.exceptions.CannotWriteException;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.Tag;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.images.Artwork;
import org.jaudiotagger.tag.images.ArtworkFactory;

import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Environment;
import android.widget.Toast;

import com.aniruddhc.acemusic.player.R;
import com.aniruddhc.acemusic.player.DBHelpers.DBAccessHelper;
import com.aniruddhc.acemusic.player.Services.AutoFetchAlbumArtService;
import com.aniruddhc.acemusic.player.Utils.Common;

/*********************************************************************
 * This class is different from AsyncGetAlbumArtTask. It includes an 
 * additional search functionality that scans the ENTIRE library,
 * checks for missing art, and then downloads them.
 *********************************************************************/
public class AsyncAutoGetAlbumArtTask extends AsyncTask<String, String, Void> {

    private Context mContext;
    private Common mApp;
    private Activity mActivity;
    private SharedPreferences sharedPreferences;
    private AsyncTask<String, String, Void> task;
    private String artworkURL;
    private Bitmap artworkBitmap;
    private byte[] buffer;
    private AudioFile audioFile;
    private File file;
    private DBAccessHelper dbHelper;

    private ProgressDialog pd;
    private int currentProgress = 0;
    private boolean DIALOG_VISIBLE = true;

    public static ArrayList<String> dataURIsList = new ArrayList<String>();
    public static ArrayList<String> artistsList = new ArrayList<String>();
    public static ArrayList<String> albumsList = new ArrayList<String>();

    public AsyncAutoGetAlbumArtTask(Context context, Activity activity) {
        mContext = context;
        mApp = (Common) context.getApplicationContext();
        mActivity = activity;
        sharedPreferences = mContext.getSharedPreferences("com.aniruddhc.acemusic.player", Context.MODE_PRIVATE);
        task = this;
        dbHelper = new DBAccessHelper(mContext);
    }

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

        pd = new ProgressDialog(mActivity);
        pd.setTitle(R.string.downloading_album_art);
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        pd.setCancelable(false);
        pd.setCanceledOnTouchOutside(false);
        pd.setMessage(mContext.getResources().getString(R.string.scanning_for_missing_art));
        pd.setButton(DialogInterface.BUTTON_NEGATIVE, mContext.getResources().getString(R.string.cancel),
                new OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        task.cancel(true);

                    }

                });

        pd.show();

    }

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

        //First, we'll go through all the songs in the music library DB and get their attributes.
        dbHelper = new DBAccessHelper(mContext);
        String selection = DBAccessHelper.SONG_SOURCE + "<>" + "'GOOGLE_PLAY_MUSIC'";
        String[] projection = { DBAccessHelper._ID, DBAccessHelper.SONG_FILE_PATH, DBAccessHelper.SONG_ALBUM,
                DBAccessHelper.SONG_ARTIST, DBAccessHelper.SONG_TITLE };

        Cursor cursor = dbHelper.getWritableDatabase().query(DBAccessHelper.MUSIC_LIBRARY_TABLE, projection,
                selection, null, null, null, null);

        if (cursor.getCount() != 0) {

            cursor.moveToFirst();
            dataURIsList.add(cursor.getString(1));
            albumsList.add(cursor.getString(2));
            artistsList.add(cursor.getString(3));

            while (cursor.moveToNext()) {

                dataURIsList.add(cursor.getString(1));
                albumsList.add(cursor.getString(2));
                artistsList.add(cursor.getString(3));
            }

        } else {
            //The user doesn't have any music so let's get outta here.
            return null;
        }

        pd.setMax(dataURIsList.size());

        //Now that we have the attributes of the songs, we'll go through them each and check for missing covers.
        for (int i = 0; i < dataURIsList.size(); i++) {

            try {
                file = new File(dataURIsList.get(i));
            } catch (Exception e) {
                continue;
            }

            audioFile = null;
            try {
                audioFile = AudioFileIO.read(file);
            } catch (CannotReadException e2) {
                // TODO Auto-generated catch block
                continue;
            } catch (IOException e2) {
                // TODO Auto-generated catch block
                continue;
            } catch (TagException e2) {
                // TODO Auto-generated catch block
                continue;
            } catch (ReadOnlyFileException e2) {
                // TODO Auto-generated catch block
                continue;
            } catch (InvalidAudioFrameException e2) {
                // TODO Auto-generated catch block
                continue;
            }

            Tag tag = audioFile.getTag();

            //Set the destination directory for the xml file.
            File SDCardRoot = Environment.getExternalStorageDirectory();
            File xmlFile = new File(SDCardRoot, "albumArt.xml");

            if (tag != null) {

                String title = tag.getFirst(FieldKey.TITLE);
                String checkingMessage = mContext.getResources().getString(R.string.checking_if) + " " + title + " "
                        + mContext.getResources().getString(R.string.has_album_art) + ".";

                currentProgress = currentProgress + 1;
                String[] checkingProgressParams = { checkingMessage, "" + currentProgress };
                publishProgress(checkingProgressParams);

                List<Artwork> artworkList = tag.getArtworkList();

                if (artworkList.size() == 0) {

                    //Since the file doesn't have any album artwork, we'll have to download it.
                    //Get the artist and album name of the file we're working with.
                    String artist = tag.getFirst(FieldKey.ARTIST);
                    String album = tag.getFirst(FieldKey.ALBUM);

                    //Update the progress dialog.
                    String message = mContext.getResources().getString(R.string.downloading_artwork_for) + " "
                            + title;
                    String[] progressParams = { message, "" + currentProgress };
                    publishProgress(progressParams);

                    //Remove any unacceptable characters.
                    if (artist.contains("#")) {
                        artist = artist.replace("#", "");
                    }

                    if (artist.contains("$")) {
                        artist = artist.replace("$", "");
                    }

                    if (artist.contains("@")) {
                        artist = artist.replace("@", "");
                    }

                    if (album.contains("#")) {
                        album = album.replace("#", "");
                    }

                    if (album.contains("$")) {
                        album = album.replace("$", "");
                    }

                    if (album.contains("@")) {
                        album = album.replace("@", "");
                    }

                    //Replace any spaces in the artist and album fields with "%20".
                    if (artist.contains(" ")) {
                        artist = artist.replace(" ", "%20");
                    }

                    if (album.contains(" ")) {
                        album = album.replace(" ", "%20");
                    }

                    //Construct the url for the HTTP request.
                    URL url = null;
                    try {
                        url = new URL(
                                "http://itunes.apple.com/search?term=" + artist + "+" + album + "&entity=album");
                    } catch (MalformedURLException e1) {
                        // TODO Auto-generated catch block
                        continue;
                    }

                    String xml = null;
                    try {

                        //Create a new HTTP connection.
                        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

                        urlConnection.connect();

                        //Check if albumArt.xml already exists and delete it.
                        if (xmlFile.exists()) {
                            xmlFile.delete();
                        }

                        //Create the OuputStream that will be used to store the downloaded data into the file.
                        FileOutputStream fileOutput = new FileOutputStream(xmlFile);

                        //Create the InputStream that will read the data from the HTTP connection.
                        InputStream inputStream = urlConnection.getInputStream();

                        //Total size of target file.
                        int totalSize = urlConnection.getContentLength();

                        //Temp variable that stores the number of downloaded bytes.
                        int downloadedSize = 0;

                        //Create a buffer to store the downloaded bytes.
                        buffer = new byte[1024];
                        int bufferLength = 0;

                        //Now read through the buffer and write the contents to the file.
                        while ((bufferLength = inputStream.read(buffer)) > 0) {
                            fileOutput.write(buffer, 0, bufferLength);
                            downloadedSize += bufferLength;

                        }

                        //Close the File Output Stream.
                        fileOutput.close();

                    } catch (MalformedURLException e) {
                        //TODO Auto-generated method stub
                        continue;
                    } catch (IOException e) {
                        // TODO Auto-generated method stub
                        continue;
                    }

                    //Load the XML file into a String variable for local use.
                    String xmlAsString = null;
                    try {
                        xmlAsString = FileUtils.readFileToString(xmlFile);
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                    //Extract the albumArt parameter from the XML file.
                    artworkURL = StringUtils.substringBetween(xmlAsString, "\"artworkUrl100\":\"", "\",");

                    if (artworkURL == null) {

                        //Check and see if a lower resolution image available.
                        artworkURL = StringUtils.substringBetween(xmlAsString, "\"artworkUrl60\":\"", "\",");

                        if (artworkURL == null) {
                            //Can't do anything about that here.
                        } else {
                            //Replace "100x100" with "600x600" to retrieve larger album art images.
                            artworkURL = artworkURL.replace("100x100", "600x600");
                        }

                    } else {
                        //Replace "100x100" with "600x600" to retrieve larger album art images.
                        artworkURL = artworkURL.replace("100x100", "600x600");
                    }

                    //If no URL has been found, there's no point in continuing.
                    if (artworkURL != null) {

                        artworkBitmap = null;
                        artworkBitmap = mApp.getImageLoader().loadImageSync(artworkURL);

                        File artworkFile = new File(Environment.getExternalStorageDirectory() + "/artwork.jpg");

                        //Save the artwork.
                        try {

                            FileOutputStream out = new FileOutputStream(artworkFile);
                            artworkBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);

                        } catch (Exception e) {
                            e.printStackTrace();
                        } finally {

                            Artwork artwork = null;
                            try {
                                artwork = ArtworkFactory.createArtworkFromFile(artworkFile);
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                setArtworkAsFile(artworkFile, dataURIsList.get(i));
                                continue;
                            } catch (ArrayIndexOutOfBoundsException e) {
                                // TODO Auto-generated catch block
                                setArtworkAsFile(artworkFile, dataURIsList.get(i));
                                continue;
                            } catch (Exception e) {
                                e.printStackTrace();
                                setArtworkAsFile(artworkFile, dataURIsList.get(i));
                                continue;
                            } catch (Error e) {
                                e.printStackTrace();
                                setArtworkAsFile(artworkFile, dataURIsList.get(i));
                                continue;
                            }

                            if (artwork != null) {

                                try {
                                    //Remove the current artwork field and recreate it.
                                    tag.deleteArtworkField();
                                    tag.addField(artwork);
                                } catch (Exception e) {
                                    // TODO Auto-generated catch block
                                    setArtworkAsFile(artworkFile, dataURIsList.get(i));
                                    continue;
                                } catch (Error e) {
                                    e.printStackTrace();
                                    setArtworkAsFile(artworkFile, dataURIsList.get(i));
                                    continue;
                                }

                                try {
                                    audioFile.commit();
                                } catch (CannotWriteException e) {
                                    // TODO Auto-generated catch block
                                    setArtworkAsFile(artworkFile, dataURIsList.get(i));
                                    continue;
                                } catch (Error e) {
                                    e.printStackTrace();
                                    setArtworkAsFile(artworkFile, dataURIsList.get(i));
                                    continue;
                                }

                            }

                            //Delete the temporary files that we stored during the fetching process.
                            if (artworkFile.exists()) {
                                artworkFile.delete();
                            }

                            if (xmlFile.exists()) {
                                xmlFile.delete();
                            }

                            //Set the files to null to help clean up memory.
                            artworkBitmap = null;
                            audioFile = null;
                            tag = null;
                            xmlFile = null;
                            artworkFile = null;

                        }

                    }

                }

            }

        }

        audioFile = null;
        file = null;
        //System.gc();

        return null;

    }

    //Saves the artwork as a JPEG file in the song's parent folder.
    public void setArtworkAsFile(File artworkFile, String songFilePath) {

        File songFile = new File(songFilePath);
        String songTitle = songFile.getName();
        int lastDotSlash = songTitle.lastIndexOf(".");
        String albumArtFileName = songTitle.substring(0, lastDotSlash);

        if (songFile.exists()) {
            int lastSlashIndex = songFilePath.lastIndexOf("/");
            String folderPath = songFilePath.substring(0, lastSlashIndex);
            File destFile = new File(folderPath + "/" + albumArtFileName + ".jpg");

            try {
                FileUtils.copyFile(artworkFile, destFile);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return;
            }

            //Update the album art tag in Jams' database.
            ContentValues values = new ContentValues();
            songFilePath = songFilePath.replace("'", "''");
            String where = DBAccessHelper.SONG_FILE_PATH + "=" + "'" + songFilePath + "'";
            values.put(DBAccessHelper.SONG_ALBUM_ART_PATH, folderPath + "/" + albumArtFileName + ".jpg");
            dbHelper.getWritableDatabase().update(DBAccessHelper.MUSIC_LIBRARY_TABLE, values, where, null);

        }

    }

    @Override
    public void onProgressUpdate(String... values) {
        super.onProgressUpdate(values);

        if (DIALOG_VISIBLE == true) {
            pd.setProgress(Integer.parseInt(values[1]));
            pd.setMessage(values[0]);
        }

        //Update the notification.
        AutoFetchAlbumArtService.builder
                .setContentTitle(mContext.getResources().getString(R.string.downloading_missing_cover_art));
        AutoFetchAlbumArtService.builder.setSmallIcon(R.drawable.notif_icon);
        AutoFetchAlbumArtService.builder.setContentInfo(null);
        AutoFetchAlbumArtService.builder.setContentText(null);
        AutoFetchAlbumArtService.builder.setProgress(dataURIsList.size(), currentProgress, false);
        AutoFetchAlbumArtService.notification = AutoFetchAlbumArtService.builder.build();

        NotificationManager notifyManager = (NotificationManager) mContext
                .getSystemService(Context.NOTIFICATION_SERVICE);
        notifyManager.notify(AutoFetchAlbumArtService.NOTIFICATION_ID, AutoFetchAlbumArtService.notification);

    }

    @Override
    protected void onPostExecute(Void arg0) {

        Intent intent = new Intent(mContext, AutoFetchAlbumArtService.class);
        mContext.stopService(intent);

        if (pd.isShowing() && DIALOG_VISIBLE == true) {
            pd.dismiss();
        }

        //Dismiss the notification.
        AutoFetchAlbumArtService.builder
                .setTicker(mContext.getResources().getString(R.string.done_downloading_art));
        AutoFetchAlbumArtService.builder
                .setContentTitle(mContext.getResources().getString(R.string.done_downloading_art));
        AutoFetchAlbumArtService.builder.setSmallIcon(R.drawable.notif_icon);
        AutoFetchAlbumArtService.builder.setContentInfo(null);
        AutoFetchAlbumArtService.builder.setContentText(null);
        AutoFetchAlbumArtService.builder.setProgress(0, 0, false);
        AutoFetchAlbumArtService.notification = AutoFetchAlbumArtService.builder.build();
        AutoFetchAlbumArtService.notification.flags = Notification.FLAG_AUTO_CANCEL;

        NotificationManager notifyManager = (NotificationManager) mContext
                .getSystemService(Context.NOTIFICATION_SERVICE);
        notifyManager.notify(AutoFetchAlbumArtService.NOTIFICATION_ID, AutoFetchAlbumArtService.notification);

        Toast.makeText(mContext, R.string.done_downloading_art, Toast.LENGTH_LONG).show();

        //Rescan for album art.
        //Seting the "RESCAN_ALBUM_ART" flag to true will force MainActivity to rescan the folders.
        sharedPreferences.edit().putBoolean("RESCAN_ALBUM_ART", true).commit();

        //Restart the app.
        final Intent i = mActivity.getBaseContext().getPackageManager()
                .getLaunchIntentForPackage(mActivity.getBaseContext().getPackageName());

        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        mActivity.startActivity(i);
        mActivity.finish();

    }

}