Fill empty space with blurred cover art

This commit is contained in:
Andrew Rabert 2018-03-28 01:35:49 -04:00
parent be1dc7d8c9
commit b1d0e91b8a
4 changed files with 85 additions and 27 deletions

View File

@ -87,6 +87,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
private TextView emptyTextView; private TextView emptyTextView;
private TextView songTitleTextView; private TextView songTitleTextView;
private ImageView albumArtImageView; private ImageView albumArtImageView;
private ImageView albumArtBackgroundView;
private RecyclerView playlistView; private RecyclerView playlistView;
private TextView positionTextView; private TextView positionTextView;
private TextView durationTextView; private TextView durationTextView;
@ -151,6 +152,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
emptyTextView = rootView.findViewById(R.id.download_empty); emptyTextView = rootView.findViewById(R.id.download_empty);
songTitleTextView = rootView.findViewById(R.id.download_song_title); songTitleTextView = rootView.findViewById(R.id.download_song_title);
albumArtImageView = rootView.findViewById(R.id.download_album_art_image); albumArtImageView = rootView.findViewById(R.id.download_album_art_image);
albumArtBackgroundView = rootView.findViewById(R.id.download_album_art_background);
positionTextView = rootView.findViewById(R.id.download_position); positionTextView = rootView.findViewById(R.id.download_position);
durationTextView = rootView.findViewById(R.id.download_duration); durationTextView = rootView.findViewById(R.id.download_duration);
statusTextView = rootView.findViewById(R.id.download_status); statusTextView = rootView.findViewById(R.id.download_status);
@ -516,6 +518,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
} }
if (currentPlaying == null && downloadService != null && currentPlaying == downloadService.getCurrentPlaying()) { if (currentPlaying == null && downloadService != null && currentPlaying == downloadService.getCurrentPlaying()) {
getImageLoader().loadBlurImage(albumArtBackgroundView, null, true, false);
getImageLoader().loadImage(albumArtImageView, null, true, false); getImageLoader().loadImage(albumArtImageView, null, true, false);
} }
@ -804,6 +807,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
if (currentPlaying != null) { if (currentPlaying != null) {
Entry song = currentPlaying.getSong(); Entry song = currentPlaying.getSong();
songTitleTextView.setText(song.getTitle()); songTitleTextView.setText(song.getTitle());
getImageLoader().loadBlurImage(albumArtBackgroundView, song, true, true);
getImageLoader().loadImage(albumArtImageView, song, true, true); getImageLoader().loadImage(albumArtImageView, song, true, true);
DownloadService downloadService = getDownloadService(); DownloadService downloadService = getDownloadService();
@ -814,6 +818,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
} }
} else { } else {
songTitleTextView.setText(null); songTitleTextView.setText(null);
getImageLoader().loadBlurImage(albumArtBackgroundView, null, true, false);
getImageLoader().loadImage(albumArtImageView, null, true, false); getImageLoader().loadImage(albumArtImageView, null, true, false);
setSubtitle(null); setSubtitle(null);
} }
@ -939,6 +944,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
@Override @Override
public void onMetadataUpdate(Entry song, int fieldChange) { public void onMetadataUpdate(Entry song, int fieldChange) {
if (song != null && albumArtImageView != null && fieldChange == DownloadService.METADATA_UPDATED_COVER_ART) { if (song != null && albumArtImageView != null && fieldChange == DownloadService.METADATA_UPDATED_COVER_ART) {
getImageLoader().loadBlurImage(albumArtBackgroundView, song, true, true);
getImageLoader().loadImage(albumArtImageView, song, true, true); getImageLoader().loadImage(albumArtImageView, song, true, true);
} }
} }

View File

@ -0,0 +1,32 @@
package net.nullsum.audinaut.util;
import android.content.Context;
import android.graphics.Bitmap;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
class BlurBuilder {
private static final float BITMAP_SCALE = 0.4f;
private static final float BLUR_RADIUS = 25f;
public static Bitmap blur(Context context, Bitmap image) {
int width = Math.round(image.getWidth() * BITMAP_SCALE);
int height = Math.round(image.getHeight() * BITMAP_SCALE);
Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);
RenderScript rs = RenderScript.create(context);
ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
theIntrinsic.setRadius(BLUR_RADIUS);
theIntrinsic.setInput(tmpIn);
theIntrinsic.forEach(tmpOut);
tmpOut.copyTo(outputBitmap);
return outputBitmap;
}
}

View File

