Further progress with glide

This commit is contained in:
Karim Abou Zeid 2016-01-02 16:28:13 +01:00
commit d776926510
16 changed files with 160 additions and 542 deletions

View file

@ -125,7 +125,6 @@ dependencies {
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.okhttp:okhttp:2.7.0'
compile 'com.github.kabouzeid:Android-Universal-Image-Loader:1.9.5'
compile 'com.jakewharton:butterknife:7.0.1'
compile 'org.solovyev.android.views:linear-layout-manager:0.5@aar'
//noinspection GradleDynamicVersion

View file

@ -3,11 +3,6 @@ package com.kabouzeid.gramophone;
import android.app.Application;
import com.crashlytics.android.Crashlytics;
import com.kabouzeid.gramophone.imageloader.PhonographExecutor;
import com.kabouzeid.gramophone.imageloader.PhonographImageDownloader;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.utils.L;
import io.fabric.sdk.android.Fabric;
@ -24,12 +19,5 @@ public class App extends Application {
super.onCreate();
if (!BuildConfig.DEBUG) Fabric.with(this, new Crashlytics());
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this)
.imageDownloader(new PhonographImageDownloader(this))
.taskExecutor(new PhonographExecutor())
.build();
ImageLoader.getInstance().init(config);
L.writeLogs(false); // turns off UILs annoying LogCat output
}
}

View file

