OSDN Git Service

Rewrite image fetching and caching
authorIwo Banas <banas.iwo@gmail.com>
Sun, 16 Sep 2012 12:15:36 +0000 (13:15 +0100)
committerEvan McClain <aeroevan@gmail.com>
Sun, 6 Jan 2013 05:42:02 +0000 (00:42 -0500)
Rewrite of artist and album images fetching and caching functionality.
The main objectives of this rewrite are to:
reduce images flickering when scrolling,
ensure that correct images are displayed next to corresponding artist
and to simplify the code so that it’s easier to extend.
The image downloading logic, which was previously scattered throughout
the application, got replaced with the call to ImageUtils.setArtistImage()
static function which delegates the the task to the ImageProvider singleton.
To prevent image flickering bitmaps cached in memory are applied
to ImageViews synchronously on the UI thread.
Images requiring disc or network access are processed in AsyncTasks.

Conflicts:
src/com/andrew/apollo/service/ApolloService.java

Change-Id: Icba3939b87df72986f56e2305cbc59df9feb20f9

40 files changed:
res/values/config.xml
src/com/andrew/apollo/AudioPlayerFragment.java
src/com/andrew/apollo/Constants.java
src/com/andrew/apollo/IApolloService.aidl
src/com/andrew/apollo/activities/MusicLibrary.java
src/com/andrew/apollo/activities/TracksBrowser.java
src/com/andrew/apollo/adapters/AlbumAdapter.java
src/com/andrew/apollo/adapters/ArtistAdapter.java
src/com/andrew/apollo/adapters/ArtistAlbumAdapter.java
src/com/andrew/apollo/adapters/QuickQueueAdapter.java
src/com/andrew/apollo/adapters/RecentlyAddedAdapter.java
src/com/andrew/apollo/app/widgets/AppWidget11.java
src/com/andrew/apollo/app/widgets/AppWidget41.java
src/com/andrew/apollo/app/widgets/AppWidget42.java
src/com/andrew/apollo/grid/fragments/AlbumsFragment.java
src/com/andrew/apollo/grid/fragments/ArtistsFragment.java
src/com/andrew/apollo/list/fragments/ArtistAlbumsFragment.java
src/com/andrew/apollo/preferences/SettingsHolder.java
src/com/andrew/apollo/service/ApolloService.java
src/com/andrew/apollo/tasks/BitmapFromURL.java [deleted file]
src/com/andrew/apollo/tasks/FetchAlbumImages.java [deleted file]
src/com/andrew/apollo/tasks/FetchArtistImages.java [deleted file]
src/com/andrew/apollo/tasks/GetAlbumImageTask.java [new file with mode: 0644]
src/com/andrew/apollo/tasks/GetArtistImageTask.java [new file with mode: 0644]
src/com/andrew/apollo/tasks/GetBitmapTask.java [new file with mode: 0644]
src/com/andrew/apollo/tasks/GetCachedImages.java [deleted file]
src/com/andrew/apollo/tasks/LastfmGetAlbumImages.java [deleted file]
src/com/andrew/apollo/tasks/LastfmGetArtistImages.java [deleted file]
src/com/andrew/apollo/tasks/LastfmGetArtistImagesOriginal.java [deleted file]
src/com/andrew/apollo/tasks/ViewHolderQueueTask.java [deleted file]
src/com/andrew/apollo/tasks/ViewHolderTask.java [deleted file]
src/com/andrew/apollo/ui/widgets/BottomActionBar.java
src/com/andrew/apollo/ui/widgets/BottomActionBarItem.java
src/com/andrew/apollo/utils/ApolloUtils.java
src/com/andrew/apollo/utils/ImageCache.java [new file with mode: 0644]
src/com/andrew/apollo/utils/ImageProvider.java [new file with mode: 0644]
src/com/andrew/apollo/utils/ImageUtils.java [new file with mode: 0644]
src/com/andrew/apollo/views/ViewHolderGrid.java
src/com/andrew/apollo/views/ViewHolderList.java
src/com/andrew/apollo/views/ViewHolderQueue.java

index c3e8295..d907f3c 100644 (file)
@@ -17,4 +17,7 @@
     <integer name="listview_padding_left">16</integer>\r
     <integer name="listview_padding_right">32</integer>\r
 \r
+    <!-- Fade in duration for newly downloaded album and artist images -->\r
+    <integer name="image_fade_in_duration">300</integer>\r
+\r
 </resources>
\ No newline at end of file
index 88517c8..ee4bf6b 100644 (file)
@@ -8,12 +8,7 @@ import android.content.BroadcastReceiver;
 import android.content.Context;\r
 import android.content.Intent;\r
 import android.content.IntentFilter;\r
-import android.os.AsyncTask;\r
-import android.os.Bundle;\r
-import android.os.Handler;\r
-import android.os.Message;\r
-import android.os.RemoteException;\r
-import android.os.SystemClock;\r
+import android.os.*;\r
 import android.provider.BaseColumns;\r
 import android.provider.MediaStore.Audio;\r
 import android.support.v4.app.Fragment;\r
@@ -21,27 +16,17 @@ import android.view.LayoutInflater;
 import android.view.View;\r
 import android.view.View.OnClickListener;\r
 import android.view.ViewGroup;\r
-import android.widget.ImageButton;\r
-import android.widget.ImageView;\r
-import android.widget.SeekBar;\r
+import android.widget.*;\r
 import android.widget.SeekBar.OnSeekBarChangeListener;\r
-import android.widget.TextView;\r
-import android.widget.Toast;\r
-\r
 import com.andrew.apollo.activities.TracksBrowser;\r
 import com.andrew.apollo.service.ApolloService;\r
-import com.andrew.apollo.tasks.GetCachedImages;\r
-import com.andrew.apollo.tasks.LastfmGetAlbumImages;\r
 import com.andrew.apollo.ui.widgets.RepeatingImageButton;\r
 import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 import com.andrew.apollo.utils.ThemeUtils;\r
 \r