@ -209,10 +209,19 @@ public class ImageLoader {
public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) { public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) {
int size = large ? imageSizeLarge : imageSizeDefault; int size = large ? imageSizeLarge : imageSizeDefault;
return loadImage(view, entry, large, size, crossfade); return loadImage(view, entry, large, size, crossfade, false);
} }
public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, int size, boolean crossfade) { public void loadBlurImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) {
int size = large ? imageSizeLarge : imageSizeDefault;
loadImage(view, entry, large, size, crossfade, true);
}
public void loadImage(View view, MusicDirectory.Entry entry, boolean large, int size, boolean crossfade) {
loadImage(view, entry, large, size, crossfade, false);
}
private SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, int size, boolean crossfade, boolean blur) {
// If we know this a artist, try to load artist info instead // If we know this a artist, try to load artist info instead
if (entry != null && !entry.isAlbum() && !Util.isOffline(context)) { if (entry != null && !entry.isAlbum() && !Util.isOffline(context)) {
SilentBackgroundTask task = new ArtistImageTask(view.getContext(), entry, size, large, view, crossfade); SilentBackgroundTask task = new ArtistImageTask(view.getContext(), entry, size, large, view, crossfade);
@ -229,12 +238,18 @@ public class ImageLoader {
Bitmap bitmap; Bitmap bitmap;
if (entry == null || entry.getCoverArt() == null) { if (entry == null || entry.getCoverArt() == null) {
bitmap = getUnknownImage(entry, size); bitmap = getUnknownImage(entry, size);
if (blur) {
bitmap = BlurBuilder.blur(context, bitmap);
}
setImage(view, Util.createDrawableFromBitmap(context, bitmap), crossfade); setImage(view, Util.createDrawableFromBitmap(context, bitmap), crossfade);
return null; return null;
} }
bitmap = cache.get(getKey(entry.getCoverArt(), size)); bitmap = cache.get(getKey(entry.getCoverArt(), size));
if (bitmap != null && !bitmap.isRecycled()) { if (bitmap != null && !bitmap.isRecycled()) {
if (blur) {
bitmap = BlurBuilder.blur(context, bitmap);
}
final Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); final Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap);
setImage(view, drawable, crossfade); setImage(view, drawable, crossfade);
if (large) { if (large) {
@ -246,7 +261,7 @@ public class ImageLoader {
if (!large) { if (!large) {
setImage(view, null, false); setImage(view, null, false);
} }
ImageTask task = new ViewImageTask(view.getContext(), entry, size, large, view, crossfade); ImageTask task = new ViewImageTask(view.getContext(), entry, size, large, view, crossfade, blur);
task.execute(); task.execute();
return task; return task;
} }
@ -322,14 +337,16 @@ public class ImageLoader {
private final Context mContext; private final Context mContext;
private final int mSize; private final int mSize;
private final boolean mIsNowPlaying; private final boolean mIsNowPlaying;
private final boolean mBlur;
Drawable mDrawable; Drawable mDrawable;
public ImageTask(Context context, MusicDirectory.Entry entry, int size, boolean isNowPlaying) { public ImageTask(Context context, MusicDirectory.Entry entry, int size, boolean isNowPlaying, boolean blur) {
super(context); super(context);
mContext = context; mContext = context;
mEntry = entry; mEntry = entry;
mSize = size; mSize = size;
mIsNowPlaying = isNowPlaying; mIsNowPlaying = isNowPlaying;
mBlur = blur;
} }
@Override @Override
@ -348,7 +365,9 @@ public class ImageLoader {
} else { } else {
bitmap = getUnknownImage(mEntry, mSize); bitmap = getUnknownImage(mEntry, mSize);
} }
if (mBlur) {
bitmap = BlurBuilder.blur(context, bitmap);
}
mDrawable = Util.createDrawableFromBitmap(mContext, bitmap); mDrawable = Util.createDrawableFromBitmap(mContext, bitmap);
} catch (Throwable x) { } catch (Throwable x) {
Log.e(TAG, "Failed to download album art.", x); Log.e(TAG, "Failed to download album art.", x);
@ -363,8 +382,8 @@ public class ImageLoader {
final boolean mCrossfade; final boolean mCrossfade;
private final View mView; private final View mView;
public ViewImageTask(Context context, MusicDirectory.Entry entry, int size, boolean isNowPlaying, View view, boolean crossfade) { public ViewImageTask(Context context, MusicDirectory.Entry entry, int size, boolean isNowPlaying, View view, boolean crossfade, boolean blur) {
super(context, entry, size, isNowPlaying); super(context, entry, size, isNowPlaying, blur);
mView = view; mView = view;
mCrossfade = crossfade; mCrossfade = crossfade;
@ -409,7 +428,7 @@ public class ImageLoader {
} }
if (mEntry != null && mEntry.getCoverArt() != null) { if (mEntry != null && mEntry.getCoverArt() != null) {
subTask = new ViewImageTask(mContext, mEntry, mSize, mIsNowPlaying, mView, mCrossfade); subTask = new ViewImageTask(mContext, mEntry, mSize, mIsNowPlaying, mView, mCrossfade, false);
} else { } else {
// If entry is null as well, we need to just set as a blank image // If entry is null as well, we need to just set as a blank image
Bitmap bitmap = getUnknownImage(mEntry, mSize); Bitmap bitmap = getUnknownImage(mEntry, mSize);

View File

@ -20,22 +20,25 @@
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:orientation="vertical"> android:orientation="vertical">
<FrameLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1"> android:layout_weight="1">
<FrameLayout <net.nullsum.audinaut.view.RecyclingImageView
android:id="@+id/download_album_art_background"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:scaleType="centerCrop" />
<net.nullsum.audinaut.view.RecyclingImageView <net.nullsum.audinaut.view.RecyclingImageView
android:id="@+id/download_album_art_image" android:id="@+id/download_album_art_image"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:scaleType="fitCenter" /> android:scaleType="fitCenter" />
</RelativeLayout>
<LinearLayout <LinearLayout
android:id="@+id/download_overlay_buttons" android:id="@+id/download_overlay_buttons"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -45,8 +48,6 @@
android:gravity="center" android:gravity="center"
android:orientation="horizontal" android:orientation="horizontal"
android:visibility="invisible" /> android:visibility="invisible" />
</FrameLayout>
</FrameLayout>
<TextView <TextView
android:id="@+id/download_status" android:id="@+id/download_status"