Reverted DownloadActivity and ImageLoader changes, updated icons, tweaked icon padding
|
@ -2,7 +2,7 @@
|
|||
<manifest xmlns:a="http://schemas.android.com/apk/res/android"
|
||||
package="net.sourceforge.subsonic.androidapp"
|
||||
a:versionCode="47"
|
||||
a:versionName="3.9.9" a:installLocation="auto">
|
||||
a:versionName="3.9.9.1" a:installLocation="auto">
|
||||
|
||||
<uses-permission a:name="android.permission.INTERNET"/>
|
||||
<uses-permission a:name="android.permission.READ_PHONE_STATE"/>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "ant.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-15
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 923 B After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.8 KiB |
|
@ -189,13 +189,12 @@
|
|||
a:layout_alignParentLeft="true"
|
||||
a:layout_toLeftOf="@+id/download_control_layout"
|
||||
>
|
||||
|
||||
<FrameLayout
|
||||
a:id="@+id/download_album_art_layout"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="fill_parent"
|
||||
a:background="@drawable/pinstripe_tile" >
|
||||
|
||||
<FrameLayout
|
||||
a:id="@+id/download_album_art_layout"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="fill_parent"
|
||||
a:background="@drawable/album_art_background">
|
||||
<ImageView
|
||||
a:id="@+id/download_album_art_image"
|
||||
a:layout_width="wrap_content"
|
||||
|
|
|
@ -9,14 +9,14 @@
|
|||
a:layout_width="fill_parent"
|
||||
a:layout_height="0dip"
|
||||
a:layout_weight="1">
|
||||
|
||||
|
||||
<RelativeLayout
|
||||
a:id="@+id/download_album_art_layout"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:background="@drawable/pinstripe_tile"
|
||||
a:orientation="vertical" >
|
||||
a:id="@+id/download_album_art_layout"
|
||||
a:orientation="vertical"
|
||||
a:layout_width="fill_parent"
|
||||
a:layout_height="fill_parent"
|
||||
a:layout_weight="1"
|
||||
a:background="@drawable/album_art_background">
|
||||
|
||||
<ImageButton
|
||||
a:id="@+id/download_repeat"
|
||||
|
@ -40,7 +40,7 @@
|
|||
a:layout_gravity="top|right"
|
||||
a:layout_below="@+id/download_repeat"
|
||||
a:paddingTop="12dip"
|
||||
a:paddingLeft="14dip"
|
||||
a:paddingLeft="0dip"
|
||||
a:paddingBottom="15dip"/>
|
||||
|
||||
<Button
|
||||
|
@ -140,7 +140,7 @@
|
|||
a:background="@drawable/list_selector_holo_dark"
|
||||
a:paddingBottom="12dip"
|
||||
a:paddingLeft="8dip"
|
||||
a:paddingTop="24dip"
|
||||
a:paddingTop="12dip"
|
||||
a:src="@drawable/ic_menu_moreoverflow" />
|
||||
|
||||
<ImageButton
|
||||
|
|
|
@ -1,253 +1,252 @@
|
|||
/*
|
||||
This file is part of Subsonic.
|
||||
|
||||
Subsonic is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Subsonic is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
package net.sourceforge.subsonic.androidapp.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.TransitionDrawable;
|
||||
import android.os.Handler;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import net.sourceforge.subsonic.androidapp.R;
|
||||
import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicService;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* Asynchronous loading of images, with caching.
|
||||
* <p/>
|
||||
* There should normally be only one instance of this class.
|
||||
*
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public class ImageLoader implements Runnable {
|
||||
|
||||
private static final String TAG = ImageLoader.class.getSimpleName();
|
||||
private static final int CONCURRENCY = 5;
|
||||
|
||||
private final LRUCache<String, Drawable> cache = new LRUCache<String, Drawable>(100);
|
||||
private final BlockingQueue<Task> queue;
|
||||
private final int imageSizeDefault;
|
||||
private final int imageSizeLarge;
|
||||
private Drawable largeUnknownImage;
|
||||
|
||||
public ImageLoader(Context context) {
|
||||
queue = new LinkedBlockingQueue<Task>(500);
|
||||
|
||||
// Determine the density-dependent image sizes.
|
||||
imageSizeDefault = context.getResources().getDrawable(R.drawable.unknown_album).getIntrinsicHeight();
|
||||
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||
/*imageSizeLarge = (int) Math.round(Math.min(metrics.widthPixels, metrics.heightPixels) * 0.6);*/
|
||||
imageSizeLarge = (int) Math.round(Math.min(metrics.widthPixels, metrics.heightPixels));
|
||||
|
||||
for (int i = 0; i < CONCURRENCY; i++) {
|
||||
new Thread(this, "ImageLoader").start();
|
||||
}
|
||||
|
||||
createLargeUnknownImage(context);
|
||||
}
|
||||
|
||||
private void createLargeUnknownImage(Context context) {
|
||||
BitmapDrawable drawable = (BitmapDrawable) context.getResources().getDrawable(R.drawable.unknown_album_large);
|
||||
Bitmap bitmap = Bitmap.createScaledBitmap(drawable.getBitmap(), imageSizeLarge, imageSizeLarge, true);
|
||||
bitmap = createReflection(bitmap);
|
||||
largeUnknownImage = Util.createDrawableFromBitmap(context, bitmap);
|
||||
}
|
||||
|
||||
public void loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) {
|
||||
if (entry == null || entry.getCoverArt() == null) {
|
||||
setUnknownImage(view, large);
|
||||
return;
|
||||
}
|
||||
|
||||
int size = large ? imageSizeLarge : imageSizeDefault;
|
||||
Drawable drawable = cache.get(getKey(entry.getCoverArt(), size));
|
||||
if (drawable != null) {
|
||||
setImage(view, drawable, large);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!large) {
|
||||
setUnknownImage(view, large);
|
||||
}
|
||||
queue.offer(new Task(view, entry, size, false, large, crossfade));
|
||||
}
|
||||
|
||||
private String getKey(String coverArtId, int size) {
|
||||
return coverArtId + size;
|
||||
}
|
||||
|
||||
private void setImage(View view, Drawable drawable, boolean crossfade) {
|
||||
if (view instanceof TextView) {
|
||||
// Cross-fading is not implemented for TextView since it's not in use. It would be easy to add it, though.
|
||||
TextView textView = (TextView) view;
|
||||
textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
|
||||
} else if (view instanceof ImageView) {
|
||||
ImageView imageView = (ImageView) view;
|
||||
if (crossfade) {
|
||||
|
||||
Drawable existingDrawable = imageView.getDrawable();
|
||||
if (existingDrawable == null) {
|
||||
Bitmap emptyImage = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
existingDrawable = new BitmapDrawable(emptyImage);
|
||||
}
|
||||
|
||||
Drawable[] layers = new Drawable[]{existingDrawable, drawable};
|
||||
|
||||
TransitionDrawable transitionDrawable = new TransitionDrawable(layers);
|
||||
imageView.setImageDrawable(transitionDrawable);
|
||||
transitionDrawable.startTransition(250);
|
||||
} else {
|
||||
imageView.setImageDrawable(drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setUnknownImage(View view, boolean large) {
|
||||
if (large) {
|
||||
setImage(view, largeUnknownImage, false);
|
||||
} else {
|
||||
if (view instanceof TextView) {
|
||||
((TextView) view).setCompoundDrawablesWithIntrinsicBounds(R.drawable.unknown_album, 0, 0, 0);
|
||||
} else if (view instanceof ImageView) {
|
||||
((ImageView) view).setImageResource(R.drawable.unknown_album);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
queue.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
Task task = queue.take();
|
||||
task.execute();
|
||||
} catch (Throwable x) {
|
||||
Log.e(TAG, "Unexpected exception in ImageLoader.", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap createReflection(Bitmap originalImage) {
|
||||
|
||||
int width = originalImage.getWidth();
|
||||
int height = originalImage.getHeight();
|
||||
|
||||
// The gap we want between the reflection and the original image
|
||||
final int reflectionGap = 4;
|
||||
|
||||
// This will not scale but will flip on the Y axis
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.preScale(1, -1);
|
||||
|
||||
// Create a Bitmap with the flip matix applied to it.
|
||||
// We only want the bottom half of the image
|
||||
Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height / 2, width, height / 2, matrix, false);
|
||||
|
||||
// Create a new bitmap with same width but taller to fit reflection
|
||||
Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height / 2), Bitmap.Config.ARGB_8888);
|
||||
|
||||
// Create a new Canvas with the bitmap that's big enough for
|
||||
// the image plus gap plus reflection
|
||||
Canvas canvas = new Canvas(bitmapWithReflection);
|
||||
|
||||
// Draw in the original image
|
||||
canvas.drawBitmap(originalImage, 0, 0, null);
|
||||
|
||||
// Draw in the gap
|
||||
Paint defaultPaint = new Paint();
|
||||
canvas.drawRect(0, height, width, height + reflectionGap, defaultPaint);
|
||||
|
||||
// Draw in the reflection
|
||||
canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);
|
||||
|
||||
// Create a shader that is a linear gradient that covers the reflection
|
||||
Paint paint = new Paint();
|
||||
LinearGradient shader = new LinearGradient(0, originalImage.getHeight(), 0,
|
||||
bitmapWithReflection.getHeight() + reflectionGap, 0x70000000, 0xff000000,
|
||||
Shader.TileMode.CLAMP);
|
||||
|
||||
// Set the paint to use this shader (linear gradient)
|
||||
paint.setShader(shader);
|
||||
|
||||
// Draw a rectangle using the paint with our linear gradient
|
||||
canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + reflectionGap, paint);
|
||||
|
||||
return bitmapWithReflection;
|
||||
}
|
||||
|
||||
private class Task {
|
||||
private final View view;
|
||||
private final MusicDirectory.Entry entry;
|
||||
private final Handler handler;
|
||||
private final int size;
|
||||
private final boolean reflection;
|
||||
private final boolean saveToFile;
|
||||
private final boolean crossfade;
|
||||
|
||||
public Task(View view, MusicDirectory.Entry entry, int size, boolean reflection, boolean saveToFile, boolean crossfade) {
|
||||
this.view = view;
|
||||
this.entry = entry;
|
||||
this.size = size;
|
||||
this.reflection = reflection;
|
||||
this.saveToFile = saveToFile;
|
||||
this.crossfade = crossfade;
|
||||
handler = new Handler();
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
try {
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(view.getContext());
|
||||
Bitmap bitmap = musicService.getCoverArt(view.getContext(), entry, size, saveToFile, null);
|
||||
|
||||
if (reflection) {
|
||||
bitmap = createReflection(bitmap);
|
||||
}
|
||||
|
||||
final Drawable drawable = Util.createDrawableFromBitmap(view.getContext(), bitmap);
|
||||
cache.put(getKey(entry.getCoverArt(), size), drawable);
|
||||
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setImage(view, drawable, crossfade);
|
||||
}
|
||||
});
|
||||
} catch (Throwable x) {
|
||||
Log.e(TAG, "Failed to download album art.", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
This file is part of Subsonic.
|
||||
|
||||
Subsonic is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Subsonic is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
package net.sourceforge.subsonic.androidapp.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.TransitionDrawable;
|
||||
import android.os.Handler;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import net.sourceforge.subsonic.androidapp.R;
|
||||
import net.sourceforge.subsonic.androidapp.domain.MusicDirectory;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicService;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* Asynchronous loading of images, with caching.
|
||||
* <p/>
|
||||
* There should normally be only one instance of this class.
|
||||
*
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public class ImageLoader implements Runnable {
|
||||
|
||||
private static final String TAG = ImageLoader.class.getSimpleName();
|
||||
private static final int CONCURRENCY = 5;
|
||||
|
||||
private final LRUCache<String, Drawable> cache = new LRUCache<String, Drawable>(100);
|
||||
private final BlockingQueue<Task> queue;
|
||||
private final int imageSizeDefault;
|
||||
private final int imageSizeLarge;
|
||||
private Drawable largeUnknownImage;
|
||||
|
||||
public ImageLoader(Context context) {
|
||||
queue = new LinkedBlockingQueue<Task>(500);
|
||||
|
||||
// Determine the density-dependent image sizes.
|
||||
imageSizeDefault = context.getResources().getDrawable(R.drawable.unknown_album).getIntrinsicHeight();
|
||||
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||
imageSizeLarge = (int) Math.round(Math.min(metrics.widthPixels, metrics.heightPixels) * 0.6);
|
||||
|
||||
for (int i = 0; i < CONCURRENCY; i++) {
|
||||
new Thread(this, "ImageLoader").start();
|
||||
}
|
||||
|
||||
createLargeUnknownImage(context);
|
||||
}
|
||||
|
||||
private void createLargeUnknownImage(Context context) {
|
||||
BitmapDrawable drawable = (BitmapDrawable) context.getResources().getDrawable(R.drawable.unknown_album_large);
|
||||
Bitmap bitmap = Bitmap.createScaledBitmap(drawable.getBitmap(), imageSizeLarge, imageSizeLarge, true);
|
||||
bitmap = createReflection(bitmap);
|
||||
largeUnknownImage = Util.createDrawableFromBitmap(context, bitmap);
|
||||
}
|
||||
|
||||
public void loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) {
|
||||
if (entry == null || entry.getCoverArt() == null) {
|
||||
setUnknownImage(view, large);
|
||||
return;
|
||||
}
|
||||
|
||||
int size = large ? imageSizeLarge : imageSizeDefault;
|
||||
Drawable drawable = cache.get(getKey(entry.getCoverArt(), size));
|
||||
if (drawable != null) {
|
||||
setImage(view, drawable, large);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!large) {
|
||||
setUnknownImage(view, large);
|
||||
}
|
||||
queue.offer(new Task(view, entry, size, large, large, crossfade));
|
||||
}
|
||||
|
||||
private String getKey(String coverArtId, int size) {
|
||||
return coverArtId + size;
|
||||
}
|
||||
|
||||
private void setImage(View view, Drawable drawable, boolean crossfade) {
|
||||
if (view instanceof TextView) {
|
||||
// Cross-fading is not implemented for TextView since it's not in use. It would be easy to add it, though.
|
||||
TextView textView = (TextView) view;
|
||||
textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
|
||||
} else if (view instanceof ImageView) {
|
||||
ImageView imageView = (ImageView) view;
|
||||
if (crossfade) {
|
||||
|
||||
Drawable existingDrawable = imageView.getDrawable();
|
||||
if (existingDrawable == null) {
|
||||
Bitmap emptyImage = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
existingDrawable = new BitmapDrawable(emptyImage);
|
||||
}
|
||||
|
||||
Drawable[] layers = new Drawable[]{existingDrawable, drawable};
|
||||
|
||||
TransitionDrawable transitionDrawable = new TransitionDrawable(layers);
|
||||
imageView.setImageDrawable(transitionDrawable);
|
||||
transitionDrawable.startTransition(250);
|
||||
} else {
|
||||
imageView.setImageDrawable(drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setUnknownImage(View view, boolean large) {
|
||||
if (large) {
|
||||
setImage(view, largeUnknownImage, false);
|
||||
} else {
|
||||
if (view instanceof TextView) {
|
||||
((TextView) view).setCompoundDrawablesWithIntrinsicBounds(R.drawable.unknown_album, 0, 0, 0);
|
||||
} else if (view instanceof ImageView) {
|
||||
((ImageView) view).setImageResource(R.drawable.unknown_album);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
queue.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
Task task = queue.take();
|
||||
task.execute();
|
||||
} catch (Throwable x) {
|
||||
Log.e(TAG, "Unexpected exception in ImageLoader.", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap createReflection(Bitmap originalImage) {
|
||||
|
||||
int width = originalImage.getWidth();
|
||||
int height = originalImage.getHeight();
|
||||
|
||||
// The gap we want between the reflection and the original image
|
||||
final int reflectionGap = 4;
|
||||
|
||||
// This will not scale but will flip on the Y axis
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.preScale(1, -1);
|
||||
|
||||
// Create a Bitmap with the flip matix applied to it.
|
||||
// We only want the bottom half of the image
|
||||
Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height / 2, width, height / 2, matrix, false);
|
||||
|
||||
// Create a new bitmap with same width but taller to fit reflection
|
||||
Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height / 2), Bitmap.Config.ARGB_8888);
|
||||
|
||||
// Create a new Canvas with the bitmap that's big enough for
|
||||
// the image plus gap plus reflection
|
||||
Canvas canvas = new Canvas(bitmapWithReflection);
|
||||
|
||||
// Draw in the original image
|
||||
canvas.drawBitmap(originalImage, 0, 0, null);
|
||||
|
||||
// Draw in the gap
|
||||
Paint defaultPaint = new Paint();
|
||||
canvas.drawRect(0, height, width, height + reflectionGap, defaultPaint);
|
||||
|
||||
// Draw in the reflection
|
||||
canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);
|
||||
|
||||
// Create a shader that is a linear gradient that covers the reflection
|
||||
Paint paint = new Paint();
|
||||
LinearGradient shader = new LinearGradient(0, originalImage.getHeight(), 0,
|
||||
bitmapWithReflection.getHeight() + reflectionGap, 0x70000000, 0xff000000,
|
||||
Shader.TileMode.CLAMP);
|
||||
|
||||
// Set the paint to use this shader (linear gradient)
|
||||
paint.setShader(shader);
|
||||
|
||||
// Draw a rectangle using the paint with our linear gradient
|
||||
canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + reflectionGap, paint);
|
||||
|
||||
return bitmapWithReflection;
|
||||
}
|
||||
|
||||
private class Task {
|
||||
private final View view;
|
||||
private final MusicDirectory.Entry entry;
|
||||
private final Handler handler;
|
||||
private final int size;
|
||||
private final boolean reflection;
|
||||
private final boolean saveToFile;
|
||||
private final boolean crossfade;
|
||||
|
||||
public Task(View view, MusicDirectory.Entry entry, int size, boolean reflection, boolean saveToFile, boolean crossfade) {
|
||||
this.view = view;
|
||||
this.entry = entry;
|
||||
this.size = size;
|
||||
this.reflection = reflection;
|
||||
this.saveToFile = saveToFile;
|
||||
this.crossfade = crossfade;
|
||||
handler = new Handler();
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
try {
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(view.getContext());
|
||||
Bitmap bitmap = musicService.getCoverArt(view.getContext(), entry, size, saveToFile, null);
|
||||
|
||||
if (reflection) {
|
||||
bitmap = createReflection(bitmap);
|
||||
}
|
||||
|
||||
final Drawable drawable = Util.createDrawableFromBitmap(view.getContext(), bitmap);
|
||||
cache.put(getKey(entry.getCoverArt(), size), drawable);
|
||||
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setImage(view, drawable, crossfade);
|
||||
}
|
||||
});
|
||||
} catch (Throwable x) {
|
||||
Log.e(TAG, "Failed to download album art.", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|