diff --git a/src/org/kreed/vanilla/CoverBitmap.java b/src/org/kreed/vanilla/CoverBitmap.java index 2195edb6..5fe7b323 100644 --- a/src/org/kreed/vanilla/CoverBitmap.java +++ b/src/org/kreed/vanilla/CoverBitmap.java @@ -216,7 +216,6 @@ public final class CoverBitmap { int y = (bitmapHeight - coverHeight) / 2; Rect rect = new Rect(x, y, x + coverWidth, y + coverHeight); canvas.drawBitmap(cover, null, rect, paint); - cover.recycle(); } int left = (bitmapWidth - boxWidth) / 2; @@ -313,7 +312,6 @@ public final class CoverBitmap { int y = horizontal ? (bitmapHeight - coverHeight) / 2 : 0; Rect rect = new Rect(x, y, x + coverWidth, y + coverHeight); canvas.drawBitmap(cover, null, rect, paint); - cover.recycle(); } int top; @@ -382,7 +380,6 @@ public final class CoverBitmap { Rect src = new Rect(xOffset, yOffset, sourceWidth - xOffset, sourceHeight - yOffset); Rect dest = new Rect(0, 0, width, height); canvas.drawBitmap(source, src, dest, null); - source.recycle(); return bitmap; } @@ -409,9 +406,7 @@ public final class CoverBitmap { float scale = Math.min((float)width / sourceWidth, (float)height / sourceHeight); sourceWidth *= scale; sourceHeight *= scale; - Bitmap result = Bitmap.createScaledBitmap(source, sourceWidth, sourceHeight, false); - source.recycle(); - return result; + return Bitmap.createScaledBitmap(source, sourceWidth, sourceHeight, false); } /** diff --git a/src/org/kreed/vanilla/FourLongWidget.java b/src/org/kreed/vanilla/FourLongWidget.java index 4c91771e..ce688696 100644 --- a/src/org/kreed/vanilla/FourLongWidget.java +++ b/src/org/kreed/vanilla/FourLongWidget.java @@ -28,7 +28,7 @@ import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.net.Uri; +import android.graphics.Bitmap; import android.view.View; import android.widget.RemoteViews; @@ -106,11 +106,11 @@ public class FourLongWidget extends AppWidgetProvider { views.setViewVisibility(R.id.buttons, View.VISIBLE); views.setTextViewText(R.id.title, song.title); views.setTextViewText(R.id.artist, song.artist); - Uri uri = song.getCoverUri(); - if (uri == null) + Bitmap cover = song.getCover(context); + if (cover == null) views.setImageViewResource(R.id.cover, 0); else - views.setImageViewUri(R.id.cover, uri); + views.setImageViewBitmap(R.id.cover, cover); } boolean playing = (state & PlaybackService.FLAG_PLAYING) != 0; diff --git a/src/org/kreed/vanilla/FourSquareWidget.java b/src/org/kreed/vanilla/FourSquareWidget.java index 6ff038b7..b0419b49 100644 --- a/src/org/kreed/vanilla/FourSquareWidget.java +++ b/src/org/kreed/vanilla/FourSquareWidget.java @@ -28,7 +28,7 @@ import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.net.Uri; +import android.graphics.Bitmap; import android.view.View; import android.widget.RemoteViews; @@ -106,11 +106,11 @@ public class FourSquareWidget extends AppWidgetProvider { views.setViewVisibility(R.id.buttons, View.VISIBLE); views.setTextViewText(R.id.title, song.title); views.setTextViewText(R.id.artist, song.artist); - Uri uri = song.getCoverUri(); - if (uri == null) + Bitmap cover = song.getCover(context); + if (cover == null) views.setImageViewResource(R.id.cover, 0); else - views.setImageViewUri(R.id.cover, uri); + views.setImageViewBitmap(R.id.cover, cover); } boolean playing = (state & PlaybackService.FLAG_PLAYING) != 0; diff --git a/src/org/kreed/vanilla/LibraryActivity.java b/src/org/kreed/vanilla/LibraryActivity.java index fdca43cf..e73888cb 100644 --- a/src/org/kreed/vanilla/LibraryActivity.java +++ b/src/org/kreed/vanilla/LibraryActivity.java @@ -31,6 +31,7 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.database.Cursor; import android.graphics.Color; +import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.graphics.drawable.PaintDrawable; import android.net.Uri; @@ -1073,7 +1074,7 @@ public class LibraryActivity super.onSongChange(song); if (mTitle != null) { - Uri cover = null; + Bitmap cover = null; if (song == null) { mTitle.setText(R.string.none); @@ -1084,7 +1085,7 @@ public class LibraryActivity String artist = song.artist == null ? res.getString(R.string.unknown) : song.artist; mTitle.setText(title); mArtist.setText(artist); - cover = song.hasCover(this) ? song.getCoverUri() : null; + cover = song.getCover(this); } if (Song.mDisableCoverArt) @@ -1092,7 +1093,7 @@ public class LibraryActivity else if (cover == null) mCover.setImageResource(R.drawable.albumart_mp_unknown_list); else - mCover.setImageURI(cover); + mCover.setImageBitmap(cover); } } diff --git a/src/org/kreed/vanilla/OneCellWidget.java b/src/org/kreed/vanilla/OneCellWidget.java index 5fcc6035..68fa795a 100644 --- a/src/org/kreed/vanilla/OneCellWidget.java +++ b/src/org/kreed/vanilla/OneCellWidget.java @@ -29,7 +29,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.net.Uri; +import android.graphics.Bitmap; import android.widget.RemoteViews; /** @@ -108,18 +108,18 @@ public class OneCellWidget extends AppWidgetProvider { views.setOnClickPendingIntent(R.id.next, PendingIntent.getService(context, 0, next, 0)); if ((state & PlaybackService.FLAG_NO_MEDIA) != 0) { - views.setImageViewResource(R.id.cover, 0); views.setInt(R.id.title, "setText", R.string.no_songs); - } else if (song == null) { views.setImageViewResource(R.id.cover, 0); + } else if (song == null) { views.setInt(R.id.title, "setText", R.string.app_name); + views.setImageViewResource(R.id.cover, 0); } else { - Uri uri = song.getCoverUri(); - if (uri == null) + views.setTextViewText(R.id.title, song.title); + Bitmap cover = song.getCover(context); + if (cover == null) views.setImageViewResource(R.id.cover, 0); else - views.setImageViewUri(R.id.cover, uri); - views.setTextViewText(R.id.title, song.title); + views.setImageViewBitmap(R.id.cover, cover); } manager.updateAppWidget(new ComponentName(context, OneCellWidget.class), views); diff --git a/src/org/kreed/vanilla/PlaybackService.java b/src/org/kreed/vanilla/PlaybackService.java index 08e2e255..7b12307a 100644 --- a/src/org/kreed/vanilla/PlaybackService.java +++ b/src/org/kreed/vanilla/PlaybackService.java @@ -36,6 +36,7 @@ import android.content.res.TypedArray; import android.content.SharedPreferences; import android.database.ContentObserver; import android.database.Cursor; +import android.graphics.Bitmap; import android.media.AudioManager; import android.media.MediaPlayer; import android.os.Build; @@ -1437,10 +1438,11 @@ public final class PlaybackService extends Service RemoteViews views = new RemoteViews(getPackageName(), R.layout.notification); - if (!Song.mDisableCoverArt && song.hasCover(this)) { - views.setImageViewUri(R.id.icon, song.getCoverUri()); - } else { + Bitmap cover = song.getCover(this); + if (cover == null) { views.setImageViewResource(R.id.icon, R.drawable.icon); + } else { + views.setImageViewBitmap(R.id.icon, cover); } if (playing) { views.setTextViewText(R.id.title, song.title); diff --git a/src/org/kreed/vanilla/Song.java b/src/org/kreed/vanilla/Song.java index 0e61f56a..75670de4 100644 --- a/src/org/kreed/vanilla/Song.java +++ b/src/org/kreed/vanilla/Song.java @@ -32,7 +32,6 @@ import android.os.ParcelFileDescriptor; import android.provider.MediaStore; import android.util.Log; import java.io.FileDescriptor; -import java.io.FileNotFoundException; /** * Represents a Song backed by the MediaStore. Includes basic metadata and @@ -80,6 +79,11 @@ public class Song implements Comparable { MediaStore.Audio.Playlists.Members.TRACK, }; + /** + * A cache of 8 covers. + */ + private static final Cache sCoverCache = new Cache(8); + /** * If true, will not attempt to load any cover art in getCover() */ @@ -131,9 +135,10 @@ public class Song implements Comparable { public int flags; /** - * 1 if this song has cover art in the MediaStore, 0 if not, -1 if uninitialized. + * If true, this song has no cover art. If false, this song may or may not + * have cover art. */ - public int hasCover = -1; + public boolean noCover; /** * Initialize the song with the specified id. Call populate to fill fields @@ -193,42 +198,6 @@ public class Song implements Comparable { return song.id; } - /** - * Returns true if this song has cover art stored in the MediaStore. - * - * @param context A context to use to query the MediaStore - */ - public boolean hasCover(Context context) - { - if (hasCover == -1) { - Uri uri = getCoverUri(); - if (uri == null) { - hasCover = 0; - } else { - try { - hasCover = context.getContentResolver().openFileDescriptor(uri, "r") == null ? 0 : 1; - } catch (FileNotFoundException e) { - hasCover = 0; - } - } - } - return hasCover == 1; - } - - /** - * Return a URI describing where the cover art is stored, or null if this - * song has not been populated. - */ - public Uri getCoverUri() - { - // Use undocumented API to extract the cover from the media file from Eclair - // See http://android.git.kernel.org/?p=platform/packages/apps/Music.git;a=blob;f=src/com/android/music/MusicUtils.java;h=d1aea0660009940a0160cb981f381e2115768845;hb=0749a3f1c11e052f97a3ba60fd624c9283ee7331#l986 - - if (id == -1 || hasCover == 0 || mDisableCoverArt) - return null; - return Uri.parse("content://media/external/audio/media/" + id + "/albumart"); - } - private static final BitmapFactory.Options BITMAP_OPTIONS = new BitmapFactory.Options(); static { @@ -244,23 +213,34 @@ public class Song implements Comparable { */ public Bitmap getCover(Context context) { - Uri uri = getCoverUri(); - if (uri == null) + if (mDisableCoverArt || id == -1 || noCover) return null; + Bitmap cover = sCoverCache.get(id); + if (cover != null) { + return cover; + } + + Uri uri = Uri.parse("content://media/external/audio/media/" + id + "/albumart"); ContentResolver res = context.getContentResolver(); - hasCover = 0; try { ParcelFileDescriptor parcelFileDescriptor = res.openFileDescriptor(uri, "r"); if (parcelFileDescriptor != null) { - hasCover = 1; FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor(); - return BitmapFactory.decodeFileDescriptor(fileDescriptor, null, BITMAP_OPTIONS); + cover = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, BITMAP_OPTIONS); + if (cover != null) { + Bitmap discarded = sCoverCache.discardOldest(); + if (discarded != null) + discarded.recycle(); + sCoverCache.put(id, cover); + return cover; + } } } catch (Exception e) { Log.d("VanillaMusic", "Failed to load cover art for " + path, e); } + noCover = true; return null; } diff --git a/src/org/kreed/vanilla/WidgetD.java b/src/org/kreed/vanilla/WidgetD.java index 61cee4ac..3e5c78d8 100644 --- a/src/org/kreed/vanilla/WidgetD.java +++ b/src/org/kreed/vanilla/WidgetD.java @@ -28,7 +28,7 @@ import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.net.Uri; +import android.graphics.Bitmap; import android.view.View; import android.widget.RemoteViews; @@ -106,11 +106,11 @@ public class WidgetD extends AppWidgetProvider { views.setViewVisibility(R.id.buttons, View.VISIBLE); views.setTextViewText(R.id.title, song.title); views.setTextViewText(R.id.artist, song.artist); - Uri uri = song.getCoverUri(); - if (uri == null) + Bitmap cover = song.getCover(context); + if (cover == null) views.setImageViewResource(R.id.cover, 0); else - views.setImageViewUri(R.id.cover, uri); + views.setImageViewBitmap(R.id.cover, cover); } boolean playing = (state & PlaybackService.FLAG_PLAYING) != 0;