@ -1,5 +1,6 @@
package com.kabouzeid.gramophone.adapter.album;
import android.graphics.drawable.Drawable;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -89,9 +90,6 @@ public class AlbumAdapter extends AbsMultiSelectAdapter<AlbumAdapter.ViewHolder,
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
final Album album = dataSet.get(position);
final int defaultBarColor = ColorUtil.resolveColor(activity, R.attr.default_bar_color);
setColors(defaultBarColor, holder);
final boolean isChecked = isChecked(album);
holder.itemView.setActivated(isChecked);
if (holder.selectedIndicator != null) {
@ -130,6 +128,12 @@ public class AlbumAdapter extends AbsMultiSelectAdapter<AlbumAdapter.ViewHolder,
.error(R.drawable.default_album_art)
.animate(android.R.anim.fade_in)
.into(new PhonographColoredTarget(holder.image) {
@Override
public void onLoadCleared(Drawable placeholder) {
super.onLoadCleared(placeholder);
setColors(getDefaultBarColor(), holder);
}
@Override
public void onColorReady(int color) {
if (usePalette)

View file

@ -1,5 +1,6 @@
package com.kabouzeid.gramophone.adapter.artist;
import android.graphics.drawable.Drawable;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -126,6 +127,12 @@ public class ArtistAdapter extends AbsMultiSelectAdapter<ArtistAdapter.ViewHolde
.error(R.drawable.default_album_art)
.animate(android.R.anim.fade_in)
.into(new PhonographColoredTarget(holder.image) {
@Override
public void onLoadCleared(Drawable placeholder) {
super.onLoadCleared(placeholder);
setColors(getDefaultBarColor(), holder);
}
@Override
public void onColorReady(int color) {
if (usePalette)

View file

@ -15,6 +15,8 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.afollestad.materialcab.MaterialCab;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog;
import com.kabouzeid.gramophone.dialogs.DeleteSongsDialog;
@ -24,9 +26,6 @@ import com.kabouzeid.gramophone.interfaces.CabHolder;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import java.util.ArrayList;
@ -34,8 +33,6 @@ import java.util.ArrayList;
* @author Karim Abou Zeid (kabouzeid)
*/
public class ArtistSongAdapter extends ArrayAdapter<Song> implements MaterialCab.Callback {
private static final int FADE_IN_TIME = 500;
@Nullable
private final CabHolder cabHolder;
private MaterialCab cab;
@ -77,16 +74,12 @@ public class ArtistSongAdapter extends ArrayAdapter<Song> implements MaterialCab
songTitle.setText(song.title);
songInfo.setText(song.albumName);
ImageLoader.getInstance().displayImage(
MusicUtil.getSongImageLoaderString(song),
albumArt,
new DisplayImageOptions.Builder()
.cacheInMemory(true)
.showImageOnFail(R.drawable.default_album_art)
.resetViewBeforeLoading(true)
.displayer(new FadeInBitmapDisplayer(FADE_IN_TIME, true, true, false))
.build()
);
Glide.with(activity)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(song.albumId))
.diskCacheStrategy(DiskCacheStrategy.NONE)
.error(R.drawable.default_album_art)
.animate(android.R.anim.fade_in)
.into(albumArt);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
albumArt.setTransitionName(activity.getString(R.string.transition_album_art));

View file

@ -1,5 +1,6 @@
package com.kabouzeid.gramophone.adapter.song;
import android.graphics.drawable.Drawable;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -89,8 +90,6 @@ public class SongAdapter extends AbsMultiSelectAdapter<SongAdapter.ViewHolder, S
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
final Song song = dataSet.get(position);
// setColors(ColorUtil.resolveColor(activity, R.attr.default_bar_color), holder);
boolean isChecked = isChecked(song);
holder.itemView.setActivated(isChecked);
if (holder.selectedIndicator != null) {
@ -130,6 +129,12 @@ public class SongAdapter extends AbsMultiSelectAdapter<SongAdapter.ViewHolder, S
.error(R.drawable.default_album_art)
.animate(android.R.anim.fade_in)
.into(new PhonographColoredTarget(holder.image) {
@Override
public void onLoadCleared(Drawable placeholder) {
super.onLoadCleared(placeholder);
setColors(getDefaultBarColor(), holder);
}
@Override
public void onColorReady(int color) {
if (usePalette)

View file

@ -7,29 +7,27 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.RemoteViews;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.target.Target;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.MainActivity;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.assist.ImageSize;
import com.nostra13.universalimageloader.core.assist.ViewScaleType;
import com.nostra13.universalimageloader.core.imageaware.NonViewAware;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import com.nostra13.universalimageloader.core.process.BitmapProcessor;
public class WidgetMedium extends AppWidgetProvider {
private static RemoteViews widgetLayout;
private static String currentAlbumArtUri;
public static void updateWidgets(@NonNull final Context context, @NonNull final Song song, boolean isPlaying) {
if (song.id == -1) return;
@ -39,7 +37,7 @@ public class WidgetMedium extends AppWidgetProvider {
widgetLayout.setTextViewText(R.id.song_secondary_information, song.artistName + " | " + song.albumName);
updateWidgetsPlayState(context, isPlaying);
loadAlbumArt(context, song);
loadAlbumCover(context, song);
}
public static void updateWidgetsPlayState(@NonNull final Context context, boolean isPlaying) {
@ -59,46 +57,44 @@ public class WidgetMedium extends AppWidgetProvider {
}
}
private static void loadAlbumArt(@NonNull final Context context, @Nullable final Song song) {
if (song != null) {
int widgetImageSize = context.getResources().getDimensionPixelSize(R.dimen.widget_medium_image_size);
currentAlbumArtUri = MusicUtil.getSongImageLoaderString(song);
ImageLoader.getInstance().displayImage(
currentAlbumArtUri,
new NonViewAware(new ImageSize(widgetImageSize, widgetImageSize), ViewScaleType.CROP),
new DisplayImageOptions.Builder()
.postProcessor(new BitmapProcessor() {
@Override
public Bitmap process(Bitmap bitmap) {
// The RemoteViews might wants to recycle the bitmaps thrown at it, so we need
// to make sure not to hand out our cache copy
Bitmap.Config config = bitmap.getConfig();
if (config == null) {
config = Bitmap.Config.ARGB_8888;
}
bitmap = bitmap.copy(config, false);
return bitmap.copy(bitmap.getConfig(), true);
}
}).build(),
new SimpleImageLoadingListener() {
@Override
public void onLoadingComplete(String imageUri, View view, @Nullable Bitmap loadedImage) {
if (currentAlbumArtUri.equals(imageUri)) {
setAlbumArt(context, loadedImage);
}
}
private static Handler uiThreadHandler;
private static Target<Bitmap> target;
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
if (currentAlbumArtUri.equals(imageUri)) {
setAlbumArt(context, null);
}
}
});
private static void loadAlbumCover(@NonNull final Context context, @Nullable final Song song) {
if (song == null) return;
if (uiThreadHandler == null) {
uiThreadHandler = new Handler(Looper.getMainLooper());
}
if (target == null) {
int widgetImageSize = context.getResources().getDimensionPixelSize(R.dimen.widget_medium_image_size);
target = new SimpleTarget<Bitmap>(widgetImageSize, widgetImageSize) {
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
super.onLoadFailed(e, errorDrawable);
setAlbumCover(context, null);
}
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
setAlbumCover(context, resource);
}
};
}
uiThreadHandler.post(new Runnable() {
@Override
public void run() {
Glide.with(context)
.loadFromMediaStore(MusicUtil.getAlbumArtUri(song.albumId))
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(target);
}
});
}
private static void setAlbumArt(@NonNull final Context context, @Nullable final Bitmap albumArt) {
private static void setAlbumCover(@NonNull final Context context, @Nullable final Bitmap albumArt) {
if (albumArt != null) {
widgetLayout.setImageViewBitmap(R.id.image, albumArt);
} else {

View file

@ -26,7 +26,7 @@ public abstract class PhonographColoredTarget extends BitmapPaletteTarget {
onColorReady(ColorUtil.getColor(resource.getPalette(), getDefaultBarColor()));
}
private int getDefaultBarColor() {
protected int getDefaultBarColor() {
return ColorUtil.resolveColor(getView().getContext(), R.attr.default_bar_color);
}

View file

@ -86,8 +86,8 @@ public class PlayingNotificationHelper {
service.stopForeground(true);
return;
}
this.isColored = isColored;
currentSong = song;
this.isColored = isColored;
this.isPlaying = service.isPlaying();
notificationLayout = new RemoteViews(service.getPackageName(), R.layout.notification);
@ -179,19 +179,15 @@ public class PlayingNotificationHelper {
}
private void setUpCollapsedLayout() {
if (currentSong != null) {
notificationLayout.setTextViewText(R.id.title, currentSong.title);
notificationLayout.setTextViewText(R.id.text, currentSong.artistName);
notificationLayout.setTextViewText(R.id.text2, currentSong.albumName);
}
notificationLayout.setTextViewText(R.id.title, currentSong.title);
notificationLayout.setTextViewText(R.id.text, currentSong.artistName);
notificationLayout.setTextViewText(R.id.text2, currentSong.albumName);
}
private void setUpExpandedLayout() {
if (currentSong != null) {
notificationLayoutBig.setTextViewText(R.id.title, currentSong.title);
notificationLayoutBig.setTextViewText(R.id.text, currentSong.artistName);
notificationLayoutBig.setTextViewText(R.id.text2, currentSong.albumName);
}
notificationLayoutBig.setTextViewText(R.id.title, currentSong.title);
notificationLayoutBig.setTextViewText(R.id.text, currentSong.artistName);
notificationLayoutBig.setTextViewText(R.id.text2, currentSong.albumName);
}
private void loadAlbumArt() {
@ -203,7 +199,6 @@ public class PlayingNotificationHelper {
.asBitmap()
.transcode(new BitmapPaletteTranscoder(service), BitmapPaletteWrapper.class)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.error(R.drawable.default_album_art)
.into(target);
}
});

View file

@ -1,124 +0,0 @@
package com.kabouzeid.gramophone.imageloader;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RSRuntimeException;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import com.kabouzeid.gramophone.BuildConfig;
import com.kabouzeid.gramophone.helper.StackBlur;
import com.kabouzeid.gramophone.util.ImageUtil;
import com.nostra13.universalimageloader.core.process.BitmapProcessor;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class BlurProcessor implements BitmapProcessor {
public static final float DEFAULT_BLUR_RADIUS = 5f;
private Context context;
private final float blurRadius;
private final int sampling;
private BlurProcessor(Builder builder) {
this.context = builder.context;
this.blurRadius = builder.blurRadius;
this.sampling = builder.sampling;
}
// Something here seems to cause a memory leak... Go into LeakCanary for more details.
@Override
public Bitmap process(Bitmap bitmap) {
int sampling;
if (this.sampling == 0) {
sampling = ImageUtil.calculateInSampleSize(bitmap.getWidth(), bitmap.getHeight(), 100);
} else {
sampling = this.sampling;
}
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int scaledWidth = width / sampling;
int scaledHeight = height / sampling;
Bitmap out = Bitmap.createBitmap(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(out);
canvas.scale(1 / (float) sampling, 1 / (float) sampling);
Paint paint = new Paint();
paint.setFlags(Paint.FILTER_BITMAP_FLAG);
canvas.drawBitmap(bitmap, 0, 0, paint);
if (Build.VERSION.SDK_INT > 16) {
try {
final RenderScript rs = RenderScript.create(context.getApplicationContext());
final Allocation input = Allocation.createFromBitmap(rs, out, Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
final Allocation output = Allocation.createTyped(rs, input.getType());
final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setRadius(blurRadius);
script.setInput(input);
script.forEach(output);
output.copyTo(out);
rs.destroy();
return out;
} catch (RSRuntimeException e) {
// on some devices RenderScript.create() throws: android.support.v8.renderscript.RSRuntimeException: Error loading libRSSupport library
if (BuildConfig.DEBUG) e.printStackTrace();
}
}
return StackBlur.blur(out, blurRadius);
}
public static class Builder {
private Context context;
private float blurRadius = DEFAULT_BLUR_RADIUS;
private int sampling;
public Builder(@NonNull Context context) {
this.context = context;
}
/**
* @param blurRadius The radius to use. Must be between 0 and 25. Default is 5.
* @return the same Builder
*/
public Builder blurRadius(@FloatRange(from = 0.0f, to = 25.0f) float blurRadius) {
this.blurRadius = blurRadius;
return this;
}
/**
* @param sampling The inSampleSize to use. Must be a power of 2, or 1 for no down sampling or 0 for auto detect sampling. Default is 0.
* @return the same Builder
*/
public Builder sampling(int sampling) {
this.sampling = sampling;
return this;
}
public Builder fromPrototype(BlurProcessor prototype) {
context = prototype.context;
blurRadius = prototype.blurRadius;
sampling = prototype.sampling;
return this;
}
public BlurProcessor build() {
return new BlurProcessor(this);
}
}
}

View file

@ -1,68 +0,0 @@
package com.kabouzeid.gramophone.imageloader;
import android.support.annotation.NonNull;
import com.nostra13.universalimageloader.core.DefaultConfigurationFactory;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.LoadAndDisplayImageTask;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.download.ImageDownloader;
import java.io.File;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* A custom {@link Executor} meant for kabouzeid's fork of nostra13's Android Universal Image Loader (https://github.com/kabouzeid/Android-Universal-Image-Loader).
* This {@link Executor} separates network and disk loading tasks into different executors so the network image loading doesn't block the disk image loading which is in most cases much faster.
* <p/>
* Maybe there is a better solution for this with a single (ThreadPool-)Executor, but I'm lacking experience here.
*
* @author Karim Abou Zeid (kabouzeid)
*/
public class PhonographExecutor implements Executor {
public static final String TAG = PhonographExecutor.class.getSimpleName();
private static final int SECONDARY_THREAD_COUNT = 1; // must be more than ImageLoaderConfiguration.Builder.DEFAULT_THREAD_POOL_SIZE
private ThreadPoolExecutor primaryExecutor;
private ThreadPoolExecutor secondaryExecutor;
public PhonographExecutor() {
primaryExecutor = (ThreadPoolExecutor) DefaultConfigurationFactory.createExecutor(
ImageLoaderConfiguration.Builder.DEFAULT_THREAD_POOL_SIZE - SECONDARY_THREAD_COUNT,
ImageLoaderConfiguration.Builder.DEFAULT_THREAD_PRIORITY,
ImageLoaderConfiguration.Builder.DEFAULT_TASK_PROCESSING_TYPE
);
secondaryExecutor = (ThreadPoolExecutor) DefaultConfigurationFactory.createExecutor(
SECONDARY_THREAD_COUNT,
ImageLoaderConfiguration.Builder.DEFAULT_THREAD_PRIORITY,
QueueProcessingType.FIFO
);
}
@Override
public void execute(@NonNull Runnable command) {
if (command instanceof LoadAndDisplayImageTask) {
String uri = ((LoadAndDisplayImageTask) command).getLoadingUri();
switch (ImageDownloader.Scheme.ofUri(uri)) {
case HTTP:
case HTTPS:
File imageFile = ImageLoader.getInstance().getDiskCache().get(uri);
if (imageFile == null || !imageFile.exists() || imageFile.length() <= 0) {
// the image is not yet in the disk cache
secondaryExecutor.execute(command);
return;
}
}
}
if (secondaryExecutor.getActiveCount() < secondaryExecutor.getPoolSize()) {
// if the secondary executor got unused threads left, use them!
secondaryExecutor.execute(command);
} else {
primaryExecutor.execute(command);
}
}
}

View file

@ -1,121 +0,0 @@
package com.kabouzeid.gramophone.imageloader;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.kabouzeid.gramophone.lastfm.rest.LastFMRestClient;
import com.kabouzeid.gramophone.lastfm.rest.model.LastFmArtist;
import com.kabouzeid.gramophone.loader.AlbumSongLoader;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.LastFMUtil;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.AudioFileIO;
import org.jaudiotagger.tag.images.Artwork;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Locale;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class PhonographImageDownloader extends BaseImageDownloader {
public static final String SCHEME_ALBUM = "album://";
public static final String SCHEME_SONG = "song://";
public static final String SCHEME_ARTIST = Scheme.HTTP.wrap("artist://");
private final LastFMRestClient lastFMRestClient;
public PhonographImageDownloader(@NonNull Context context) {
super(context);
lastFMRestClient = new LastFMRestClient(context);
}
@Nullable
@Override
public InputStream getStream(@NonNull String imageUri, Object extra) throws IOException {
if (imageUri.toLowerCase(Locale.US).startsWith(SCHEME_ALBUM)) {
return getStreamFromAlbum(imageUri);
}
if (imageUri.toLowerCase(Locale.US).startsWith(SCHEME_SONG)) {
return getStreamFromSong(imageUri);
}
if (imageUri.toLowerCase(Locale.US).startsWith(SCHEME_ARTIST)) {
return getStreamFromArtist(imageUri, extra);
}
return super.getStream(imageUri, extra);
}
@Nullable
protected InputStream getStreamFromArtist(@NonNull String imageUri, @NonNull Object extra) throws IOException {
String[] data = imageUri.substring(SCHEME_ARTIST.length()).split("#", 2);
String artistName = data[1];
if (MusicUtil.isArtistNameUnknown(artistName)) {
return super.getStream("", extra);
}
LastFmArtist lastFmArtist = lastFMRestClient.getApiService().getArtistInfo(artistName, data[0].equals("") ? null : data[0]).execute().body();
return super.getStream(LastFMUtil.getLargestArtistImageUrl(lastFmArtist.getArtist().getImage()), extra);
}
@Nullable
protected InputStream getStreamFromAlbum(@NonNull String imageUri) throws IOException {
int albumId = Integer.valueOf(imageUri.substring(SCHEME_ALBUM.length()));
if (PreferenceUtil.getInstance(context).ignoreMediaStoreArtwork()) {
ArrayList<Song> songs = AlbumSongLoader.getAlbumSongList(context, albumId);
for (Song song : songs) {
byte[] albumCover = getAlbumCoverBinaryData(new File(song.data));
if (albumCover != null) {
return new ByteArrayInputStream(albumCover);
}
}
}
return getMediaProviderAlbumArtInputStream(albumId);
}
@Nullable
protected InputStream getStreamFromSong(@NonNull String imageUri) throws IOException {
String[] data = imageUri.substring(SCHEME_SONG.length()).split("#", 2);
if (PreferenceUtil.getInstance(context).ignoreMediaStoreArtwork()) {
byte[] albumCover = getAlbumCoverBinaryData(new File(data[1]));
if (albumCover != null) {
return new ByteArrayInputStream(albumCover);
}
}
int id = Integer.parseInt(data[0]);
return getMediaProviderAlbumArtInputStream(id);
}
@Nullable
private static byte[] getAlbumCoverBinaryData(File song) {
try {
AudioFile audioFile = AudioFileIO.read(song);
Artwork artwork = audioFile.getTagOrCreateAndSetDefault().getFirstArtwork();
if (artwork != null) {
return artwork.getBinaryData();
}
} catch (@NonNull Exception e) {
e.printStackTrace();
}
return null;
}
@Nullable
private InputStream getMediaProviderAlbumArtInputStream(int albumId) throws
FileNotFoundException {
return context.getContentResolver().openInputStream(MusicUtil.getAlbumArtUri(albumId));
}
}

View file

@ -19,6 +19,7 @@ import android.view.MenuItem;
import android.view.View;
import com.afollestad.materialdialogs.color.ColorChooserDialog;
import com.bumptech.glide.Glide;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.prefs.ColorChooserPreference;
import com.kabouzeid.gramophone.ui.activities.base.AbsBaseActivity;
@ -26,7 +27,6 @@ import com.kabouzeid.gramophone.util.ColorUtil;
import com.kabouzeid.gramophone.util.NavigationUtil;
import com.kabouzeid.gramophone.util.PreferenceUtil;
import com.kabouzeid.gramophone.util.ViewUtil;
import com.nostra13.universalimageloader.core.ImageLoader;
import butterknife.Bind;
import butterknife.ButterKnife;
@ -198,7 +198,7 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia
ignoreMediaStoreArtwork.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
ImageLoader.getInstance().clearMemoryCache();
Glide.get(getActivity()).clearMemory();
return true;
}
});

View file

@ -14,7 +14,6 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.graphics.Palette;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
@ -25,7 +24,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.util.DialogUtils;
import com.bumptech.glide.Glide;
import com.github.ksoichiro.android.observablescrollview.ObservableScrollView;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.misc.SimpleObservableScrollViewCallbacks;
@ -120,7 +119,6 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
}
private void setUpViews() {
resetColors();
setUpScrollView();
setUpFab();
setUpImageView();
@ -200,19 +198,6 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
protected abstract void save();
private void resetColors() {
paletteColorPrimary = getThemeColorPrimary();
observableScrollViewCallbacks.onScrollChanged(observableScrollView.getCurrentScrollY(), false, false);
setStatusBarColor(paletteColorPrimary);
if (shouldColorNavigationBar())
setNavigationBarColor(paletteColorPrimary);
header.setBackgroundColor(paletteColorPrimary);
boolean darkContent = ColorUtil.useDarkTextColorOnBackground(paletteColorPrimary);
ViewUtil.setToolbarContentDark(this, toolbar, darkContent);
setUseDarkStatusBarIcons(darkContent);
notifyTaskColorChange(paletteColorPrimary);
}
private void getIntentExtras() {
Bundle intentExtras = getIntent().getExtras();
if (intentExtras != null) {
@ -288,43 +273,22 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
fab.setEnabled(true);
}
protected void setImageRes(int resId) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), resId);
setImageBitmap(bitmap);
protected void setImageBitmap(@Nullable final Bitmap bitmap, int bgColor) {
image.setImageBitmap(bitmap);
setColors(bgColor);
}
protected void setImageBitmap(@Nullable final Bitmap bitmap) {
if (bitmap != null) {
image.setImageBitmap(bitmap);
applyPalette(bitmap);
} else {
resetColors();
}
}
private void applyPalette(@NonNull final Bitmap bitmap) {
Palette.from(bitmap)
.resizeBitmapSize(100)
.generate(new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(@NonNull Palette palette) {
final Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
if (vibrantSwatch != null) {
paletteColorPrimary = palette.getVibrantColor(DialogUtils.resolveColor(AbsTagEditorActivity.this, R.attr.default_bar_color));
observableScrollViewCallbacks.onScrollChanged(observableScrollView.getCurrentScrollY(), false, false);
if (shouldColorNavigationBar())
setNavigationBarColor(paletteColorPrimary);
setStatusBarColor(paletteColorPrimary);
header.setBackgroundColor(paletteColorPrimary);
boolean darkContent = ColorUtil.useDarkTextColorOnBackground(paletteColorPrimary);
ViewUtil.setToolbarContentDark(AbsTagEditorActivity.this, toolbar, darkContent);
setUseDarkStatusBarIcons(darkContent);
notifyTaskColorChange(paletteColorPrimary);
} else {
resetColors();
}
}
});
private void setColors(int color) {
paletteColorPrimary = color;
observableScrollViewCallbacks.onScrollChanged(observableScrollView.getCurrentScrollY(), false, false);
if (shouldColorNavigationBar())
setNavigationBarColor(paletteColorPrimary);
setStatusBarColor(paletteColorPrimary);
header.setBackgroundColor(paletteColorPrimary);
boolean darkContent = ColorUtil.useDarkTextColorOnBackground(paletteColorPrimary);
ViewUtil.setToolbarContentDark(AbsTagEditorActivity.this, toolbar, darkContent);
setUseDarkStatusBarIcons(darkContent);
notifyTaskColorChange(paletteColorPrimary);
}
@Override
@ -390,6 +354,9 @@ public abstract class AbsTagEditorActivity extends AbsBaseActivity {
});
if (deleteArtwork) {
MusicUtil.deleteAlbumArt(AbsTagEditorActivity.this, getId());
Glide.get(AbsTagEditorActivity.this).clearMemory();
} else if (artwork != null) {
Glide.get(AbsTagEditorActivity.this).clearMemory();
}
rescanMediaAndQuitOnFinish();
}

View file

@ -1,29 +1,33 @@
package com.kabouzeid.gramophone.ui.activities.tageditor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.glide.palette.BitmapPaletteTranscoder;
import com.kabouzeid.gramophone.glide.palette.BitmapPaletteWrapper;
import com.kabouzeid.gramophone.lastfm.rest.LastFMRestClient;
import com.kabouzeid.gramophone.lastfm.rest.model.LastFmAlbum;
import com.kabouzeid.gramophone.loader.AlbumSongLoader;
import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.util.ColorUtil;
import com.kabouzeid.gramophone.util.LastFMUtil;
import com.kabouzeid.gramophone.util.MusicUtil;
import com.kabouzeid.gramophone.util.Util;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import com.nostra13.universalimageloader.core.process.BitmapProcessor;
import org.jaudiotagger.tag.FieldKey;
import org.jaudiotagger.tag.images.Artwork;
@ -88,7 +92,8 @@ public class AlbumTagEditorActivity extends AbsTagEditorActivity implements Text
@Override
protected void loadCurrentImage() {
setImageBitmap(getAlbumArt());
Bitmap bitmap = getAlbumArt();
setImageBitmap(bitmap, ColorUtil.getColor(ColorUtil.generatePalette(bitmap), ColorUtil.resolveColor(this, R.attr.default_bar_color)));
deleteAlbumArt = false;
}
@ -105,32 +110,36 @@ public class AlbumTagEditorActivity extends AbsTagEditorActivity implements Text
public void onResponse(final Response<LastFmAlbum> response, Retrofit retrofit) {
LastFmAlbum lastFmAlbum = response.body();
if (lastFmAlbum.getAlbum() != null) {
ImageLoader.getInstance().loadImage(LastFMUtil.getLargestAlbumImageUrl(lastFmAlbum.getAlbum().getImage()),
new DisplayImageOptions.Builder()
.preProcessor(albumCoverProcessor)
.build(),
new SimpleImageLoadingListener() {
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
if (loadedImage == null) {
onLoadingFailed(imageUri, view, null);
return;
String url = LastFMUtil.getLargestAlbumImageUrl(lastFmAlbum.getAlbum().getImage());
if (!TextUtils.isEmpty(url) && url.trim().length() > 0) {
Glide.with(AlbumTagEditorActivity.this)
.load(url)
.asBitmap()
.transcode(new BitmapPaletteTranscoder(AlbumTagEditorActivity.this), BitmapPaletteWrapper.class)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.error(R.drawable.default_album_art)
.into(new SimpleTarget<BitmapPaletteWrapper>() {
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
super.onLoadFailed(e, errorDrawable);
e.printStackTrace();
Toast.makeText(AlbumTagEditorActivity.this, e.toString(), Toast.LENGTH_LONG).show();
}
albumArtBitmap = loadedImage;
setImageBitmap(albumArtBitmap);
deleteAlbumArt = false;
dataChanged();
setResult(RESULT_OK);
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
handleFailReason(failReason);
}
});
} else {
toastLoadingFailed();
@Override
public void onResourceReady(BitmapPaletteWrapper resource, GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
ColorUtil.getColor(resource.getPalette(), Color.TRANSPARENT);
albumArtBitmap = resource.getBitmap();
setImageBitmap(albumArtBitmap, ColorUtil.getColor(resource.getPalette(), ColorUtil.resolveColor(AlbumTagEditorActivity.this, R.attr.default_bar_color)));
deleteAlbumArt = false;
dataChanged();
setResult(RESULT_OK);
}
});
return;
}
}
toastLoadingFailed();
}
@Override
@ -152,7 +161,7 @@ public class AlbumTagEditorActivity extends AbsTagEditorActivity implements Text
@Override
protected void deleteImage() {
setImageRes(R.drawable.default_album_art);
setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.default_album_art), ColorUtil.resolveColor(this, R.attr.default_bar_color));
deleteAlbumArt = true;
dataChanged();
}
@ -200,23 +209,28 @@ public class AlbumTagEditorActivity extends AbsTagEditorActivity implements Text
@Override
protected void loadImageFromFile(@NonNull final Uri selectedFileUri) {
ImageLoader.getInstance().loadImage(selectedFileUri.toString(),
new DisplayImageOptions.Builder()
.preProcessor(albumCoverProcessor)
.build(),
new SimpleImageLoadingListener() {
Glide.with(AlbumTagEditorActivity.this)
.load(selectedFileUri)
.asBitmap()
.transcode(new BitmapPaletteTranscoder(AlbumTagEditorActivity.this), BitmapPaletteWrapper.class)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(new SimpleTarget<BitmapPaletteWrapper>() {
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
albumArtBitmap = loadedImage;
setImageBitmap(albumArtBitmap);
deleteAlbumArt = false;
dataChanged();
setResult(RESULT_OK);
public void onLoadFailed(Exception e, Drawable errorDrawable) {
super.onLoadFailed(e, errorDrawable);
e.printStackTrace();
Toast.makeText(AlbumTagEditorActivity.this, e.toString(), Toast.LENGTH_LONG).show();
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
handleFailReason(failReason);
public void onResourceReady(BitmapPaletteWrapper resource, GlideAnimation<? super BitmapPaletteWrapper> glideAnimation) {
ColorUtil.getColor(resource.getPalette(), Color.TRANSPARENT);
albumArtBitmap = resource.getBitmap();
setImageBitmap(albumArtBitmap, ColorUtil.getColor(resource.getPalette(), ColorUtil.resolveColor(AlbumTagEditorActivity.this, R.attr.default_bar_color)));
deleteAlbumArt = false;
dataChanged();
setResult(RESULT_OK);
}
});
}
@ -236,22 +250,6 @@ public class AlbumTagEditorActivity extends AbsTagEditorActivity implements Text
dataChanged();
}
private BitmapProcessor albumCoverProcessor = new BitmapProcessor() {
@Override
public Bitmap process(Bitmap bitmap) {
return getResizedAlbumCover(bitmap, Util.getSmallerScreenSize(AlbumTagEditorActivity.this));
}
};
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
private void handleFailReason(FailReason failReason) {
Throwable cause = failReason.getCause();
if (cause != null) {
cause.printStackTrace();
Toast.makeText(AlbumTagEditorActivity.this, cause.toString(), Toast.LENGTH_LONG).show();
}
}
private static Bitmap getResizedAlbumCover(@NonNull Bitmap src, int maxForSmallerSize) {
int width = src.getWidth();
int height = src.getHeight();

View file

@ -18,10 +18,8 @@ import android.widget.Toast;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
import com.kabouzeid.gramophone.imageloader.PhonographImageDownloader;
import com.kabouzeid.gramophone.loader.PlaylistLoader;
import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.model.Album;
import com.kabouzeid.gramophone.model.Artist;
import com.kabouzeid.gramophone.model.Playlist;
import com.kabouzeid.gramophone.model.Song;
@ -36,25 +34,6 @@ import java.util.List;
public class MusicUtil {
public static final String TAG = MusicUtil.class.getSimpleName();
@NonNull
public static String getArtistImageLoaderString(@NonNull Artist artist, boolean forceDownload) {
if (forceDownload) {
return PhonographImageDownloader.SCHEME_ARTIST + "no-cache#" + artist.name;
} else {
return PhonographImageDownloader.SCHEME_ARTIST + "#" + artist.name;
}
}
@NonNull
public static String getAlbumImageLoaderString(@NonNull Album album) {
return PhonographImageDownloader.SCHEME_ALBUM + album.id;
}
@NonNull
public static String getSongImageLoaderString(@NonNull Song song) {
return PhonographImageDownloader.SCHEME_SONG + song.albumId + "#" + song.data;
}
public static Uri getAlbumArtUri(int albumId) {
final Uri sArtworkUri = Uri
.parse("content://media/external/audio/albumart");