-import static com.andrew.apollo.Constants.ALBUM_KEY;\r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
-import static com.andrew.apollo.Constants.ARTIST_ID;\r
-import static com.andrew.apollo.Constants.ARTIST_KEY;\r
-import static com.andrew.apollo.Constants.MIME_TYPE;\r
+import static com.andrew.apollo.Constants.*;\r
 \r
 /**\r
  * @author Andrew Neal\r
@@ -584,12 +569,7 @@ public class AudioPlayerFragment extends Fragment {
         mDuration = MusicUtils.getDuration();\r
         mTotalTime.setText(MusicUtils.makeTimeString(getActivity(), mDuration / 1000));\r
 \r
-        if (ApolloUtils.getImageURL(albumName, ALBUM_IMAGE, getActivity()) == null)\r
-            new LastfmGetAlbumImages(getActivity(), mAlbumArt, 1).executeOnExecutor(\r
-                    AsyncTask.THREAD_POOL_EXECUTOR, artistName, albumName);\r
-\r
-        new GetCachedImages(getActivity(), 1, mAlbumArt).executeOnExecutor(\r
-                AsyncTask.THREAD_POOL_EXECUTOR, albumName);\r
+        ImageUtils.setAlbumImage(mAlbumArt, artistName, albumName);\r
 \r
         // Theme chooser\r
         ThemeUtils.setTextColor(getActivity(), mTrackName, "audio_player_text_color");\r
index 5491019..6ca5541 100644 (file)
@@ -14,8 +14,7 @@ public final class Constants {
 \r
     // SharedPreferences\r
     public final static String APOLLO = "Apollo", APOLLO_PREFERENCES = "apollopreferences",\r
-            ARTIST_IMAGE = "artistimage", ARTIST_IMAGE_ORIGINAL = "artistimageoriginal",\r
-            ALBUM_IMAGE = "albumimage", ARTIST_KEY = "artist", ALBUM_KEY = "album",\r
+            ARTIST_KEY = "artist", ALBUM_KEY = "album",\r
             GENRE_KEY = "genres", ARTIST_ID = "artistid", NUMWEEKS = "numweeks",\r
             PLAYLIST_NAME_FAVORITES = "Favorites", PLAYLIST_NAME = "playlist",\r
             THEME_PACKAGE_NAME = "themePackageName", THEME_DESCRIPTION = "themeDescription",\r
index b3a9b39..9e6ea1d 100644 (file)
@@ -20,6 +20,7 @@ interface IApolloService
     String getTrackName();\r
     String getAlbumName();\r
     long getAlbumId();\r
+    Bitmap getAlbumBitmap();\r
     String getArtistName();\r
     long getArtistId();\r
     void enqueue(in long [] list, int action);\r
index e86ebd8..8dcf018 100644 (file)
@@ -33,6 +33,7 @@ import com.andrew.apollo.service.ApolloService;
 import com.andrew.apollo.service.ServiceToken;\r
 import com.andrew.apollo.ui.widgets.ScrollableTabView;\r
 import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageCache;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 import com.andrew.apollo.utils.ThemeUtils;\r
 \r
@@ -99,6 +100,9 @@ public class MusicLibrary extends FragmentActivity implements ServiceConnection
         // Unbind\r
         if (MusicUtils.mService != null)\r
             MusicUtils.unbindFromService(mToken);\r
+\r
+        //TODO: clear image cache\r
+\r
         super.onStop();\r
     }\r
 \r
index 714f074..bdf257d 100644 (file)
@@ -4,19 +4,13 @@
 \r
 package com.andrew.apollo.activities;\r
 \r
-import android.content.BroadcastReceiver;\r
-import android.content.ComponentName;\r
-import android.content.Context;\r
-import android.content.Intent;\r
-import android.content.IntentFilter;\r
-import android.content.ServiceConnection;\r
+import android.content.*;\r
 import android.content.pm.ActivityInfo;\r
 import android.content.res.Resources;\r
 import android.graphics.Bitmap;\r
 import android.graphics.BitmapFactory;\r
 import android.graphics.drawable.AnimationDrawable;\r
 import android.media.AudioManager;\r
-import android.os.AsyncTask;\r
 import android.os.Bundle;\r
 import android.os.IBinder;\r
 import android.os.SystemClock;\r
@@ -31,7 +25,6 @@ import android.widget.FrameLayout;
 import android.widget.ImageView;\r
 import android.widget.RelativeLayout;\r
 import android.widget.TextView;\r
-\r
 import com.andrew.apollo.BottomActionBarControlsFragment;\r
 import com.andrew.apollo.BottomActionBarFragment;\r
 import com.andrew.apollo.IApolloService;\r
@@ -41,26 +34,12 @@ import com.andrew.apollo.list.fragments.ArtistAlbumsFragment;
 import com.andrew.apollo.list.fragments.TracksFragment;\r
 import com.andrew.apollo.service.ApolloService;\r
 import com.andrew.apollo.service.ServiceToken;\r
-import com.andrew.apollo.tasks.GetCachedImages;\r
-import com.andrew.apollo.tasks.LastfmGetAlbumImages;\r
-import com.andrew.apollo.tasks.LastfmGetArtistImagesOriginal;\r
 import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 import com.andrew.apollo.utils.ThemeUtils;\r
 \r
-import static com.andrew.apollo.Constants.ALBUM_KEY;\r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
-import static com.andrew.apollo.Constants.ARTIST_KEY;\r
-import static com.andrew.apollo.Constants.ARTIST_ID;\r
-import static com.andrew.apollo.Constants.ARTIST_IMAGE_ORIGINAL;\r
-import static com.andrew.apollo.Constants.GENRE_KEY;\r
-import static com.andrew.apollo.Constants.INTENT_ACTION;\r
-import static com.andrew.apollo.Constants.MIME_TYPE;\r
-import static com.andrew.apollo.Constants.PLAYLIST_NAME;\r
-import static com.andrew.apollo.Constants.PLAYLIST_QUEUE;\r
-import static com.andrew.apollo.Constants.PLAYLIST_FAVORITES;\r
-import static com.andrew.apollo.Constants.THEME_ITEM_BACKGROUND;\r
-import static com.andrew.apollo.Constants.UP_STARTS_ALBUM_ACTIVITY;\r
+import static com.andrew.apollo.Constants.*;\r
 \r
 /**\r
  * @author Andrew Neal\r
@@ -352,19 +331,7 @@ public class TracksBrowser extends FragmentActivity implements ServiceConnection
 \r
         // Artist image & Genre image\r
         final ImageView mFirstHalfImage = (ImageView)findViewById(R.id.half_artist_image);\r
-\r
-        mFirstHalfImage.post(new Runnable() {\r
-            @Override\r
-            public void run() {\r
-                // Only download images we don't already have\r
-                if (ApolloUtils.getImageURL(getArtist(), ARTIST_IMAGE_ORIGINAL, TracksBrowser.this) == null)\r
-                    new LastfmGetArtistImagesOriginal(TracksBrowser.this, mFirstHalfImage)\r
-                            .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getArtist());\r
-                // Get and set cached image\r
-                new GetCachedImages(TracksBrowser.this, 0, mFirstHalfImage).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, getArtist());\r
-            }\r
-        });\r
+        ImageUtils.setArtistImage(mFirstHalfImage, getArtist());\r
 \r
         mFirstHalfImage.setOnClickListener(new OnClickListener() {\r
 \r
@@ -388,20 +355,7 @@ public class TracksBrowser extends FragmentActivity implements ServiceConnection
 \r
         // Album image\r
         final ImageView mSecondHalfImage = (ImageView)findViewById(R.id.half_album_image);\r
-\r
-        mSecondHalfImage.post(new Runnable() {\r
-            @Override\r
-            public void run() {\r
-                // Only download images we don't already have\r
-                if (ApolloUtils.getImageURL(getAlbum(), ALBUM_IMAGE, TracksBrowser.this) == null)\r
-                    new LastfmGetAlbumImages(TracksBrowser.this, mSecondHalfImage, 1)\r
-                            .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, getArtist(),\r
-                                    getAlbum());\r
-                // Get and set cached image\r
-                new GetCachedImages(TracksBrowser.this, 1, mSecondHalfImage).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, getAlbum());\r
-            }\r
-        });\r
+        ImageUtils.setAlbumImage(mSecondHalfImage, getArtist(), getAlbum());\r
     }\r
 \r
     /**\r
index b7f22b1..07b0f58 100644 (file)
@@ -1,27 +1,21 @@
 \r
 package com.andrew.apollo.adapters;\r
 \r
-import java.lang.ref.WeakReference;\r
-\r
 import android.content.Context;\r
 import android.database.Cursor;\r
 import android.graphics.drawable.AnimationDrawable;\r
-import android.os.AsyncTask;\r
 import android.os.RemoteException;\r
 import android.support.v4.widget.SimpleCursorAdapter;\r
 import android.view.View;\r
 import android.view.ViewGroup;\r
-\r
 import com.andrew.apollo.R;\r
 import com.andrew.apollo.grid.fragments.AlbumsFragment;\r
-import com.andrew.apollo.tasks.LastfmGetAlbumImages;\r
-import com.andrew.apollo.tasks.ViewHolderTask;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 import com.andrew.apollo.views.ViewHolderGrid;\r
 import com.androidquery.AQuery;\r
 \r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
+import java.lang.ref.WeakReference;\r
 \r
 /**\r
  * @author Andrew Neal\r
@@ -63,21 +57,8 @@ public class AlbumAdapter extends SimpleCursorAdapter {
         String artistName = mCursor.getString(AlbumsFragment.mArtistNameIndex);\r
         holderReference.get().mViewHolderLineTwo.setText(artistName);\r
 \r
-        // Match positions\r
-        holderReference.get().position = position;\r
-        if (aq.shouldDelay(position, view, parent, "")) {\r
-            holderReference.get().mViewHolderImage.setImageDrawable(null);\r
-        } else {\r
-            // Check for missing album images and cache them\r
-            if (ApolloUtils.getImageURL(albumName, ALBUM_IMAGE, mContext) == null) {\r
-                new LastfmGetAlbumImages(mContext, null, 0).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, artistName, albumName);\r
-            } else {\r
-                new ViewHolderTask(null, holderReference.get(), position, mContext, 1, 1,\r
-                        holderReference.get().mViewHolderImage).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, albumName);\r
-            }\r
-        }\r
+        ImageUtils.setAlbumImage(viewholder.mViewHolderImage, artistName, albumName);\r
+\r
         // Now playing indicator\r
         long currentalbumid = MusicUtils.getCurrentAlbumId();\r
         long albumid = mCursor.getLong(AlbumsFragment.mAlbumIdIndex);\r
index ceb2974..bd269e8 100644 (file)
@@ -1,28 +1,22 @@
 \r
 package com.andrew.apollo.adapters;\r
 \r
-import java.lang.ref.WeakReference;\r
-\r
 import android.content.Context;\r
 import android.database.Cursor;\r
 import android.graphics.drawable.AnimationDrawable;\r
-import android.os.AsyncTask;\r
 import android.os.RemoteException;\r
 import android.provider.MediaStore;\r
 import android.support.v4.widget.SimpleCursorAdapter;\r
 import android.view.View;\r
 import android.view.ViewGroup;\r
-\r
 import com.andrew.apollo.R;\r
 import com.andrew.apollo.grid.fragments.ArtistsFragment;\r
-import com.andrew.apollo.tasks.LastfmGetArtistImages;\r
-import com.andrew.apollo.tasks.ViewHolderTask;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 import com.andrew.apollo.views.ViewHolderGrid;\r
 import com.androidquery.AQuery;\r
 \r
-import static com.andrew.apollo.Constants.ARTIST_IMAGE;\r
+import java.lang.ref.WeakReference;\r
 \r
 /**\r
  * @author Andrew Neal\r
@@ -66,20 +60,8 @@ public class ArtistAdapter extends SimpleCursorAdapter {
         String numAlbums = MusicUtils.makeAlbumsLabel(mContext, albums_plural, 0, unknown);\r
         holderReference.get().mViewHolderLineTwo.setText(numAlbums);\r
 \r
-        holderReference.get().position = position;\r
-        if (aq.shouldDelay(position, view, parent, "")) {\r
-            holderReference.get().mViewHolderImage.setImageDrawable(null);\r
-        } else {\r
-            // Check for missing artist images and cache them\r
-            if (ApolloUtils.getImageURL(artistName, ARTIST_IMAGE, mContext) == null) {\r
-                new LastfmGetArtistImages(mContext).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, artistName);\r
-            } else {\r
-                new ViewHolderTask(null, holderReference.get(), position, mContext, 0, 1,\r
-                        holderReference.get().mViewHolderImage).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, artistName);\r
-            }\r
-        }\r
+        ImageUtils.setArtistImage(viewholder.mViewHolderImage, artistName);\r
+\r
         // Now playing indicator\r
         long currentartistid = MusicUtils.getCurrentArtistId();\r
         long artistid = mCursor.getLong(ArtistsFragment.mArtistIdIndex);\r
index 4faef37..2751d1f 100644 (file)
@@ -1,27 +1,21 @@
 \r
 package com.andrew.apollo.adapters;\r
 \r
-import java.lang.ref.WeakReference;\r
-\r
 import android.content.Context;\r
 import android.database.Cursor;\r
 import android.graphics.drawable.AnimationDrawable;\r
-import android.os.AsyncTask;\r
 import android.os.RemoteException;\r
 import android.support.v4.widget.SimpleCursorAdapter;\r
 import android.view.View;\r
 import android.view.ViewGroup;\r
-\r
 import com.andrew.apollo.R;\r
 import com.andrew.apollo.list.fragments.ArtistAlbumsFragment;\r
-import com.andrew.apollo.tasks.LastfmGetAlbumImages;\r
-import com.andrew.apollo.tasks.ViewHolderTask;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 import com.andrew.apollo.views.ViewHolderList;\r
 import com.androidquery.AQuery;\r
 \r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
+import java.lang.ref.WeakReference;\r
 \r
 /**\r
  * @author Andrew Neal\r
@@ -78,21 +72,7 @@ public class ArtistAlbumAdapter extends SimpleCursorAdapter {
         String numSongs = MusicUtils.makeAlbumsLabel(mContext, 0, songs_plural, true);\r
         holderReference.get().mViewHolderLineTwo.setText(numSongs);\r
 \r
-        // Match positions\r
-        holderReference.get().position = position;\r
-        if (aq.shouldDelay(position, view, parent, "")) {\r
-            holderReference.get().mViewHolderImage.setImageDrawable(null);\r
-        } else {\r
-            // Check for missing album images and cache them\r
-            if (ApolloUtils.getImageURL(albumName, ALBUM_IMAGE, mContext) == null) {\r
-                new LastfmGetAlbumImages(mContext, null, 0).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, artistName, albumName);\r
-            } else {\r
-                new ViewHolderTask(holderReference.get(), null, position, mContext, 1, 0,\r
-                        holderReference.get().mViewHolderImage).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, albumName);\r
-            }\r
-        }\r
+        ImageUtils.setAlbumImage(viewholder.mViewHolderImage, artistName, albumName);\r
 \r
         holderReference.get().mQuickContext.setOnClickListener(showContextMenu);\r
 \r
index 5c50740..2757439 100644 (file)
@@ -1,25 +1,17 @@
 \r
 package com.andrew.apollo.adapters;\r
 \r
-import java.lang.ref.WeakReference;\r
-\r
 import android.content.Context;\r
 import android.database.Cursor;\r
-import android.os.AsyncTask;\r
 import android.support.v4.widget.SimpleCursorAdapter;\r
 import android.view.View;\r
 import android.view.ViewGroup;\r
-\r
 import com.andrew.apollo.grid.fragments.QuickQueueFragment;\r
-import com.andrew.apollo.tasks.LastfmGetAlbumImages;\r
-import com.andrew.apollo.tasks.LastfmGetArtistImages;\r
-import com.andrew.apollo.tasks.ViewHolderQueueTask;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.views.ViewHolderQueue;\r
 import com.androidquery.AQuery;\r
 \r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
-import static com.andrew.apollo.Constants.ARTIST_IMAGE;\r
+import java.lang.ref.WeakReference;\r
 \r
 /**\r
  * @author Andrew Neal\r
@@ -62,36 +54,9 @@ public class QuickQueueAdapter extends SimpleCursorAdapter {
         String trackName = mCursor.getString(QuickQueueFragment.mTitleIndex);\r
         holderReference.get().mTrackName.setText(trackName);\r
 \r
-        holderReference.get().position = position;\r
-        // Artist Image\r
-        if (aq.shouldDelay(position, view, parent, "")) {\r
-            holderReference.get().mArtistImage.setImageDrawable(null);\r
-        } else {\r
-            // Check for missing artist images and cache them\r
-            if (ApolloUtils.getImageURL(artistName, ARTIST_IMAGE, mContext) == null) {\r
-                new LastfmGetArtistImages(mContext).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, artistName);\r
-            } else {\r
-                new ViewHolderQueueTask(holderReference.get(), position, mContext, 0, 0,\r
-                        holderReference.get().mArtistImage).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, artistName);\r
-            }\r
-        }\r
+        ImageUtils.setArtistImage(viewholder.mArtistImage, artistName);\r
+        ImageUtils.setAlbumImage(viewholder.mAlbumArt, artistName, albumName);\r
 \r
-        // Album Image\r
-        if (aq.shouldDelay(position, view, parent, "")) {\r
-            holderReference.get().mAlbumArt.setImageDrawable(null);\r
-        } else {\r
-            // Check for missing album images and cache them\r
-            if (ApolloUtils.getImageURL(albumName, ALBUM_IMAGE, mContext) == null) {\r
-                new LastfmGetAlbumImages(mContext, null, 0).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, artistName, albumName);\r
-            } else {\r
-                new ViewHolderQueueTask(holderReference.get(), position, mContext, 1, 1,\r
-                        holderReference.get().mAlbumArt).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, albumName);\r
-            }\r
-        }\r
         return view;\r
     }\r
 }\r
index 8efa2eb..bc9f80b 100644 (file)
@@ -1,27 +1,21 @@
 \r
 package com.andrew.apollo.adapters;\r
 \r
-import java.lang.ref.WeakReference;\r
-\r
 import android.content.Context;\r
 import android.database.Cursor;\r
 import android.graphics.drawable.AnimationDrawable;\r
-import android.os.AsyncTask;\r
 import android.os.RemoteException;\r
 import android.support.v4.widget.SimpleCursorAdapter;\r
 import android.view.View;\r
 import android.view.ViewGroup;\r
-\r
 import com.andrew.apollo.R;\r
 import com.andrew.apollo.list.fragments.RecentlyAddedFragment;\r
-import com.andrew.apollo.tasks.LastfmGetAlbumImages;\r
-import com.andrew.apollo.tasks.ViewHolderTask;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 import com.andrew.apollo.views.ViewHolderList;\r
 import com.androidquery.AQuery;\r
 \r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
+import java.lang.ref.WeakReference;\r
 \r
 /**\r
  * @author Andrew Neal\r
@@ -66,21 +60,7 @@ public class RecentlyAddedAdapter extends SimpleCursorAdapter {
         // Album name\r
         String albumName = mCursor.getString(RecentlyAddedFragment.mAlbumIndex);\r
 \r
-        // Match positions\r
-        holderReference.get().position = position;\r
-        if (aq.shouldDelay(position, view, parent, "")) {\r
-            holderReference.get().mViewHolderImage.setImageDrawable(null);\r
-        } else {\r
-            // Check for missing artwork and cache then cache it\r
-            if (ApolloUtils.getImageURL(albumName, ALBUM_IMAGE, mContext) == null) {\r
-                new LastfmGetAlbumImages(mContext, null, 0).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, artistName, albumName);\r
-            } else {\r
-                new ViewHolderTask(holderReference.get(), null, position, mContext, 1, 0,\r
-                        holderReference.get().mViewHolderImage).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, albumName);\r
-            }\r
-        }\r
+        ImageUtils.setAlbumImage(viewholder.mViewHolderImage, artistName, albumName);\r
 \r
         holderReference.get().mQuickContext.setVisibility(View.GONE);\r
 \r
index c730a2c..465e4f4 100644 (file)
@@ -13,10 +13,6 @@ import android.widget.RemoteViews;
 \r
 import com.andrew.apollo.R;\r
 import com.andrew.apollo.service.ApolloService;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-import com.androidquery.AQuery;\r
-\r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
 \r
 /**\r
  * Simple widget to show currently playing album art along with play/pause and\r
@@ -105,9 +101,7 @@ public class AppWidget11 extends AppWidgetProvider {
                 R.layout.onebyone_app_widget);\r
 \r
         // Set album art\r
-        AQuery aq = new AQuery(service);\r
-        Bitmap bitmap = aq.getCachedImage(ApolloUtils.getImageURL(service.getAlbumName(),\r
-                ALBUM_IMAGE, service));\r
+        Bitmap bitmap = service.getAlbumBitmap();\r
         if (bitmap != null) {\r
             views.setViewVisibility(R.id.one_by_one_albumart, View.VISIBLE);\r
             views.setImageViewBitmap(R.id.one_by_one_albumart, bitmap);\r
index b34e1cf..627948f 100644 (file)
@@ -30,10 +30,6 @@ import com.andrew.apollo.R;
 import com.andrew.apollo.activities.AudioPlayerHolder;\r
 import com.andrew.apollo.activities.MusicLibrary;\r
 import com.andrew.apollo.service.ApolloService;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-import com.androidquery.AQuery;\r
-\r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
 \r
 /**\r
  * Simple widget to show currently playing album art along with play/pause and\r
@@ -125,9 +121,7 @@ public class AppWidget41 extends AppWidgetProvider {
         views.setTextViewText(R.id.four_by_one_title, titleName);\r
         views.setTextViewText(R.id.four_by_one_artist, artistName);\r
         // Set album art\r
-        AQuery aq = new AQuery(service);\r
-        Bitmap bitmap = aq.getCachedImage(ApolloUtils.getImageURL(service.getAlbumName(),\r
-                ALBUM_IMAGE, service));\r
+        Bitmap bitmap = service.getAlbumBitmap();\r
         if (bitmap != null) {\r
             views.setViewVisibility(R.id.four_by_one_albumart, View.VISIBLE);\r
             views.setViewVisibility(R.id.four_by_one_control_prev, View.GONE);\r
index 61edeec..b5f486a 100644 (file)
@@ -30,10 +30,6 @@ import com.andrew.apollo.R;
 import com.andrew.apollo.activities.AudioPlayerHolder;\r
 import com.andrew.apollo.activities.MusicLibrary;\r
 import com.andrew.apollo.service.ApolloService;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-import com.androidquery.AQuery;\r
-\r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
 \r
 /**\r
  * Simple widget to show currently playing album art along with play/pause and\r
@@ -128,9 +124,7 @@ public class AppWidget42 extends AppWidgetProvider {
         views.setTextViewText(R.id.four_by_two_trackname, trackName);\r
 \r
         // Set album art\r
-        AQuery aq = new AQuery(service);\r
-        Bitmap bitmap = aq.getCachedImage(ApolloUtils.getImageURL(service.getAlbumName(),\r
-                ALBUM_IMAGE, service));\r
+        Bitmap bitmap = service.getAlbumBitmap();\r
         if (bitmap != null) {\r
             views.setViewVisibility(R.id.four_by_two_albumart, View.VISIBLE);\r
             views.setImageViewBitmap(R.id.four_by_two_albumart, bitmap);\r
index 1cc7d78..8b12cd3 100644 (file)
@@ -10,7 +10,6 @@ import android.content.Intent;
 import android.content.IntentFilter;\r
 import android.database.Cursor;\r
 import android.net.Uri;\r
-import android.os.AsyncTask;\r
 import android.os.Bundle;\r
 import android.provider.BaseColumns;\r
 import android.provider.MediaStore.Audio;\r
@@ -19,34 +18,21 @@ import android.support.v4.app.Fragment;
 import android.support.v4.app.LoaderManager.LoaderCallbacks;\r
 import android.support.v4.content.CursorLoader;\r
 import android.support.v4.content.Loader;\r
-import android.view.ContextMenu;\r
+import android.view.*;\r
 import android.view.ContextMenu.ContextMenuInfo;\r
-import android.view.LayoutInflater;\r
-import android.view.MenuItem;\r
-import android.view.View;\r
-import android.view.ViewGroup;\r
 import android.widget.AdapterView;\r
 import android.widget.AdapterView.OnItemClickListener;\r
 import android.widget.GridView;\r
 import android.widget.ImageView;\r
 import android.widget.TextView;\r
-\r
 import com.andrew.apollo.R;\r
 import com.andrew.apollo.activities.TracksBrowser;\r
 import com.andrew.apollo.adapters.AlbumAdapter;\r
 import com.andrew.apollo.service.ApolloService;\r
-import com.andrew.apollo.tasks.GetCachedImages;\r
-import com.andrew.apollo.tasks.LastfmGetAlbumImages;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 \r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
-import static com.andrew.apollo.Constants.ALBUM_KEY;\r
-import static com.andrew.apollo.Constants.ARTIST_KEY;\r
-import static com.andrew.apollo.Constants.INTENT_ADD_TO_PLAYLIST;\r
-import static com.andrew.apollo.Constants.INTENT_PLAYLIST_LIST;\r
-import static com.andrew.apollo.Constants.MIME_TYPE;\r
-import static com.andrew.apollo.Constants.UP_STARTS_ALBUM_ACTIVITY;\r
+import static com.andrew.apollo.Constants.*;\r
 \r
 /**\r
  * @author Andrew Neal\r
@@ -253,14 +239,7 @@ public class AlbumsFragment extends Fragment implements LoaderCallbacks<Cursor>,
         // Artist image\r
         ImageView headerImage = (ImageView)header.findViewById(R.id.header_image);\r
 \r
-        // Only download images we don't already have\r
-        if (ApolloUtils.getImageURL(albumName, ALBUM_IMAGE, getActivity()) == null)\r
-            new LastfmGetAlbumImages(getActivity(), null, 0).executeOnExecutor(\r
-                    AsyncTask.THREAD_POOL_EXECUTOR, artistName, albumName);\r
-\r
-        // Get and set cached image\r
-        new GetCachedImages(getActivity(), 1, headerImage).executeOnExecutor(\r
-                AsyncTask.THREAD_POOL_EXECUTOR, albumName);\r
+        ImageUtils.setAlbumImage(headerImage, artistName, albumName);\r
 \r
         // Set artist name\r
         TextView headerText = (TextView)header.findViewById(R.id.header_text);\r
index f35290b..4c0a09d 100644 (file)
@@ -10,7 +10,6 @@ import android.content.Intent;
 import android.content.IntentFilter;\r
 import android.database.Cursor;\r
 import android.net.Uri;\r
-import android.os.AsyncTask;\r
 import android.os.Bundle;\r
 import android.provider.BaseColumns;\r
 import android.provider.MediaStore.Audio;\r
@@ -19,33 +18,22 @@ import android.support.v4.app.Fragment;
 import android.support.v4.app.LoaderManager.LoaderCallbacks;\r
 import android.support.v4.content.CursorLoader;\r
 import android.support.v4.content.Loader;\r
-import android.view.ContextMenu;\r
+import android.view.*;\r
 import android.view.ContextMenu.ContextMenuInfo;\r
-import android.view.LayoutInflater;\r
-import android.view.MenuItem;\r
-import android.view.View;\r
-import android.view.ViewGroup;\r
 import android.widget.AdapterView;\r
 import android.widget.AdapterView.OnItemClickListener;\r
 import android.widget.GridView;\r
 import android.widget.ImageView;\r
 import android.widget.TextView;\r
-\r
 import com.andrew.apollo.R;\r
 import com.andrew.apollo.activities.TracksBrowser;\r
 import com.andrew.apollo.adapters.ArtistAdapter;\r
 import com.andrew.apollo.service.ApolloService;\r
-import com.andrew.apollo.tasks.GetCachedImages;\r
-import com.andrew.apollo.tasks.LastfmGetArtistImagesOriginal;\r
 import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 \r
-import static com.andrew.apollo.Constants.ARTIST_ID;\r
-import static com.andrew.apollo.Constants.ARTIST_IMAGE_ORIGINAL;\r
-import static com.andrew.apollo.Constants.ARTIST_KEY;\r
-import static com.andrew.apollo.Constants.INTENT_ADD_TO_PLAYLIST;\r
-import static com.andrew.apollo.Constants.INTENT_PLAYLIST_LIST;\r
-import static com.andrew.apollo.Constants.MIME_TYPE;\r
+import static com.andrew.apollo.Constants.*;\r
 \r
 /**\r
  * @author Andrew Neal\r
@@ -253,21 +241,7 @@ public class ArtistsFragment extends Fragment implements LoaderCallbacks<Cursor>
 \r
         // Artist image\r
         final ImageView mHanderImage = (ImageView)header.findViewById(R.id.header_image);\r
-\r
-        mHanderImage.post(new Runnable() {\r
-\r
-            @Override\r
-            public void run() {\r
-                // Only download images we don't already have\r
-                if (ApolloUtils.getImageURL(artistName, ARTIST_IMAGE_ORIGINAL, getActivity()) == null)\r
-                    new LastfmGetArtistImagesOriginal(getActivity(), mHanderImage)\r
-                            .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, artistName);\r
-\r
-                // Get and set cached image\r
-                new GetCachedImages(getActivity(), 0, mHanderImage).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, artistName);\r
-            }\r
-        });\r
+        ImageUtils.setArtistImage(mHanderImage, artistName);\r
 \r
         // Set artist name\r
         TextView headerText = (TextView)header.findViewById(R.id.header_text);\r
index c4d4b4d..f86e422 100644 (file)
@@ -10,7 +10,6 @@ import android.content.Intent;
 import android.content.IntentFilter;\r
 import android.database.Cursor;\r
 import android.net.Uri;\r
-import android.os.AsyncTask;\r
 import android.os.Bundle;\r
 import android.provider.BaseColumns;\r
 import android.provider.MediaStore.Audio;\r
@@ -19,34 +18,22 @@ import android.support.v4.app.Fragment;
 import android.support.v4.app.LoaderManager.LoaderCallbacks;\r
 import android.support.v4.content.CursorLoader;\r
 import android.support.v4.content.Loader;\r
-import android.view.ContextMenu;\r
+import android.view.*;\r
 import android.view.ContextMenu.ContextMenuInfo;\r
-import android.view.LayoutInflater;\r
-import android.view.MenuItem;\r
-import android.view.View;\r
-import android.view.ViewGroup;\r
 import android.widget.AdapterView;\r
 import android.widget.AdapterView.OnItemClickListener;\r
 import android.widget.ImageView;\r
 import android.widget.ListView;\r
 import android.widget.TextView;\r
-\r
 import com.andrew.apollo.R;\r
 import com.andrew.apollo.activities.TracksBrowser;\r
 import com.andrew.apollo.adapters.ArtistAlbumAdapter;\r
 import com.andrew.apollo.service.ApolloService;\r
-import com.andrew.apollo.tasks.GetCachedImages;\r
-import com.andrew.apollo.tasks.LastfmGetAlbumImages;\r
 import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 \r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
-import static com.andrew.apollo.Constants.ALBUM_KEY;\r
-import static com.andrew.apollo.Constants.ARTIST_KEY;\r
-import static com.andrew.apollo.Constants.EXTERNAL;\r
-import static com.andrew.apollo.Constants.INTENT_ADD_TO_PLAYLIST;\r
-import static com.andrew.apollo.Constants.INTENT_PLAYLIST_LIST;\r
-import static com.andrew.apollo.Constants.MIME_TYPE;\r
+import static com.andrew.apollo.Constants.*;\r
 \r
 /**\r
  * @author Andrew Neal\r
@@ -262,15 +249,7 @@ public class ArtistAlbumsFragment extends Fragment implements LoaderCallbacks<Cu
 \r
         // Artist image\r
         ImageView headerImage = (ImageView)header.findViewById(R.id.header_image);\r
-\r
-        // Only download images we don't already have\r
-        if (ApolloUtils.getImageURL(albumName, ALBUM_IMAGE, getActivity()) == null)\r
-            new LastfmGetAlbumImages(getActivity(), null, 0).executeOnExecutor(\r
-                    AsyncTask.THREAD_POOL_EXECUTOR, artistName, albumName);\r
-\r
-        // Get and set cached image\r
-        new GetCachedImages(getActivity(), 1, headerImage).executeOnExecutor(\r
-                AsyncTask.THREAD_POOL_EXECUTOR, albumName);\r
+        ImageUtils.setAlbumImage(headerImage, artistName, albumName);\r
 \r
         // Set artist name\r
         TextView headerText = (TextView)header.findViewById(R.id.header_text);\r
index 3704d6c..25d0dce 100644 (file)
@@ -34,12 +34,10 @@ import com.andrew.apollo.activities.AudioPlayerHolder;
 import com.andrew.apollo.activities.MusicLibrary;\r
 import com.andrew.apollo.service.ApolloService;\r
 import com.andrew.apollo.service.ServiceToken;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 import com.andrew.apollo.utils.ThemeUtils;\r
-import com.androidquery.AQuery;\r
 \r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
 import static com.andrew.apollo.Constants.APOLLO;\r
 import static com.andrew.apollo.Constants.THEME_PACKAGE_NAME;\r
 import static com.andrew.apollo.Constants.THEME_PREVIEW;\r
@@ -143,9 +141,7 @@ public class SettingsHolder extends PreferenceActivity implements ServiceConnect
         TextView mTrackName = (TextView)view.findViewById(R.id.action_bar_track_name);\r
         TextView mAlbumName = (TextView)view.findViewById(R.id.action_bar_album_name);\r
 \r
-        String url = ApolloUtils.getImageURL(MusicUtils.getAlbumName(), ALBUM_IMAGE, this);\r
-        AQuery aq = new AQuery(this);\r
-        mAlbumArt.setImageBitmap(aq.getCachedImage(url));\r
+        ImageUtils.setAlbumImage(mAlbumArt, MusicUtils.getArtistName(), MusicUtils.getAlbumName());\r
 \r
         mTrackName.setText(MusicUtils.getTrackName());\r
         mAlbumName.setText(MusicUtils.getAlbumName());\r
index 263673d..151056e 100644 (file)
@@ -62,23 +62,21 @@ import android.util.Log;
 import android.view.KeyEvent;\r
 import android.view.View;\r
 import android.widget.RemoteViews;\r
-import android.widget.Toast;\r
 \r
 import com.andrew.apollo.IApolloService;\r
 import com.andrew.apollo.R;\r
 import com.andrew.apollo.app.widgets.AppWidget11;\r
 import com.andrew.apollo.app.widgets.AppWidget41;\r
 import com.andrew.apollo.app.widgets.AppWidget42;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
+import com.andrew.apollo.tasks.GetAlbumImageTask;\r
+import com.andrew.apollo.tasks.GetBitmapTask;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 import com.andrew.apollo.utils.SharedPreferencesCompat;\r
-import com.androidquery.AQuery;\r
 \r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
 import static com.andrew.apollo.Constants.APOLLO_PREFERENCES;\r
 import static com.andrew.apollo.Constants.DATA_SCHEME;\r
 \r
-public class ApolloService extends Service {\r
+public class ApolloService extends Service implements GetBitmapTask.OnBitmapReadyListener {\r
     /**\r
      * used to specify whether enqueue() should start playing the new list of\r
      * files right away, next or once all the currently queued files have been\r
@@ -255,6 +253,10 @@ public class ApolloService extends Service {
 \r
     private final AppWidget41 mAppWidgetProvider4x1 = AppWidget41.getInstance();\r
 \r
+    private String mAlbumBitmapTag;\r
+\r
+    private Bitmap mAlbumBitmap;\r
+\r
     // interval after which we stop the service when idle\r
     private static final int IDLE_DELAY = 60000;\r
 \r
@@ -303,6 +305,7 @@ public class ApolloService extends Service {
                             mCursor = null;\r
                         }\r
                         mCursor = getCursorForId(mPlayList[mPlayPos]);\r
+                        updateAlbumBitmap();\r
                         notifyChange(META_CHANGED);\r
                         updateNotification();\r
                         setNextTrack();\r
@@ -509,6 +512,7 @@ public class ApolloService extends Service {
             mCursor.close();\r
             mCursor = null;\r
         }\r
+        updateAlbumBitmap();\r
 \r
         unregisterReceiver(mIntentReceiver);\r
         if (mUnmountReceiver != null) {\r
@@ -939,9 +943,7 @@ public class ApolloService extends Service {
             ed.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, getAlbumName());\r
             ed.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, getArtistName());\r
             ed.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, duration());\r
-            AQuery aq = new AQuery(this);\r
-            Bitmap b = aq\r
-                    .getCachedImage(ApolloUtils.getImageURL(getAlbumName(), ALBUM_IMAGE, this));\r
+            Bitmap b = getAlbumBitmap();\r
             if (b != null) {\r
                 ed.putBitmap(MetadataEditor.BITMAP_KEY_ARTWORK, b);\r
             }\r
@@ -1002,6 +1004,7 @@ public class ApolloService extends Service {
         if (mPlayListLen == 0) {\r
             mCursor.close();\r
             mCursor = null;\r
+            updateAlbumBitmap();\r
             notifyChange(META_CHANGED);\r
         }\r
     }\r
@@ -1151,6 +1154,8 @@ public class ApolloService extends Service {
                 }\r
             }\r
 \r
+            updateAlbumBitmap();\r
+\r
             // go to bookmark if needed\r
             if (isPodcast()) {\r
                 long bookmark = getBookmark();\r
@@ -1223,6 +1228,8 @@ public class ApolloService extends Service {
                     }\r
                 } catch (UnsupportedOperationException ex) {\r
                 }\r
+\r
+                updateAlbumBitmap();\r
             }\r
             mFileToPlay = path;\r
             mPlayer.setDataSource(mFileToPlay);\r
@@ -1286,6 +1293,8 @@ public class ApolloService extends Service {
         mAudioManager.registerMediaButtonEventReceiver(new ComponentName(getPackageName(),\r
                 MediaButtonIntentReceiver.class.getName()));\r
 \r
+        Bitmap b = getAlbumBitmap();\r
+\r
         if (mPlayer.isInitialized()) {\r
             // if we are at the end of the song, go to the next song first\r
 \r
@@ -1310,9 +1319,7 @@ public class ApolloService extends Service {
     }\r
 \r
     private void updateNotification() {\r
-        AQuery aq = new AQuery(this);\r
-        Bitmap b = aq.getCachedImage(ApolloUtils.getImageURL(getAlbumName(), ALBUM_IMAGE, this));\r
-\r
+        Bitmap b = getAlbumBitmap();\r
         RemoteViews views = new RemoteViews(getPackageName(), R.layout.status_bar);\r
         if (b != null) {\r
             views.setViewVisibility(R.id.status_bar_icon, View.GONE);\r
@@ -1367,6 +1374,7 @@ public class ApolloService extends Service {
         if (mCursor != null) {\r
             mCursor.close();\r
             mCursor = null;\r
+            updateAlbumBitmap();\r
         }\r
         if (remove_status_icon) {\r
             gotoIdleState();\r
@@ -1798,12 +1806,38 @@ public class ApolloService extends Service {
                         play();\r
                     }\r
                 }\r
+                updateAlbumBitmap();\r
                 notifyChange(META_CHANGED);\r
             }\r
             return last - first + 1;\r
         }\r
     }\r
 \r
+    private synchronized void updateAlbumBitmap()\r
+    {\r
+        if (mCursor == null)\r
+            return;\r
+\r
+        String tag = getArtistName() + " - " + getAlbumName();\r
+        if (tag == mAlbumBitmapTag)\r
+            return;\r
+\r
+        mAlbumBitmapTag = tag;\r
+        mAlbumBitmap = null;\r
+        new GetAlbumImageTask(getArtistName(), getAlbumName(), this, tag, this).execute();\r
+    }\r
+\r
+    @Override\r
+    public void bitmapReady(Bitmap bitmap, String tag) {\r
+        synchronized (this) {\r
+            if (tag.equals(mAlbumBitmapTag)) {\r
+                mAlbumBitmap = bitmap;\r
+            }\r
+        }\r
+        notifyChange(META_CHANGED);\r
+        updateNotification();\r
+    }\r
+\r
     /**\r
      * Removes all instances of the track with the given id from the playlist.\r
      * \r
@@ -1958,6 +1992,10 @@ public class ApolloService extends Service {
         }\r
     }\r
 \r
+    public Bitmap getAlbumBitmap() {\r
+        return mAlbumBitmap;\r
+    }\r
+\r
     public String getTrackName() {\r
         synchronized (this) {\r
             if (mCursor == null) {\r
@@ -2333,6 +2371,11 @@ public class ApolloService extends Service {
         }\r
 \r
         @Override\r
+        public Bitmap getAlbumBitmap() {\r
+            return mService.get().getAlbumBitmap();\r
+        }\r
+\r
+        @Override\r
         public long getAlbumId() {\r
             return mService.get().getAlbumId();\r
         }\r
diff --git a/src/com/andrew/apollo/tasks/BitmapFromURL.java b/src/com/andrew/apollo/tasks/BitmapFromURL.java
deleted file mode 100644 (file)
index a147f09..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/**\r
- * \r
- */\r
-\r
-package com.andrew.apollo.tasks;\r
-\r
-import java.lang.ref.WeakReference;\r
-\r
-import android.graphics.Bitmap;\r
-import android.os.AsyncTask;\r
-import android.widget.ImageView;\r
-\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-\r
-/**\r
- * @author Andrew Neal\r
- */\r
-public class BitmapFromURL extends AsyncTask<String, Integer, Bitmap> {\r
-\r
-    private final WeakReference<ImageView> imageViewReference;\r
-\r
-    private final ImageView mImageView;\r
-\r
-    private WeakReference<Bitmap> bitmapReference;\r
-\r
-    public BitmapFromURL(ImageView iv) {\r
-        imageViewReference = new WeakReference<ImageView>(iv);\r
-        mImageView = imageViewReference.get();\r
-    }\r
-\r
-    @Override\r
-    protected Bitmap doInBackground(String... params) {\r
-        bitmapReference = new WeakReference<Bitmap>(ApolloUtils.getBitmapFromURL(params[0]));\r
-        return bitmapReference.get();\r
-    }\r
-\r
-    @Override\r
-    protected void onPostExecute(Bitmap result) {\r
-        if (result != null && mImageView != null)\r
-            ApolloUtils.runnableBackground(mImageView, result);\r
-        super.onPostExecute(result);\r
-    }\r
-}\r
diff --git a/src/com/andrew/apollo/tasks/FetchAlbumImages.java b/src/com/andrew/apollo/tasks/FetchAlbumImages.java
deleted file mode 100644 (file)
index 7bd8b10..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/**\r
- * \r
- */\r
-\r
-package com.andrew.apollo.tasks;\r
-\r
-import java.lang.ref.WeakReference;\r
-import java.util.ArrayList;\r
-\r
-import android.content.Context;\r
-import android.database.Cursor;\r
-import android.net.Uri;\r
-import android.os.AsyncTask;\r
-import android.provider.BaseColumns;\r
-import android.provider.MediaStore.Audio;\r
-import android.provider.MediaStore.Audio.AlbumColumns;\r
-\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-\r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
-\r
-/**\r
- * @author Andrew Neal\r
- * @returns A String[] of all the artists and albums on a device in default\r
- *          album order that are then fed into the Last.fm API\r
- */\r
-public class FetchAlbumImages {\r
-\r
-    private final Context mContext;\r
-\r
-    private final WeakReference<Context> contextReference;\r
-\r
-    private final int choice;\r
-\r
-    public FetchAlbumImages(Context context, int opt) {\r
-        contextReference = new WeakReference<Context>(context);\r
-        mContext = contextReference.get();\r
-        choice = opt;\r
-    }\r
-\r
-    /**\r
-     * @return album names in default album sort order\r
-     */\r
-    public String[] getAlbumArtists() {\r
-        String[] projection = new String[] {\r
-                BaseColumns._ID, AlbumColumns.ARTIST\r
-        };\r
-        String sortOrder = Audio.Albums.DEFAULT_SORT_ORDER;\r
-        Uri uri = Audio.Albums.EXTERNAL_CONTENT_URI;\r
-        Cursor c = mContext.getContentResolver().query(uri, projection, null, null, sortOrder);\r
-        ArrayList<String> artistIds = new ArrayList<String>();\r
-        if (c != null) {\r
-            int count = c.getCount();\r
-            if (count > 0) {\r
-                final int ARTIST_IDX = c.getColumnIndex(AlbumColumns.ARTIST);\r
-                for (int i = 0; i < count; i++) {\r
-                    c.moveToPosition(i);\r
-                    artistIds.add(c.getString(ARTIST_IDX));\r
-                }\r
-            }\r
-            c.close();\r
-            c = null;\r
-        }\r
-        return artistIds.toArray(new String[artistIds.size()]);\r
-    }\r
-\r
-    /**\r
-     * @author Andrew Neal\r
-     * @returns artist names in default album sort order that are then fed into\r
-     *          the Last.fm API along with @getAlbumArtists()\r
-     */\r
-    public class getAlbums extends AsyncTask<Void, Integer, String[]> {\r
-\r
-        @Override\r
-        protected String[] doInBackground(Void... params) {\r
-            String[] projection = new String[] {\r
-                    BaseColumns._ID, AlbumColumns.ALBUM\r
-            };\r
-            String sortOrder = Audio.Albums.DEFAULT_SORT_ORDER;\r
-            Uri uri = Audio.Albums.EXTERNAL_CONTENT_URI;\r
-            Cursor c = mContext.getContentResolver().query(uri, projection, null, null, sortOrder);\r
-            ArrayList<String> artistIds = new ArrayList<String>();\r
-            if (c != null) {\r
-                int count = c.getCount();\r
-                if (count > 0) {\r
-                    final int ARTIST_IDX = c.getColumnIndex(AlbumColumns.ALBUM);\r
-                    for (int i = 0; i < count; i++) {\r
-                        c.moveToPosition(i);\r
-                        artistIds.add(c.getString(ARTIST_IDX));\r
-                    }\r
-                }\r
-                c.close();\r
-                c = null;\r
-            }\r
-            return artistIds.toArray(new String[artistIds.size()]);\r
-        }\r
-\r
-        @Override\r
-        protected void onPostExecute(String[] result) {\r
-            for (int i = 0; i < result.length; i++) {\r
-                // Only download images we don't already have\r
-                if (choice == 0 && result != null) {\r
-                    if (ApolloUtils.getImageURL(result[i], ALBUM_IMAGE, mContext) == null) {\r
-                        new LastfmGetAlbumImages(mContext, null, 0).executeOnExecutor(\r
-                                AsyncTask.THREAD_POOL_EXECUTOR, getAlbumArtists()[i], result[i]);\r
-                    }\r
-                } else if (choice == 1 && result != null) {\r
-                    // Unless the user wants to grab new images\r
-                    new LastfmGetAlbumImages(mContext, null, 0).executeOnExecutor(\r
-                            AsyncTask.THREAD_POOL_EXECUTOR, getAlbumArtists()[i], result[i]);\r
-                }\r
-            }\r
-            super.onPostExecute(result);\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Fetch album art\r
-     */\r
-    public void runTask() {\r
-        new getAlbums().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);\r
-    }\r
-}\r
diff --git a/src/com/andrew/apollo/tasks/FetchArtistImages.java b/src/com/andrew/apollo/tasks/FetchArtistImages.java
deleted file mode 100644 (file)
index dcd03fa..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/**\r
- * \r
- */\r
-\r
-package com.andrew.apollo.tasks;\r
-\r
-import java.lang.ref.WeakReference;\r
-import java.util.ArrayList;\r
-\r
-import android.content.Context;\r
-import android.database.Cursor;\r
-import android.net.Uri;\r
-import android.os.AsyncTask;\r
-import android.provider.BaseColumns;\r
-import android.provider.MediaStore.Audio;\r
-import android.provider.MediaStore.Audio.ArtistColumns;\r
-\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-\r
-import static com.andrew.apollo.Constants.ARTIST_IMAGE;\r
-\r
-/**\r
- * @author Andrew Neal\r
- * @returns A String[] of all the artists on a device in default artist order\r
- *          that are then fed into the Last.fm API\r
- */\r
-public class FetchArtistImages extends AsyncTask<Void, Integer, String[]> {\r
-\r
-    private final WeakReference<Context> contextReference;\r
-\r
-    private final int choice;\r
-\r
-    public FetchArtistImages(Context context, int opt) {\r
-        contextReference = new WeakReference<Context>(context);\r
-        choice = opt;\r
-    }\r
-\r
-    @Override\r
-    protected String[] doInBackground(Void... params) {\r
-        String[] projection = new String[] {\r
-                BaseColumns._ID, ArtistColumns.ARTIST\r
-        };\r
-        String sortOrder = Audio.Artists.DEFAULT_SORT_ORDER;\r
-        Uri uri = Audio.Artists.EXTERNAL_CONTENT_URI;\r
-        Cursor c = contextReference.get().getContentResolver()\r
-                .query(uri, projection, null, null, sortOrder);\r
-        ArrayList<String> artistIds = new ArrayList<String>();\r
-        if (c != null) {\r
-            int count = c.getCount();\r
-            if (count > 0) {\r
-                final int ARTIST_IDX = c.getColumnIndex(ArtistColumns.ARTIST);\r
-                for (int i = 0; i < count; i++) {\r
-                    c.moveToPosition(i);\r
-                    artistIds.add(c.getString(ARTIST_IDX));\r
-                }\r
-            }\r
-            c.close();\r
-            c = null;\r
-        }\r
-        return artistIds.toArray(new String[artistIds.size()]);\r
-    }\r
-\r
-    @Override\r
-    protected void onPostExecute(String[] result) {\r
-        for (int i = 0; i < result.length; i++) {\r
-            // Only download images we don't already have\r
-            if (choice == 0 && result != null) {\r
-                if (ApolloUtils.getImageURL(result[i], ARTIST_IMAGE, contextReference.get()) == null) {\r
-                    new LastfmGetArtistImages(contextReference.get()).executeOnExecutor(\r
-                            AsyncTask.THREAD_POOL_EXECUTOR, result[i]);\r
-                }\r
-            } else if (choice == 1 && result != null) {\r
-                // Unless the user wants to grab new images\r
-                new LastfmGetArtistImages(contextReference.get()).executeOnExecutor(\r
-                        AsyncTask.THREAD_POOL_EXECUTOR, result[i]);\r
-            }\r
-        }\r
-        super.onPostExecute(result);\r
-    }\r
-\r
-    /**\r
-     * Fetch artist images\r
-     */\r
-    public void runTask() {\r
-        executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);\r
-    }\r
-}\r
diff --git a/src/com/andrew/apollo/tasks/GetAlbumImageTask.java b/src/com/andrew/apollo/tasks/GetAlbumImageTask.java
new file mode 100644 (file)
index 0000000..dfc2118
--- /dev/null
@@ -0,0 +1,56 @@
+package com.andrew.apollo.tasks;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.util.Log;
+import com.andrew.apollo.lastfm.api.Album;
+import com.andrew.apollo.lastfm.api.ImageSize;
+import com.andrew.apollo.utils.ApolloUtils;
+import com.andrew.apollo.utils.ImageUtils;
+
+import java.io.File;
+
+import static com.andrew.apollo.Constants.LASTFM_API_KEY;
+
+public class GetAlbumImageTask extends GetBitmapTask {
+
+    private final String TAG = "GetArtistImageTask";
+
+    private String mArtist;
+
+    private String mAlbum;
+
+    public GetAlbumImageTask(String artist, String album, OnBitmapReadyListener listener, String tag, Context context) {
+        super(listener, tag, context);
+        mArtist = artist;
+        mAlbum = album;
+    }
+
+    @Override
+    protected File getFile(Context context, String extension) {
+        String albumPart = ApolloUtils.escapeForFileSystem(mAlbum);
+        String artistPart = ApolloUtils.escapeForFileSystem(mArtist);
+
+        if (albumPart == null || artistPart == null) {
+            Log.e(TAG, "Can't create file name for: " + mAlbum + " " + mArtist);
+            return null;
+        }
+
+        return new File(context.getExternalFilesDir(null), artistPart + " - " + albumPart + extension);
+    }
+
+    @Override
+    protected String getImageUrl() {
+        try {
+            Album album = Album.getInfo(mArtist, this.mAlbum, LASTFM_API_KEY);
+            if (album == null) {
+                if (ImageUtils.DEBUG) Log.w(TAG, "Album not found: " + mArtist + " - " + this.mAlbum);
+                return null;
+            }
+            return album.getImageURL(ImageSize.LARGE); //TODO: ensure that there is an image available in the specified size
+        } catch (Exception e) {
+            if (ImageUtils.DEBUG) Log.w(TAG, "Error when retrieving album image url", e);
+            return null;
+        }
+    }
+}
diff --git a/src/com/andrew/apollo/tasks/GetArtistImageTask.java b/src/com/andrew/apollo/tasks/GetArtistImageTask.java
new file mode 100644 (file)
index 0000000..ee785da
--- /dev/null
@@ -0,0 +1,55 @@
+package com.andrew.apollo.tasks;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.util.Log;
+import com.andrew.apollo.lastfm.api.Artist;
+import com.andrew.apollo.lastfm.api.Image;
+import com.andrew.apollo.lastfm.api.ImageSize;
+import com.andrew.apollo.lastfm.api.PaginatedResult;
+import com.andrew.apollo.utils.ApolloUtils;
+import com.andrew.apollo.utils.ImageUtils;
+
+import java.io.File;
+import java.util.Iterator;
+
+import static com.andrew.apollo.Constants.LASTFM_API_KEY;
+
+public class GetArtistImageTask extends GetBitmapTask {
+
+    private final String TAG = "GetArtistImageTask";
+
+    private String mArtist;
+
+    public GetArtistImageTask(String artist, OnBitmapReadyListener listener, String tag, Context context) {
+        super(listener, tag, context);
+        mArtist = artist;
+    }
+
+    @Override
+    protected File getFile(Context context, String extension) {
+        String fileName = ApolloUtils.escapeForFileSystem(mArtist);
+        if (fileName == null) {
+            Log.e(TAG, "Can't create file name for: " + mArtist);
+            return null;
+        }
+        return new File(context.getExternalFilesDir(null), fileName + extension);
+    }
+
+    @Override
+    protected String getImageUrl() {
+        try {
+            PaginatedResult<Image> images = Artist.getImages(this.mArtist, 2, 1, LASTFM_API_KEY);
+            Iterator<Image> iterator = images.getPageResults().iterator();
+            if (!iterator.hasNext()) {
+                if (ImageUtils.DEBUG) Log.w(TAG, "Error when retrieving artist image url for \"" + mArtist + "\" - empty result");
+                return null;
+            }
+            Image image = iterator.next();
+            return image.getImageURL(ImageSize.LARGESQUARE); //TODO: ensure that there is an image available in the specified size
+        } catch (Exception e) {
+            if (ImageUtils.DEBUG) Log.w(TAG, "Error when retrieving artist image url for \"" + mArtist + "\"", e);
+            return null;
+        }
+    }
+}
diff --git a/src/com/andrew/apollo/tasks/GetBitmapTask.java b/src/com/andrew/apollo/tasks/GetBitmapTask.java
new file mode 100644 (file)
index 0000000..400fb08
--- /dev/null
@@ -0,0 +1,123 @@
+package com.andrew.apollo.tasks;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.util.Log;
+import com.andrew.apollo.utils.ApolloUtils;
+import com.andrew.apollo.utils.ImageUtils;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+
+public abstract class GetBitmapTask extends AsyncTask<String, Integer, Bitmap> {
+
+    private static final String TAG = "GetBitmapTask";
+
+    private static final String EXTENSION_JPG = ".jpg";
+    private static final String EXTENSION_PNG = ".png";
+    private static final String EXTENSION_GIF = ".gif";
+
+    private static final String[] IMAGE_EXTENSIONS = new String[]{EXTENSION_JPG, EXTENSION_PNG, EXTENSION_GIF};
+
+    private WeakReference<OnBitmapReadyListener> mListenerReference;
+
+    private WeakReference<Context> mContextReference;
+
+    private String mTag;
+
+    public GetBitmapTask(OnBitmapReadyListener listener, String tag, Context context) {
+        mListenerReference = new WeakReference<OnBitmapReadyListener>(listener);
+        mContextReference = new WeakReference<Context>(context);
+        mTag = tag;
+    }
+
+    @Override
+    protected Bitmap doInBackground(String... ignored) {
+        Context context = mContextReference.get();
+        if (context == null) {
+            return null;
+        }
+
+        if (ImageUtils.DEBUG) Log.v(TAG, "Get image for: " + mTag);
+
+        File file = findCachedFile(context);
+
+        if (file == null) {
+            file = downloadImage(context);
+        }
+
+        if (file == null) {
+            return null;
+        }
+
+        Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
+
+        if (bitmap == null) {
+            if (ImageUtils.DEBUG) Log.w(TAG, "Error decoding bitmap: " + file.getAbsolutePath());
+            return null;
+        }
+
+        if (ImageUtils.DEBUG) Log.d(TAG, "Bitmap decoded: " + mTag + " size:" + bitmap.getWidth() + "x" + bitmap.getHeight());
+        return bitmap;
+    }
+
+    protected abstract String getImageUrl();
+
+    protected abstract File getFile(Context context, String extension);
+
+    private File findCachedFile(Context context) {
+        for (String extension : IMAGE_EXTENSIONS) {
+            File file = getFile(context, extension);
+            if (file == null) {
+                return null;
+            }
+            if (file.exists()) {
+                if (ImageUtils.DEBUG) Log.d(TAG, "Cached file found: " + file.getAbsolutePath());
+                return file;
+            }
+        }
+        return null;
+    }
+
+    private File downloadImage(Context context) {
+        String url = getImageUrl();
+        if (url == null || url.isEmpty()) {
+            if (ImageUtils.DEBUG) Log.w(TAG, "No URL received for: " + mTag);
+            return null;
+        }
+        File file = getFile(context, getExtension(url));
+        if (ImageUtils.DEBUG) Log.v(TAG, "Downloading " + url + " to " + file.getAbsolutePath());
+        ApolloUtils.downloadFile(url, file);
+        if (file.exists()) {
+            if (ImageUtils.DEBUG) Log.v(TAG, "Image downloaded: " + mTag);
+            return file;
+        }
+        if (ImageUtils.DEBUG) Log.w(TAG, "Error downloading a " + url + " to " + file.getAbsolutePath());
+        return null;
+    }
+
+    protected String getExtension(String url) {
+        for (String extension : IMAGE_EXTENSIONS) {
+            if (url.endsWith(extension))
+                return extension;
+        }
+        return EXTENSION_JPG;
+    }
+
+    @Override
+    protected void onPostExecute(Bitmap bitmap) {
+        super.onPostExecute(bitmap);
+        OnBitmapReadyListener listener = mListenerReference.get();
+        if (bitmap != null) {
+            if (listener != null) {
+                listener.bitmapReady(bitmap, mTag);
+            }
+        }
+    }
+
+    public static interface OnBitmapReadyListener {
+        public void bitmapReady(Bitmap bitmap, String tag);
+    }
+}
diff --git a/src/com/andrew/apollo/tasks/GetCachedImages.java b/src/com/andrew/apollo/tasks/GetCachedImages.java
deleted file mode 100644 (file)
index 7bd2b46..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/**\r
- * \r
- */\r
-\r
-package com.andrew.apollo.tasks;\r
-\r
-import java.lang.ref.WeakReference;\r
-\r
-import android.content.Context;\r
-import android.graphics.Bitmap;\r
-import android.os.AsyncTask;\r
-import android.widget.ImageView;\r
-\r
-import com.andrew.apollo.R;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-import com.androidquery.AQuery;\r
-\r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
-import static com.andrew.apollo.Constants.ARTIST_IMAGE_ORIGINAL;\r
-\r
-/**\r
- * @author Andrew Neal Returns a cached image for @TracksBrowser\r
- */\r
-public class GetCachedImages extends AsyncTask<String, Integer, Bitmap> {\r
-\r
-    private final Context mContext;\r
-\r
-    private final int choice;\r
-\r
-    private final WeakReference<ImageView> imageViewReference;\r
-\r
-    private final AQuery aquery;\r
-\r
-    private final ImageView mImageView;\r
-\r
-    private String url;\r
-\r
-    private WeakReference<Bitmap> bitmapReference;\r
-\r
-    private final WeakReference<Context> contextReference;\r
-\r
-    public GetCachedImages(Context c, int opt, ImageView iv) {\r
-        contextReference = new WeakReference<Context>(c);\r
-        mContext = contextReference.get();\r
-        choice = opt;\r
-        imageViewReference = new WeakReference<ImageView>(iv);\r
-        mImageView = imageViewReference.get();\r
-\r
-        // AQuery\r
-        aquery = new AQuery(mContext);\r
-    }\r
-\r
-    @Override\r
-    protected Bitmap doInBackground(String... args) {\r
-        if (choice == 0)\r
-            url = ApolloUtils.getImageURL(args[0], ARTIST_IMAGE_ORIGINAL, mContext);\r
-        if (choice == 1)\r
-            url = ApolloUtils.getImageURL(args[0], ALBUM_IMAGE, mContext);\r
-        bitmapReference = new WeakReference<Bitmap>(aquery.getCachedImage(url, 300));\r
-        return bitmapReference.get();\r
-    }\r
-\r
-    @Override\r
-    protected void onPostExecute(Bitmap result) {\r
-        if (imageViewReference != null && result != null) {\r
-            ApolloUtils.runnableBackground(mImageView, result);\r
-        } else {\r
-            result = aquery.getCachedImage(R.drawable.promo);\r
-            ApolloUtils.runnableBackground(mImageView, result);\r
-        }\r
-        super.onPostExecute(result);\r
-    }\r
-}\r
diff --git a/src/com/andrew/apollo/tasks/LastfmGetAlbumImages.java b/src/com/andrew/apollo/tasks/LastfmGetAlbumImages.java
deleted file mode 100644 (file)
index ae8d74a..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/**\r
- * \r
- */\r
-\r
-package com.andrew.apollo.tasks;\r
-\r
-import java.lang.ref.WeakReference;\r
-\r
-import android.app.Activity;\r
-import android.content.Context;\r
-import android.os.AsyncTask;\r
-import android.widget.ImageView;\r
-\r
-import com.andrew.apollo.lastfm.api.Album;\r
-import com.andrew.apollo.lastfm.api.ImageSize;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-import com.androidquery.AQuery;\r
-\r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
-import static com.andrew.apollo.Constants.LASTFM_API_KEY;\r
-\r
-/**\r
- * @author Andrew Neal\r
- * @returns A convenient image size that's perfect for a GridView.\r
- */\r
-public class LastfmGetAlbumImages extends AsyncTask<String, Integer, String> {\r
-\r
-    // URL to cache\r
-    private String url = null;\r
-\r
-    // AQuery\r
-    private final AQuery aq;\r
-\r
-    private final WeakReference<Context> contextReference;\r
-\r
-    private final WeakReference<ImageView> imageviewReference;\r
-\r
-    private final ImageView mImageView;\r
-\r
-    private final int choice;\r
-\r
-    private Album album;\r
-\r
-    public LastfmGetAlbumImages(Context context, ImageView iv, int opt) {\r
-        contextReference = new WeakReference<Context>(context);\r
-        imageviewReference = new WeakReference<ImageView>(iv);\r
-        mImageView = imageviewReference.get();\r
-        choice = opt;\r
-\r
-        // Initiate AQuery\r
-        aq = new AQuery((Activity)contextReference.get(), iv);\r
-    }\r
-\r
-    @Override\r
-    protected String doInBackground(String... name) {\r
-        if (ApolloUtils.isOnline(contextReference.get()) && name[0] != null && name[1] != null) {\r
-            try {\r
-                album = Album.getInfo(name[0], name[1], LASTFM_API_KEY);\r
-                url = album.getImageURL(ImageSize.LARGE);\r
-                aq.cache(url, 0);\r
-                ApolloUtils.setImageURL(name[1], url, ALBUM_IMAGE, contextReference.get());\r
-                return url;\r
-            } catch (Exception e) {\r
-                return null;\r
-            }\r
-        } else {\r
-            url = ApolloUtils.getImageURL(name[1], ALBUM_IMAGE, contextReference.get());\r
-        }\r
-        return url;\r
-    }\r
-\r
-    @Override\r
-    protected void onPostExecute(String result) {\r
-        if (result != null && mImageView != null && choice == 1)\r
-            new BitmapFromURL(mImageView).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, result);\r
-        super.onPostExecute(result);\r
-    }\r
-}\r
diff --git a/src/com/andrew/apollo/tasks/LastfmGetArtistImages.java b/src/com/andrew/apollo/tasks/LastfmGetArtistImages.java
deleted file mode 100644 (file)
index 2110fe5..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/**\r
- * \r
- */\r
-\r
-package com.andrew.apollo.tasks;\r
-\r
-import java.lang.ref.WeakReference;\r
-import java.util.Iterator;\r
-\r
-import android.content.Context;\r
-import android.os.AsyncTask;\r
-\r
-import com.andrew.apollo.lastfm.api.Artist;\r
-import com.andrew.apollo.lastfm.api.Image;\r
-import com.andrew.apollo.lastfm.api.ImageSize;\r
-import com.andrew.apollo.lastfm.api.PaginatedResult;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-import com.androidquery.AQuery;\r
-\r
-import static com.andrew.apollo.Constants.ARTIST_IMAGE;\r
-import static com.andrew.apollo.Constants.LASTFM_API_KEY;\r
-\r
-/**\r
- * @author Andrew Neal\r
- * @returns A convenient image size that's perfect for a GridView.\r
- */\r
-public class LastfmGetArtistImages extends AsyncTask<String, Integer, String> {\r
-\r
-    // URL to cache\r
-    private String url = null;\r
-\r
-    private PaginatedResult<Image> artist;\r
-\r
-    // AQuery\r
-    private final AQuery aq;\r
-\r
-    private final WeakReference<Context> contextReference;\r
-\r
-    public LastfmGetArtistImages(Context context) {\r
-        contextReference = new WeakReference<Context>(context);\r
-\r
-        // Initiate AQuery\r
-        aq = new AQuery(contextReference.get());\r
-    }\r
-\r
-    @Override\r
-    protected String doInBackground(String... artistname) {\r
-        if (ApolloUtils.isOnline(contextReference.get()) && artistname[0] != null) {\r
-            try {\r
-                artist = Artist.getImages(artistname[0], 1, 1, LASTFM_API_KEY);\r
-                Iterator<Image> iterator = artist.getPageResults().iterator();\r
-                while (iterator.hasNext()) {\r
-                    Image mTemp = iterator.next();\r
-                    url = mTemp.getImageURL(ImageSize.LARGESQUARE);\r
-                }\r
-                aq.cache(url, 0);\r
-                ApolloUtils.setImageURL(artistname[0], url, ARTIST_IMAGE, contextReference.get());\r
-                return url;\r
-            } catch (Exception e) {\r
-                return null;\r
-            }\r
-        } else {\r
-            url = ApolloUtils.getImageURL(artistname[0], ARTIST_IMAGE, contextReference.get());\r
-        }\r
-        return url;\r
-    }\r
-}\r
diff --git a/src/com/andrew/apollo/tasks/LastfmGetArtistImagesOriginal.java b/src/com/andrew/apollo/tasks/LastfmGetArtistImagesOriginal.java
deleted file mode 100644 (file)
index 8e38af4..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/**\r
- * \r
- */\r
-\r
-package com.andrew.apollo.tasks;\r
-\r
-import java.lang.ref.WeakReference;\r
-import java.util.Iterator;\r
-\r
-import android.content.Context;\r
-import android.os.AsyncTask;\r
-import android.widget.ImageView;\r
-\r
-import com.andrew.apollo.lastfm.api.Artist;\r
-import com.andrew.apollo.lastfm.api.Image;\r
-import com.andrew.apollo.lastfm.api.ImageSize;\r
-import com.andrew.apollo.lastfm.api.PaginatedResult;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-import com.androidquery.AQuery;\r
-\r
-import static com.andrew.apollo.Constants.ARTIST_IMAGE_ORIGINAL;\r
-import static com.andrew.apollo.Constants.LASTFM_API_KEY;\r
-\r
-/**\r
- * @author Andrew Neal\r
- * @Note This is used to display artist images in @TracksBrowser\r
- */\r
-public class LastfmGetArtistImagesOriginal extends AsyncTask<String, Integer, String> {\r
-\r
-    // URL to cache\r
-    private String url = null;\r
-\r
-    private final ImageView mImageView;\r
-\r
-    private final WeakReference<ImageView> imageviewReference;\r
-\r
-    // AQuery\r
-    private final AQuery aq;\r
-\r
-    // Context\r
-    private final Context mContext;\r
-\r
-    private final WeakReference<Context> contextReference;\r
-\r
-    public LastfmGetArtistImagesOriginal(Context context, ImageView iv) {\r
-        contextReference = new WeakReference<Context>(context);\r
-        mContext = contextReference.get();\r
-        imageviewReference = new WeakReference<ImageView>(iv);\r
-        mImageView = imageviewReference.get();\r
-\r
-        // Initiate AQuery\r
-        aq = new AQuery(mContext);\r
-    }\r
-\r
-    @Override\r
-    protected String doInBackground(String... artistname) {\r
-        if (ApolloUtils.isOnline(mContext)) {\r
-            PaginatedResult<Image> artist = Artist.getImages(artistname[0], 1, 1, LASTFM_API_KEY);\r
-            Iterator<Image> iterator = artist.getPageResults().iterator();\r
-            while (iterator.hasNext()) {\r
-                Image mTemp = iterator.next();\r
-                url = mTemp.getImageURL(ImageSize.ORIGINAL);\r
-            }\r
-            aq.cache(url, 0);\r
-            ApolloUtils.setImageURL(artistname[0], url, ARTIST_IMAGE_ORIGINAL, mContext);\r
-            return url;\r
-        } else {\r
-            url = ApolloUtils.getImageURL(artistname[0], ARTIST_IMAGE_ORIGINAL, mContext);\r
-        }\r
-        return url;\r
-    }\r
-\r
-    @Override\r
-    protected void onPostExecute(String result) {\r
-        if (result != null && mImageView != null) {\r
-            new BitmapFromURL(mImageView).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, result);\r
-        }\r
-        super.onPostExecute(result);\r
-    }\r
-}\r
diff --git a/src/com/andrew/apollo/tasks/ViewHolderQueueTask.java b/src/com/andrew/apollo/tasks/ViewHolderQueueTask.java
deleted file mode 100644 (file)
index 0357258..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/**\r
- * \r
- */\r
-\r
-package com.andrew.apollo.tasks;\r
-\r
-import java.lang.ref.WeakReference;\r
-\r
-import android.content.Context;\r
-import android.graphics.Bitmap;\r
-import android.os.AsyncTask;\r
-import android.widget.ImageView;\r
-\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-import com.andrew.apollo.views.ViewHolderQueue;\r
-import com.androidquery.AQuery;\r
-\r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
-import static com.andrew.apollo.Constants.ARTIST_IMAGE;\r
-\r
-/**\r
- * @author Andrew Neal\r
- */\r
-public class ViewHolderQueueTask extends AsyncTask<String, Integer, Bitmap> {\r
-\r
-    private final ViewHolderQueue mViewHolderQueue;\r
-\r
-    private final WeakReference<ImageView> imageViewReference;\r
-\r
-    private final Context mContext;\r
-\r
-    private final int mPosition;\r
-\r
-    private final int choice;\r
-\r
-    private final int holderChoice;\r
-\r
-    private final AQuery aquery;\r
-\r
-    private final ImageView mImageView;\r
-\r
-    private String url;\r
-\r
-    private WeakReference<Bitmap> bitmapReference;\r
-\r
-    private final WeakReference<Context> contextReference;\r
-\r
-    public ViewHolderQueueTask(ViewHolderQueue vh, int position, Context c, int opt, int holderOpt,\r
-            ImageView iv) {\r
-        mViewHolderQueue = vh;\r
-        mPosition = position;\r
-        contextReference = new WeakReference<Context>(c);\r
-        mContext = contextReference.get();\r
-        choice = opt;\r
-        holderChoice = holderOpt;\r
-        imageViewReference = new WeakReference<ImageView>(iv);\r
-        mImageView = imageViewReference.get();\r
-\r
-        // AQuery\r
-        aquery = new AQuery(mContext);\r
-    }\r
-\r
-    @Override\r
-    protected Bitmap doInBackground(String... args) {\r
-        if (choice == 0)\r
-            url = ApolloUtils.getImageURL(args[0], ARTIST_IMAGE, mContext);\r
-        if (choice == 1)\r
-            url = ApolloUtils.getImageURL(args[0], ALBUM_IMAGE, mContext);\r
-        bitmapReference = new WeakReference<Bitmap>(aquery.getCachedImage(url));\r
-        return bitmapReference.get();\r
-    }\r
-\r
-    @Override\r
-    protected void onPostExecute(Bitmap result) {\r
-        if (imageViewReference != null && holderChoice == 0\r
-                && mViewHolderQueue.position == mPosition && mViewHolderQueue != null)\r
-            aquery.id(mImageView).image(result);\r
-        if (imageViewReference != null && holderChoice == 1\r
-                && mViewHolderQueue.position == mPosition && mViewHolderQueue != null)\r
-            aquery.id(mImageView).image(result);\r
-        super.onPostExecute(result);\r
-    }\r
-}\r
diff --git a/src/com/andrew/apollo/tasks/ViewHolderTask.java b/src/com/andrew/apollo/tasks/ViewHolderTask.java
deleted file mode 100644 (file)
index 5468fc2..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/**\r
- * \r
- */\r
-\r
-package com.andrew.apollo.tasks;\r
-\r
-import java.lang.ref.WeakReference;\r
-\r
-import android.content.Context;\r
-import android.graphics.Bitmap;\r
-import android.os.AsyncTask;\r
-import android.widget.ImageView;\r
-\r
-import com.andrew.apollo.R;\r
-import com.andrew.apollo.utils.ApolloUtils;\r
-import com.andrew.apollo.views.ViewHolderGrid;\r
-import com.andrew.apollo.views.ViewHolderList;\r
-import com.androidquery.AQuery;\r
-\r
-import static com.andrew.apollo.Constants.ALBUM_IMAGE;\r
-import static com.andrew.apollo.Constants.ARTIST_IMAGE;\r
-\r
-/**\r
- * @author Andrew Neal\r
- */\r
-public class ViewHolderTask extends AsyncTask<String, Integer, Bitmap> {\r
-\r
-    private final ViewHolderList mViewHolderList;\r
-\r
-    private final ViewHolderGrid mViewHolderGrid;\r
-\r
-    private final WeakReference<ImageView> imageViewReference;\r
-\r
-    private final Context mContext;\r
-\r
-    private final int mPosition;\r
-\r
-    private final int choice;\r
-\r
-    private final int holderChoice;\r
-\r
-    private final AQuery aquery;\r
-\r
-    private final ImageView mImageView;\r
-\r
-    private final int albumart;\r
-\r
-    private final WeakReference<Context> contextReference;\r
-\r
-    private String url;\r
-\r
-    private WeakReference<Bitmap> bitmapReference;\r
-\r
-    public ViewHolderTask(ViewHolderList vh, ViewHolderGrid vhg, int position, Context c, int opt,\r
-            int holderOpt, ImageView iv) {\r
-        mViewHolderList = vh;\r
-        mViewHolderGrid = vhg;\r
-        mPosition = position;\r
-        contextReference = new WeakReference<Context>(c);\r
-        mContext = contextReference.get();\r
-        choice = opt;\r
-        holderChoice = holderOpt;\r
-        imageViewReference = new WeakReference<ImageView>(iv);\r
-        mImageView = imageViewReference.get();\r
-        aquery = new AQuery(mContext);\r
-\r
-        albumart = mContext.getResources().getInteger(R.integer.listview_album_art);\r
-    }\r
-\r
-    @Override\r
-    protected Bitmap doInBackground(String... args) {\r
-        if (choice == 0)\r
-            url = ApolloUtils.getImageURL(args[0], ARTIST_IMAGE, mContext);\r
-        if (choice == 1)\r
-            url = ApolloUtils.getImageURL(args[0], ALBUM_IMAGE, mContext);\r
-        bitmapReference = new WeakReference<Bitmap>(aquery.getCachedImage(url));\r
-        if (holderChoice == 0) {\r
-            return ApolloUtils.getResizedBitmap(bitmapReference.get(), albumart, albumart);\r
-        } else if (holderChoice == 1) {\r
-            return bitmapReference.get();\r
-        }\r
-        return null;\r
-    }\r
-\r
-    @Override\r
-    protected void onPostExecute(Bitmap result) {\r
-        if (result != null && imageViewReference != null && holderChoice == 0\r
-                && mViewHolderList.position == mPosition && mViewHolderList != null)\r
-            mImageView.setImageBitmap(result);\r
-        if (result != null && imageViewReference != null && holderChoice == 1\r
-                && mViewHolderGrid.position == mPosition && mViewHolderGrid != null)\r
-            mImageView.setImageBitmap(result);\r
-        super.onPostExecute(result);\r
-    }\r
-}\r
index 991c2fd..76c904c 100644 (file)
@@ -7,7 +7,6 @@ package com.andrew.apollo.ui.widgets;
 import android.app.Activity;\r
 import android.content.Context;\r
 import android.content.Intent;\r
