From b1d0e91b8ac3e1907b3c87fde2dca44f8f8de69b Mon Sep 17 00:00:00 2001 From: Andrew Rabert Date: Wed, 28 Mar 2018 01:35:49 -0400 Subject: [PATCH] Fill empty space with blurred cover art --- .../fragments/NowPlayingFragment.java | 6 +++ .../nullsum/audinaut/util/BlurBuilder.java | 32 +++++++++++++++ .../nullsum/audinaut/util/ImageLoader.java | 35 +++++++++++++---- app/src/main/res/layout-port/download.xml | 39 ++++++++++--------- 4 files changed, 85 insertions(+), 27 deletions(-) create mode 100644 app/src/main/java/net/nullsum/audinaut/util/BlurBuilder.java diff --git a/app/src/main/java/net/nullsum/audinaut/fragments/NowPlayingFragment.java b/app/src/main/java/net/nullsum/audinaut/fragments/NowPlayingFragment.java index 209785a..01a9533 100644 --- a/app/src/main/java/net/nullsum/audinaut/fragments/NowPlayingFragment.java +++ b/app/src/main/java/net/nullsum/audinaut/fragments/NowPlayingFragment.java @@ -87,6 +87,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis private TextView emptyTextView; private TextView songTitleTextView; private ImageView albumArtImageView; + private ImageView albumArtBackgroundView; private RecyclerView playlistView; private TextView positionTextView; private TextView durationTextView; @@ -151,6 +152,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis emptyTextView = rootView.findViewById(R.id.download_empty); songTitleTextView = rootView.findViewById(R.id.download_song_title); 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); durationTextView = rootView.findViewById(R.id.download_duration); 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()) { + getImageLoader().loadBlurImage(albumArtBackgroundView, null, true, false); getImageLoader().loadImage(albumArtImageView, null, true, false); } @@ -804,6 +807,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis if (currentPlaying != null) { Entry song = currentPlaying.getSong(); songTitleTextView.setText(song.getTitle()); + getImageLoader().loadBlurImage(albumArtBackgroundView, song, true, true); getImageLoader().loadImage(albumArtImageView, song, true, true); DownloadService downloadService = getDownloadService(); @@ -814,6 +818,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis } } else { songTitleTextView.setText(null); + getImageLoader().loadBlurImage(albumArtBackgroundView, null, true, false); getImageLoader().loadImage(albumArtImageView, null, true, false); setSubtitle(null); } @@ -939,6 +944,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis @Override public void onMetadataUpdate(Entry song, int fieldChange) { if (song != null && albumArtImageView != null && fieldChange == DownloadService.METADATA_UPDATED_COVER_ART) { + getImageLoader().loadBlurImage(albumArtBackgroundView, song, true, true); getImageLoader().loadImage(albumArtImageView, song, true, true); } } diff --git a/app/src/main/java/net/nullsum/audinaut/util/BlurBuilder.java b/app/src/main/java/net/nullsum/audinaut/util/BlurBuilder.java new file mode 100644 index 0000000..efefabc --- /dev/null +++ b/app/src/main/java/net/nullsum/audinaut/util/BlurBuilder.java @@ -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; + } +} diff --git a/app/src/main/java/net/nullsum/audinaut/util/ImageLoader.java b/app/src/main/java/net/nullsum/audinaut/util/ImageLoader.java index 85b446b..2f15110 100644 --- a/app/src/main/java/net/nullsum/audinaut/util/ImageLoader.java +++ b/app/src/main/java/net/nullsum/audinaut/util/ImageLoader.java @@ -209,10 +209,19 @@ public class ImageLoader { public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) { 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 (entry != null && !entry.isAlbum() && !Util.isOffline(context)) { SilentBackgroundTask task = new ArtistImageTask(view.getContext(), entry, size, large, view, crossfade); @@ -229,12 +238,18 @@ public class ImageLoader { Bitmap bitmap; if (entry == null || entry.getCoverArt() == null) { bitmap = getUnknownImage(entry, size); + if (blur) { + bitmap = BlurBuilder.blur(context, bitmap); + } setImage(view, Util.createDrawableFromBitmap(context, bitmap), crossfade); return null; } bitmap = cache.get(getKey(entry.getCoverArt(), size)); if (bitmap != null && !bitmap.isRecycled()) { + if (blur) { + bitmap = BlurBuilder.blur(context, bitmap); + } final Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); setImage(view, drawable, crossfade); if (large) { @@ -246,7 +261,7 @@ public class ImageLoader { if (!large) { 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(); return task; } @@ -322,14 +337,16 @@ public class ImageLoader { private final Context mContext; private final int mSize; private final boolean mIsNowPlaying; + private final boolean mBlur; 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); mContext = context; mEntry = entry; mSize = size; mIsNowPlaying = isNowPlaying; + mBlur = blur; } @Override @@ -348,7 +365,9 @@ public class ImageLoader { } else { bitmap = getUnknownImage(mEntry, mSize); } - + if (mBlur) { + bitmap = BlurBuilder.blur(context, bitmap); + } mDrawable = Util.createDrawableFromBitmap(mContext, bitmap); } catch (Throwable x) { Log.e(TAG, "Failed to download album art.", x); @@ -363,8 +382,8 @@ public class ImageLoader { final boolean mCrossfade; private final View mView; - public ViewImageTask(Context context, MusicDirectory.Entry entry, int size, boolean isNowPlaying, View view, boolean crossfade) { - super(context, entry, size, isNowPlaying); + public ViewImageTask(Context context, MusicDirectory.Entry entry, int size, boolean isNowPlaying, View view, boolean crossfade, boolean blur) { + super(context, entry, size, isNowPlaying, blur); mView = view; mCrossfade = crossfade; @@ -409,7 +428,7 @@ public class ImageLoader { } 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 { // If entry is null as well, we need to just set as a blank image Bitmap bitmap = getUnknownImage(mEntry, mSize); diff --git a/app/src/main/res/layout-port/download.xml b/app/src/main/res/layout-port/download.xml index 9a67916..f1c54a3 100644 --- a/app/src/main/res/layout-port/download.xml +++ b/app/src/main/res/layout-port/download.xml @@ -20,33 +20,34 @@ android:background="@android:color/transparent" android:orientation="vertical"> - - + android:scaleType="centerCrop" /> - + - - - + + +