Commit f199f983 authored by linus_lee's avatar linus_lee
Browse files

Eleven: Switch default artist and album to a more colorful version

Also fixed a bug where playlist worker tasks were running more than necessary
Removed the picker to fetch images from internet
because last.fm is removed for now

Change-Id: Ice438ac650d8b7be0c275f8270af13086e6568d6
parent cb83a720
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<com.cyngn.eleven.widgets.SquareImageView
<ImageView
android:id="@+id/image"
android:layout_width="@dimen/list_item_image_width"
android:layout_height="@dimen/list_item_image_height"
......
......@@ -27,7 +27,6 @@
android:id="@+id/notification_base_image"
android:layout_width="@dimen/notification_big_icon_width"
android:layout_height="@dimen/notification_big_icon_height"
android:background="@drawable/default_artwork"
android:gravity="center" />
<LinearLayout
......
......@@ -115,4 +115,18 @@
<!-- Background Lyrics Color -->
<color name="lyrics_background_color">#b2000000</color>
<!-- Letter tile colors -->
<color name="letter_tile_default_color">#cccccc</color>
<color name="letter_tile_font_color">#ffffff</color>
<array name="letter_tile_colors">
<item>#9237A2</item>
<item>#4B498C</item>
<item>#4E5BA7</item>
<item>#41A4F4</item>
<item>#10887C</item>
<item>#689144</item>
<item>#B9BF45</item>
<item>#757578</item>
</array>
</resources>
......@@ -207,4 +207,6 @@
<!-- General consensus is to leave dividers at 1px instead of having different
partial scaled up values for different resolutions -->
<dimen name="divider_height">1px</dimen>
<item name="letter_to_tile_ratio" type="dimen">53%</item>
</resources>
......@@ -22,4 +22,6 @@
<!-- Do not translate. This provides a separator for two strings -->
<string name="combine_two_strings" translatable="false">%1$s | %2$s</string>
<!-- Font family used when drawing letters for letter tile avatars. -->
<string name="letter_tile_letter_font_family" translatable="false">sans-serif-light</string>
</resources>
......@@ -201,5 +201,4 @@
<string name="search_title_playlists">All \"%s\" playlists</string>
<string name="duration_format"><xliff:g id="hours">%1$s</xliff:g> <xliff:g id="minutes">%2$s</xliff:g></string>
</resources>
......@@ -22,6 +22,7 @@ import com.cyngn.eleven.MusicPlaybackService;
import com.cyngn.eleven.cache.PlaylistWorkerTask.PlaylistWorkerType;
import com.cyngn.eleven.utils.MusicUtils;
import com.cyngn.eleven.widgets.BlurScrimImage;
import com.cyngn.eleven.widgets.LetterTileDrawable;
import java.io.FileNotFoundException;
import java.io.IOException;
......@@ -173,40 +174,6 @@ public class ImageFetcher extends ImageWorker {
}
}
/**
* @param key The key used to find the image to return
*/
public Bitmap getCachedBitmap(final String key) {
if (mImageCache != null) {
return mImageCache.getCachedBitmap(key);
}
return getDefaultArtwork();
}
/**
* @param keyAlbum The key (album name) used to find the album art to return
* @param keyArtist The key (artist name) used to find the album art to return
*/
public Bitmap getCachedArtwork(final String keyAlbum, final String keyArtist) {
return getCachedArtwork(keyAlbum, keyArtist,
MusicUtils.getIdForAlbum(mContext, keyAlbum, keyArtist));
}
/**
* @param keyAlbum The key (album name) used to find the album art to return
* @param keyArtist The key (artist name) used to find the album art to return
* @param keyId The key (album id) used to find the album art to return
*/
public Bitmap getCachedArtwork(final String keyAlbum, final String keyArtist,
final long keyId) {
if (mImageCache != null) {
return mImageCache.getCachedArtwork(mContext,
generateAlbumCacheKey(keyAlbum, keyArtist),
keyId);
}
return getDefaultArtwork();
}
/**
* Finds cached or downloads album art. Used in {@link MusicPlaybackService}
* to set the current album art in the notification and lock screen
......@@ -222,10 +189,11 @@ public class ImageFetcher extends ImageWorker {
boolean smallArtwork) {
// Check the disk cache
Bitmap artwork = null;
String key = albumName;
if (artwork == null && albumName != null && mImageCache != null) {
artwork = mImageCache.getBitmapFromDiskCache(
generateAlbumCacheKey(albumName, artistName));
key = generateAlbumCacheKey(albumName, artistName);
artwork = mImageCache.getBitmapFromDiskCache(key);
}
if (artwork == null && albumId >= 0 && mImageCache != null) {
// Check for local artwork
......@@ -234,7 +202,9 @@ public class ImageFetcher extends ImageWorker {
if (artwork != null) {
return artwork;
}
return getDefaultArtwork(smallArtwork);
return LetterTileDrawable.createDefaultBitmap(mContext, key, ImageType.ALBUM, false,
smallArtwork);
}
/**
......
......@@ -20,7 +20,7 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.support.v8.renderscript.RenderScript;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
......@@ -30,6 +30,7 @@ import com.cyngn.eleven.utils.ApolloUtils;
import com.cyngn.eleven.utils.ImageUtils;
import com.cyngn.eleven.widgets.BlurScrimImage;
import com.cyngn.eleven.cache.PlaylistWorkerTask.PlaylistWorkerType;
import com.cyngn.eleven.widgets.LetterTileDrawable;
import java.lang.ref.WeakReference;
import java.util.Collections;
......@@ -76,26 +77,6 @@ public abstract class ImageWorker {
*/
private final ColorDrawable mTransparentDrawable;
/**
* Default album art
*/
private final Bitmap mDefault;
/**
* A small version of the default album art
*/
private final Bitmap mDefaultSmall;
/**
* Default Artist art
*/
private final Bitmap mDefaultArtist;
/**
* Default Playlist art
*/
private final Bitmap mDefaultPlaylist;
/**
* The Context to use
*/
......@@ -119,17 +100,6 @@ public abstract class ImageWorker {
}
mResources = mContext.getResources();
// Create the default artwork
mDefault = ((BitmapDrawable) mResources.getDrawable(R.drawable.default_artwork)).getBitmap();
// Create the small version of the default artwork
mDefaultSmall = ((BitmapDrawable) mResources.getDrawable(R.drawable.default_artwork_sm))
.getBitmap();
// Create the artist artwork
mDefaultArtist = ((BitmapDrawable) mResources.getDrawable(R.drawable.default_artist))
.getBitmap();
// Create the playlist artwork
mDefaultPlaylist = ((BitmapDrawable) mResources.getDrawable(R.drawable.default_playlist))
.getBitmap();
// Create the transparent layer for the transition drawable
mTransparentDrawable = new ColorDrawable(Color.TRANSPARENT);
}
......@@ -177,47 +147,14 @@ public abstract class ImageWorker {
}
/**
* @return The default artwork
*/
public Bitmap getDefaultArtwork() {
return getDefaultArtwork(false);
}
/**
* @param small returns the smaller version of the default artwork if true
* @return The default artwork
* @return A new drawable of the default artwork
*/
public Bitmap getDefaultArtwork(boolean small) {
return small ? mDefaultSmall : mDefault;
}
/**
* @return A new bitmap drawable of the default artwork
*/
public BitmapDrawable getNewDefaultBitmapDrawable(ImageType imageType) {
Bitmap targetBitmap = null;
switch (imageType) {
case ARTIST:
targetBitmap = mDefaultArtist;
break;
case PLAYLIST:
targetBitmap = mDefaultPlaylist;
break;
case ALBUM:
default:
targetBitmap = mDefault;
break;
}
BitmapDrawable bitmapDrawable = new BitmapDrawable(mResources, targetBitmap);
// No filter and no dither makes things much quicker
bitmapDrawable.setFilterBitmap(false);
bitmapDrawable.setDither(false);
return bitmapDrawable;
public Drawable getNewDrawable(ImageType imageType, String name,
String identifier) {
LetterTileDrawable letterTileDrawable = new LetterTileDrawable(mContext);
letterTileDrawable.setTileDetails(name, identifier, imageType);
letterTileDrawable.setIsCircular(false);
return letterTileDrawable;
}
public static Bitmap getBitmapInBackground(final Context context, final ImageCache imageCache,
......@@ -446,6 +383,25 @@ public abstract class ImageWorker {
}
}
/**
* Loads the default image into the image view given the image type
* @param imageView The {@link ImageView}
* @param imageType The type of image
*/
public void loadDefaultImage(final ImageView imageView, final ImageType imageType,
final String name, final String identifier) {
if (imageView != null) {
// if an existing letter drawable exists, re-use it
Drawable existingDrawable = imageView.getDrawable();
if (existingDrawable != null && existingDrawable instanceof LetterTileDrawable) {
((LetterTileDrawable)existingDrawable).setTileDetails(name, identifier, imageType);
} else {
imageView.setImageDrawable(getNewDrawable(imageType, name,
identifier));
}
}
}
/**
* Called to fetch the artist or album art.
*
......@@ -493,17 +449,28 @@ public abstract class ImageWorker {
imageView.setImageBitmap(lruBitmap);
}
} else {
// if a background drawable hasn't been set, create one so that even if
// the disk cache is paused we see something
if (imageView.getBackground() == null) {
imageView.setBackgroundDrawable(getNewDefaultBitmapDrawable(imageType));
// load the default image
if (imageType == ImageType.ARTIST) {
loadDefaultImage(imageView, imageType, artistName, key);
} else if (imageType == ImageType.ALBUM) {
// don't show letters for albums so pass in null as the display string
// because an album could have multiple artists, use the album id as the key here
loadDefaultImage(imageView, imageType, null, String.valueOf(albumId));
} else {
// don't show letters for playlists so pass in null as the display string
loadDefaultImage(imageView, imageType, null, key);
}
if (executePotentialWork(key, imageView)
&& imageView != null && !mImageCache.isDiskCachePaused()) {
Drawable fromDrawable = imageView.getDrawable();
if (fromDrawable == null) {
fromDrawable = mTransparentDrawable;
}
// Otherwise run the worker task
final SimpleBitmapWorkerTask bitmapWorkerTask = new SimpleBitmapWorkerTask(key,
imageView, imageType, mTransparentDrawable, mContext, scaleImgToView);
imageView, imageType, fromDrawable, mContext, scaleImgToView);
final AsyncTaskContainer asyncTaskContainer = new AsyncTaskContainer(bitmapWorkerTask);
imageView.setTag(asyncTaskContainer);
......@@ -546,15 +513,8 @@ public abstract class ImageWorker {
// Bitmap found in memory cache
imageView.setImageBitmap(lruBitmap);
} else {
// if a background drawable hasn't been set, create one so that even if
// the disk cache is paused we see something
if (imageView.getBackground() == null) {
if (type == PlaylistWorkerType.Artist) {
imageView.setBackground(getNewDefaultBitmapDrawable(ImageType.ARTIST));
} else if (type == PlaylistWorkerType.CoverArt) {
imageView.setBackground(getNewDefaultBitmapDrawable(ImageType.PLAYLIST));
}
}
// load the default image
loadDefaultImage(imageView, ImageType.PLAYLIST, null, String.valueOf(playlistId));
}
// even though we may have found the image in the cache, we want to check if the playlist
......
......@@ -4,18 +4,15 @@
package com.cyngn.eleven.cache;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.provider.MediaStore;
import android.widget.ImageView;
import com.cyngn.eleven.R;
import com.cyngn.eleven.cache.ImageWorker.ImageType;
import com.cyngn.eleven.loaders.PlaylistSongLoader;
import com.cyngn.eleven.loaders.SortedCursor;
......@@ -48,6 +45,9 @@ public class PlaylistWorkerTask extends BitmapWorkerTask<Void, Void, TransitionD
// if the playlist has changed
protected final boolean mFoundInCache;
// because a cached image can be loaded, we use this flag to signal to remove that default image
protected boolean mFallbackToDefaultImage;
/**
* Constructor of <code>PlaylistWorkerTask</code>
* @param key the key of the image to store to
......@@ -66,6 +66,7 @@ public class PlaylistWorkerTask extends BitmapWorkerTask<Void, Void, TransitionD
mWorkerType = type;
mPlaylistStore = PlaylistArtworkStore.getInstance(mContext);
mFoundInCache = foundInCache;
mFallbackToDefaultImage = false;
}
/**
......@@ -99,9 +100,15 @@ public class PlaylistWorkerTask extends BitmapWorkerTask<Void, Void, TransitionD
bitmap = mImageCache.getCachedBitmap(mKey);
}
// if we found a bitmap and we don't need an update, return it
if (bitmap != null && !needsUpdate) {
return createImageTransitionDrawable(bitmap);
// if we don't need an update, return something
if (!needsUpdate) {
if (bitmap != null) {
// if we found a bitmap, return it
return createImageTransitionDrawable(bitmap);
} else {
// otherwise return null since we don't need an update
return null;
}
}
// otherwise re-run the logic to get the bitmap
......@@ -123,19 +130,15 @@ public class PlaylistWorkerTask extends BitmapWorkerTask<Void, Void, TransitionD
mPlaylistStore.updateArtistArt(mPlaylistId);
// remove the cached image
mImageCache.removeFromCache(PlaylistArtworkStore.getArtistCacheKey(mPlaylistId));
// go back to the default image
BitmapDrawable drawable =
(BitmapDrawable) mResources.getDrawable(R.drawable.default_artist);
bitmap = drawable.getBitmap();
// revert back to default image
mFallbackToDefaultImage = true;
} else if (mWorkerType == PlaylistWorkerType.CoverArt) {
// update the timestamp
mPlaylistStore.updateCoverArt(mPlaylistId);
// remove the cached image
mImageCache.removeFromCache(PlaylistArtworkStore.getCoverCacheKey(mPlaylistId));
// go back to the default image
BitmapDrawable drawable =
(BitmapDrawable) mResources.getDrawable(R.drawable.default_playlist);
bitmap = drawable.getBitmap();
// revert back to default image
mFallbackToDefaultImage = true;
}
} else if (mWorkerType == PlaylistWorkerType.Artist) {
bitmap = loadTopArtist(sortedCursor);
......@@ -230,16 +233,23 @@ public class PlaylistWorkerTask extends BitmapWorkerTask<Void, Void, TransitionD
null, artistName, -1, ImageType.ARTIST);
} while (sortedCursor.moveToNext() && bitmap == null);
sortedCursor.close();
if (bitmap == null) {
// if we can't find any artist images, try loading the top songs image
bitmap = mImageCache.getCachedBitmap(
PlaylistArtworkStore.getCoverCacheKey(mPlaylistId));
}
if (bitmap != null) {
// add the image to the cache
mImageCache.addBitmapToCache(mKey, bitmap, true);
// store this artist name into the db
mPlaylistStore.updateArtistArt(mPlaylistId);
} else {
mImageCache.removeFromCache(mKey);
mFallbackToDefaultImage = true;
}
// store the fact that we ran this code into the db to prevent multiple re-runs
mPlaylistStore.updateArtistArt(mPlaylistId);
return bitmap;
}
......@@ -292,8 +302,6 @@ public class PlaylistWorkerTask extends BitmapWorkerTask<Void, Void, TransitionD
}
} while (sortedCursor.moveToNext() && loadedBitmaps.size() < MAX_NUM_BITMAPS_TO_LOAD);
sortedCursor.close();
// if we found at least 1 bitmap
if (loadedBitmaps.size() > 0) {
// get the first bitmap
......@@ -324,22 +332,24 @@ public class PlaylistWorkerTask extends BitmapWorkerTask<Void, Void, TransitionD
combinedCanvas.drawBitmap(loadedBitmaps.get(3), null,
new Rect(width / 2, height / 2, width, height), null);
combinedCanvas.release();
combinedCanvas = null;
bitmap = combinedBitmap;
}
}
if (bitmap != null) {
// add the image to the cache
mImageCache.addBitmapToCache(mKey, bitmap, true);
// store the fact that we ran this code into the db to prevent multiple re-runs
mPlaylistStore.updateCoverArt(mPlaylistId);
// store this artist name into the db
mPlaylistStore.updateCoverArt(mPlaylistId);
}
return bitmap;
if (bitmap != null) {
// add the image to the cache
mImageCache.addBitmapToCache(mKey, bitmap, true);
} else {
mImageCache.removeFromCache(mKey);
mFallbackToDefaultImage = true;
}
return null;
return bitmap;
}
/**
......@@ -348,8 +358,13 @@ public class PlaylistWorkerTask extends BitmapWorkerTask<Void, Void, TransitionD
@Override
protected void onPostExecute(TransitionDrawable transitionDrawable) {
final ImageView imageView = getAttachedImageView();
if (transitionDrawable != null && imageView != null) {
imageView.setImageDrawable(transitionDrawable);
if (imageView != null) {
if (transitionDrawable != null) {
imageView.setImageDrawable(transitionDrawable);
} else if (mFallbackToDefaultImage) {
ImageFetcher.getInstance(mContext).loadDefaultImage(imageView,
ImageType.PLAYLIST, null, String.valueOf(mPlaylistId));
}
}
}
}
......@@ -118,10 +118,11 @@ public class PhotoSelectionDialog extends DialogFragment {
private void setArtistChoices() {
// Select a photo from the gallery
mChoices.add(NEW_PHOTO, getString(R.string.new_photo));
/* Disable fetching image until we find a last.fm replacement
if (ApolloUtils.isOnline(getActivity())) {
// Option to fetch the old artist image
mChoices.add(OLD_PHOTO, getString(R.string.context_menu_fetch_artist_image));
}
}*/
}
/**
......@@ -130,11 +131,12 @@ public class PhotoSelectionDialog extends DialogFragment {
private void setAlbumChoices() {
// Select a photo from the gallery
mChoices.add(NEW_PHOTO, getString(R.string.new_photo));
/* Disable fetching image until we find a last.fm replacement
// Option to fetch the old album image
if (ApolloUtils.isOnline(getActivity())) {
// Option to fetch the old artist image
mChoices.add(OLD_PHOTO, getString(R.string.context_menu_fetch_album_art));
}
}*/
}
/**
......@@ -143,8 +145,9 @@ public class PhotoSelectionDialog extends DialogFragment {
private void setOtherChoices() {
// Select a photo from the gallery
mChoices.add(NEW_PHOTO, getString(R.string.new_photo));
// Disable fetching image until we find a last.fm replacement
// Option to use the default image
mChoices.add(OLD_PHOTO, getString(R.string.use_default));
// mChoices.add(OLD_PHOTO, getString(R.string.use_default));
}
/**
......
......@@ -7,7 +7,7 @@ import android.widget.AbsListView.OnScrollListener;
import com.cyngn.eleven.ui.activities.HomeActivity;
public abstract class FadingBarFragment extends DetailFragment implements OnScrollListener {
protected static final int ACTION_BAR_DEFAULT_OPACITY = 65;
protected static final int ACTION_BAR_DEFAULT_OPACITY = 100;
@Override
public void setupActionBar() {
......
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cyngn.eleven.widgets;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import junit.framework.Assert;
import com.cyngn.eleven.R;
import com.cyngn.eleven.cache.ImageWorker.ImageType;
import com.cyngn.eleven.utils.MusicUtils;
/**
* A drawable that encapsulates all the functionality needed to display a letter tile to
* represent a artist/album/playlist image.
*/
public class LetterTileDrawable extends Drawable {
private final String TAG = LetterTileDrawable.class.getSimpleName();
private final Paint mPaint;
/** Letter tile */
private static TypedArray sColors;
private static int sDefaultColor;
private static int sTileFontColor;
private static float sLetterToTileRatio;
private static Bitmap DEFAULT_ARTIST;
private static Bitmap DEFAULT_ARTIST_LARGE;
private static Bitmap DEFAULT_ALBUM;
private static Bitmap DEFAULT_ALBUM_LARGE;
private static Bitmap DEFAULT_PLAYLIST;
private static Bitmap DEFAULT_PLAYLIST_LARGE;
/** Reusable components to avoid new allocations */
private static final Paint sPaint = new Paint();
private static final Rect sRect = new Rect();
private static final char[] sChars = new char[2];
private String mDisplayName;
private String mIdentifier;
private float mScale = 1.0f;
private float mOffset = 0.0f;
private Resources res;
private boolean mIsCircle = false;
private ImageType mImageType;