-import android.os.AsyncTask;\r
 import android.os.RemoteException;\r
 import android.util.AttributeSet;\r
 import android.view.View;\r
@@ -21,7 +20,7 @@ import android.widget.TextView;
 import com.andrew.apollo.R;\r
 import com.andrew.apollo.activities.AudioPlayerHolder;\r
 import com.andrew.apollo.activities.QuickQueue;\r
-import com.andrew.apollo.tasks.GetCachedImages;\r
+import com.andrew.apollo.utils.ImageUtils;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 import com.andrew.apollo.utils.ThemeUtils;\r
 \r
@@ -71,9 +70,7 @@ public class BottomActionBar extends LinearLayout implements OnClickListener, On
             // Album art\r
             ImageView mAlbumArt = (ImageView)bottomActionBar\r
                     .findViewById(R.id.bottom_action_bar_album_art);\r
-\r
-            new GetCachedImages(activity, 1, mAlbumArt).executeOnExecutor(\r
-                    AsyncTask.THREAD_POOL_EXECUTOR, MusicUtils.getAlbumName());\r
+            ImageUtils.setAlbumImage(mAlbumArt, MusicUtils.getArtistName(), MusicUtils.getAlbumName());\r
 \r
             // Favorite image\r
             ImageButton mFavorite = (ImageButton)bottomActionBar\r
