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
<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
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
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
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
\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
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
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
// Unbind\r
if (MusicUtils.mService != null)\r
MusicUtils.unbindFromService(mToken);\r
+\r
+ //TODO: clear image cache\r
+\r
super.onStop();\r
}\r
\r
\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
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
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
\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
\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
\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
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
\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
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
\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
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
\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
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
\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
// 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
\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
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
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
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
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
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
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
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
// 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
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
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
\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
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
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
\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
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
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
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
\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
mCursor = null;\r
}\r
mCursor = getCursorForId(mPlayList[mPlayPos]);\r
+ updateAlbumBitmap();\r
notifyChange(META_CHANGED);\r
updateNotification();\r
setNextTrack();\r
mCursor.close();\r
mCursor = null;\r
}\r
+ updateAlbumBitmap();\r
\r
unregisterReceiver(mIntentReceiver);\r
if (mUnmountReceiver != null) {\r
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
if (mPlayListLen == 0) {\r
mCursor.close();\r
mCursor = null;\r
+ updateAlbumBitmap();\r
notifyChange(META_CHANGED);\r
}\r
}\r
}\r
}\r
\r
+ updateAlbumBitmap();\r
+\r
// go to bookmark if needed\r
if (isPodcast()) {\r
long bookmark = getBookmark();\r
}\r
} catch (UnsupportedOperationException ex) {\r
}\r
+\r
+ updateAlbumBitmap();\r
}\r
mFileToPlay = path;\r
mPlayer.setDataSource(mFileToPlay);\r
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
}\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
if (mCursor != null) {\r
mCursor.close();\r
mCursor = null;\r
+ updateAlbumBitmap();\r
}\r
if (remove_status_icon) {\r
gotoIdleState();\r
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
}\r
}\r
\r
+ public Bitmap getAlbumBitmap() {\r
+ return mAlbumBitmap;\r
+ }\r
+\r
public String getTrackName() {\r
synchronized (this) {\r
if (mCursor == null) {\r
}\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
+++ /dev/null
-/**\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
+++ /dev/null
-/**\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
+++ /dev/null
-/**\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
--- /dev/null
+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;
+ }
+ }
+}
--- /dev/null
+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;
+ }
+ }
+}
--- /dev/null
+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);
+ }
+}
+++ /dev/null
-/**\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
+++ /dev/null
-/**\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
+++ /dev/null
-/**\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
+++ /dev/null
-/**\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
+++ /dev/null
-/**\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
+++ /dev/null
-/**\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
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
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
// 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
\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
* 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
\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
}\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
}\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
}\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
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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);
+ }
+ }
+ }
+}
--- /dev/null
+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;
+ }
+}
\r
public final TextView mViewHolderLineTwo;\r
\r
- public int position;\r
-\r
public final LinearLayout mInfoHolder;\r
\r
public ViewHolderGrid(View view) {\r
\r
public final TextView mViewHolderLineTwo;\r
\r
- public int position;\r
-\r
public final FrameLayout mQuickContext;\r
\r
public ViewHolderList(View view) {\r
\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