index dd02758..00da5b0 100644 (file)
@@ -25,8 +25,6 @@ import android.widget.Toast;
 \r
 import com.andrew.apollo.R;\r
 import com.andrew.apollo.preferences.SettingsHolder;\r
-import com.andrew.apollo.tasks.FetchAlbumImages;\r
-import com.andrew.apollo.tasks.FetchArtistImages;\r
 import com.andrew.apollo.utils.MusicUtils;\r
 \r
 /**\r
@@ -122,16 +120,12 @@ public class BottomActionBarItem extends ImageButton implements OnLongClickListe
      * something went wrong the first time around.\r
      */\r
     public void initArtistImages() {\r
-        FetchArtistImages getArtistImages = new FetchArtistImages(mContext, 1);\r
-        getArtistImages.runTask();\r
     }\r
 \r
     /**\r
      * Manually fetch all of the album art.\r
      */\r
     public void initAlbumImages() {\r
-        FetchAlbumImages getAlbumImages = new FetchAlbumImages(mContext, 1);\r
-        getAlbumImages.runTask();\r
     }\r
 \r
     /**\r
index d992cc5..92830c2 100644 (file)
@@ -4,8 +4,7 @@
 \r
 package com.andrew.apollo.utils;\r
 \r
-import java.io.IOException;\r
-import java.io.InputStream;\r
+import java.io.*;\r
 import java.net.HttpURLConnection;\r
 import java.net.URL;\r
 \r
@@ -121,32 +120,6 @@ public class ApolloUtils {
     }\r
 \r
     /**\r
-     * Sets cached image URLs\r
-     * \r
-     * @param artistName\r
-     * @param url\r
-     * @param key\r
-     * @param context\r
-     */\r
-    public static void setImageURL(String name, String url, String key, Context context) {\r
-        SharedPreferences settings = context.getSharedPreferences(key, 0);\r
-        SharedPreferences.Editor editor = settings.edit();\r
-        editor.putString(name, url);\r
-        editor.commit();\r
-    }\r
-\r
-    /**\r
-     * @param name\r
-     * @param key\r
-     * @param context\r
-     * @return cached image URLs\r
-     */\r
-    public static String getImageURL(String name, String key, Context context) {\r
-        SharedPreferences settings = context.getSharedPreferences(key, 0);\r
-        return settings.getString(name, null);\r
-    }\r
-\r
-    /**\r
      * @param context\r
      * @return if a Tablet is the device being used\r
      */\r
@@ -166,28 +139,6 @@ public class ApolloUtils {
     }\r
 \r
     /**\r
-     * @param bitmap\r
-     * @param newHeight\r
-     * @param newWidth\r
-     * @return a scaled Bitmap\r
-     */\r
-    public static Bitmap getResizedBitmap(Bitmap bitmap, int newHeight, int newWidth) {\r
-\r
-        if (bitmap == null) {\r
-            return null;\r
-        }\r
-\r
-        int width = bitmap.getWidth();\r
-        int height = bitmap.getHeight();\r
-        float scaleWidth = ((float)newWidth) / width;\r
-        float scaleHeight = ((float)newHeight) / height;\r
-        Matrix matrix = new Matrix();\r
-        matrix.postScale(scaleWidth, scaleHeight);\r
-        Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);\r
-        return resizedBitmap;\r
-    }\r
-\r
-    /**\r
      * Header used in the track browser\r
      * \r
      * @param fragment\r
@@ -280,22 +231,55 @@ public class ApolloUtils {
     }\r
 \r
     /**\r
-     * @param src\r
-     * @return Bitmap fro URL\r
+     * Replace the characters not allowed in file names with underscore\r
+     * @param name\r
+     * @return\r
      */\r
-    public static Bitmap getBitmapFromURL(String src) {\r
+    public static String escapeForFileSystem(String name) {\r
+        return name.replaceAll("[\\\\/:*?\"<>|]+", "_");\r
+    }\r
+\r
+    /**\r
+     * Static utility function to download the file from the specified URL to the specified file.\r
+     * @param urlString\r
+     * @param outFile\r
+     * @return true if the download succeeded false otherwise\r
+     */\r
+    public static boolean downloadFile(String urlString, File outFile) {\r
+        HttpURLConnection urlConnection = null;\r
+        BufferedOutputStream out = null;\r
+\r
         try {\r
-            URL url = new URL(src);\r
-            HttpURLConnection connection = (HttpURLConnection)url.openConnection();\r
-            connection.setDoInput(true);\r
-            connection.connect();\r
-            InputStream input = connection.getInputStream();\r
-            Bitmap myBitmap = BitmapFactory.decodeStream(input);\r
-            return myBitmap;\r
-        } catch (IOException e) {\r
-            e.printStackTrace();\r
-            return null;\r
+            File dir = outFile.getParentFile();\r
+            if (!dir.exists() && !dir.mkdirs())\r
+                return false;\r
+\r
+            final URL url = new URL(urlString);\r
+            urlConnection = (HttpURLConnection) url.openConnection();\r
+            final InputStream in =\r
+                    new BufferedInputStream(urlConnection.getInputStream());\r
+            out = new BufferedOutputStream(new FileOutputStream(outFile));\r
+\r
+            int b;\r
+            while ((b = in.read()) != -1) {\r
+                out.write(b);\r
+            }\r
+\r
+        } catch (final IOException e) {\r
+            return false;\r
+        } finally {\r
+            if (urlConnection != null) {\r
+                urlConnection.disconnect();\r
+            }\r
+            if (out != null) {\r
+                try {\r
+                    out.close();\r
+                } catch (final IOException e) {\r
+                    return false;\r
+                }\r
+            }\r
         }\r
+        return true;\r
     }\r
 \r
     /**\r
diff --git a/src/com/andrew/apollo/utils/ImageCache.java b/src/com/andrew/apollo/utils/ImageCache.java
new file mode 100644 (file)
index 0000000..31ee9d4
--- /dev/null
@@ -0,0 +1,22 @@
+package com.andrew.apollo.utils;
+
+import android.graphics.Bitmap;
+import android.util.LruCache;
+
+public class ImageCache extends LruCache<String, Bitmap> {
+
+    public final static int DEFAULT_SIZE = 1024 * 1024 * 16;
+
+    public ImageCache(int maxSize) {
+        super(maxSize);
+    }
+
+    /**
+     * Measure item size in bytes rather than units which is more practical for a bitmap
+     * cache
+     */
+    @Override
+    protected int sizeOf(String key, Bitmap bitmap) {
+        return bitmap.getByteCount();
+    }
+}
diff --git a/src/com/andrew/apollo/utils/ImageProvider.java b/src/com/andrew/apollo/utils/ImageProvider.java
new file mode 100644 (file)
index 0000000..656043c
--- /dev/null
@@ -0,0 +1,112 @@
+package com.andrew.apollo.utils;
+
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.TransitionDrawable;
+import android.os.AsyncTask;
+import android.widget.ImageView;
+import com.andrew.apollo.R;
+import com.andrew.apollo.tasks.GetAlbumImageTask;
+import com.andrew.apollo.tasks.GetArtistImageTask;
+import com.andrew.apollo.tasks.GetBitmapTask;
+
+import java.util.*;
+
+public class ImageProvider implements GetBitmapTask.OnBitmapReadyListener {
+
+    private ImageCache memCache = new ImageCache(ImageCache.DEFAULT_SIZE);
+
+    private Map<String, Set<ImageView>> pendingImagesMap = new HashMap<String, Set<ImageView>>();
+
+    private Set<String> unavailable = new HashSet<String>();
+
+    public ImageProvider() {
+
+    }
+
+    public void setArtistImage(ImageView imageView, String artist) {
+        String tag = getArtistTag(artist);
+        if (!setCachedBitmap(imageView, tag)) {
+            asyncLoad(tag, imageView, new GetArtistImageTask(artist, this, tag, imageView.getContext()));
+        }
+    }
+
+    public void setAlbumImage(ImageView imageView, String artist, String album) {
+        String tag = getAlbumTag(artist, album);
+        if (!setCachedBitmap(imageView, tag)) {
+            asyncLoad(tag, imageView, new GetAlbumImageTask(artist, album, this, tag, imageView.getContext()));
+        }
+    }
+
+    private boolean setCachedBitmap(ImageView imageView, String tag) {
+        if (unavailable.contains(tag)) {
+            handleBitmapUnavailable(imageView, tag);
+            return true;
+        }
+        Bitmap bitmap = memCache.get(tag);
+        if (bitmap == null)
+            return false;
+        imageView.setTag(tag);
+        imageView.setImageBitmap(bitmap);
+        return true;
+    }
+
+    private void handleBitmapUnavailable(ImageView imageView, String tag) {
+        imageView.setTag(tag);
+        imageView.setImageDrawable(null);
+    }
+
+    private void setLoadedBitmap(ImageView imageView, Bitmap bitmap, String tag) {
+        if (!tag.equals(imageView.getTag()))
+            return;
+
+        final TransitionDrawable transition = new TransitionDrawable(new Drawable[]{
+                new ColorDrawable(android.R.color.transparent),
+                new BitmapDrawable(imageView.getResources(), bitmap)
+        });
+
+        imageView.setImageDrawable(transition);
+        final int duration = imageView.getResources().getInteger(R.integer.image_fade_in_duration);
+        transition.startTransition(duration);
+    }
+
+    private void asyncLoad(String tag, ImageView imageView, GetBitmapTask task) {
+        Set<ImageView> pendingImages = pendingImagesMap.get(tag);
+        if (pendingImages == null) {
+            pendingImages = Collections.newSetFromMap(new WeakHashMap<ImageView, Boolean>()); // create weak set
+            pendingImagesMap.put(tag, pendingImages);
+            task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        }
+        pendingImages.add(imageView);
+        imageView.setTag(tag);
+        imageView.setImageDrawable(null);
+    }
+
+    private String getArtistTag(String artist) {
+        return artist;
+    }
+
+    private String getAlbumTag(String artist, String album) {
+        return artist + " - " + album;
+    }
+
+    @Override
+    public void bitmapReady(Bitmap bitmap, String tag) {
+        if (bitmap == null) {
+            unavailable.add(tag);
+        }
+        else
+        {
+            memCache.put(tag, bitmap);
+        }
+        Set<ImageView> pendingImages = pendingImagesMap.get(tag);
+        if (pendingImages != null) {
+            pendingImagesMap.remove(tag);
+            for (ImageView imageView : pendingImages) {
+                setLoadedBitmap(imageView, bitmap, tag);
+            }
+        }
+    }
+}
diff --git a/src/com/andrew/apollo/utils/ImageUtils.java b/src/com/andrew/apollo/utils/ImageUtils.java
new file mode 100644 (file)
index 0000000..bc81736
--- /dev/null
@@ -0,0 +1,24 @@
+package com.andrew.apollo.utils;
+
+import android.widget.ImageView;
+
+public class ImageUtils {
+
+    private static ImageProvider imageProvider;
+
+    public static final boolean DEBUG = true;
+
+    public static void setArtistImage(ImageView imageView, String artist) {
+        getImageProvider().setArtistImage(imageView, artist);
+    }
+
+    public static void setAlbumImage(ImageView imageView, String artist, String album) {
+        getImageProvider().setAlbumImage(imageView, artist, album);
+    }
+
+    private static ImageProvider getImageProvider() {
+        if (imageProvider == null)
+            imageProvider = new ImageProvider();
+        return imageProvider;
+    }
+}
index cce2fc6..335e6b9 100644 (file)
@@ -22,8 +22,6 @@ public class ViewHolderGrid {
 \r
     public final TextView mViewHolderLineTwo;\r
 \r
-    public int position;\r
-\r
     public final LinearLayout mInfoHolder;\r
 \r
     public ViewHolderGrid(View view) {\r
index 5ceb08a..444d7e8 100644 (file)
@@ -24,8 +24,6 @@ public class ViewHolderList {
 \r
     public final TextView mViewHolderLineTwo;\r
 \r
-    public int position;\r
-\r
     public final FrameLayout mQuickContext;\r
 \r
     public ViewHolderList(View view) {\r
index f998553..54cde13 100644 (file)
@@ -21,8 +21,6 @@ public class ViewHolderQueue {
 \r
     public final TextView mTrackName;\r
 \r
-    public int position;\r
-\r
     public ViewHolderQueue(View view) {\r
         mArtistImage = (ImageView)view.findViewById(R.id.queue_artist_image);\r
         mAlbumArt = (ImageView)view.findViewById(R.id.queue_album_art);\r