summaryrefslogtreecommitdiffstats
path: root/src/com/cyngn/eleven
diff options
context:
space:
mode:
authorlinus_lee <llee@cyngn.com>2014-09-02 18:57:39 -0700
committerlinus_lee <llee@cyngn.com>2014-11-20 11:59:11 -0800
commit32e9492d3d5d0fae297af88865cfc3cfc22e27c1 (patch)
treea17d7d9233935af839885e3fffdfe0f9a5dc5eb1 /src/com/cyngn/eleven
parent08276a046ece9c2d25ee5db858bce822bfb0a292 (diff)
downloadandroid_packages_apps_Eleven-32e9492d3d5d0fae297af88865cfc3cfc22e27c1.tar.gz
android_packages_apps_Eleven-32e9492d3d5d0fae297af88865cfc3cfc22e27c1.tar.bz2
android_packages_apps_Eleven-32e9492d3d5d0fae297af88865cfc3cfc22e27c1.zip
Eleven: Add blurring behind the now playing and the queue fragments and fixes a few bugs
In addition to blurring, hide non-english headers, and fix the gripper colors Change-Id: I6899a5d1d3bb8c6c7711652a618b1bdc47abcb1f
Diffstat (limited to 'src/com/cyngn/eleven')
-rw-r--r--src/com/cyngn/eleven/adapters/SongAdapter.java21
-rw-r--r--src/com/cyngn/eleven/cache/ImageFetcher.java10
-rw-r--r--src/com/cyngn/eleven/cache/ImageWorker.java422
-rw-r--r--src/com/cyngn/eleven/slidinguppanel/SlidingUpPanelLayout.java28
-rw-r--r--src/com/cyngn/eleven/ui/activities/HomeActivity.java18
-rw-r--r--src/com/cyngn/eleven/ui/fragments/QueueFragment.java2
-rw-r--r--src/com/cyngn/eleven/ui/fragments/SongFragment.java2
-rw-r--r--src/com/cyngn/eleven/utils/MusicUtils.java20
-rw-r--r--src/com/cyngn/eleven/utils/SectionCreatorUtils.java9
-rw-r--r--src/com/cyngn/eleven/widgets/BlurScrimImage.java73
10 files changed, 545 insertions, 60 deletions
diff --git a/src/com/cyngn/eleven/adapters/SongAdapter.java b/src/com/cyngn/eleven/adapters/SongAdapter.java
index 54b0f23..1cefb05 100644
--- a/src/com/cyngn/eleven/adapters/SongAdapter.java
+++ b/src/com/cyngn/eleven/adapters/SongAdapter.java
@@ -97,15 +97,18 @@ public class SongAdapter extends ArrayAdapter<Song> implements SectionAdapter.Ba
// padding doesn't apply to included layouts, so we need
// to wrap it in a container and show/hide with the container
PlayPauseProgressButton playPauseProgressButton = holder.mPlayPauseProgressButton.get();
- View playPauseContainer = holder.mPlayPauseProgressContainer.get();
- if (mCurrentlyPlayingSongId == dataHolder.mItemId) {
- // make it visible
- playPauseProgressButton.enableAndShow();
- playPauseContainer.setVisibility(View.VISIBLE);
- } else {
- // hide it
- playPauseProgressButton.disableAndHide();
- playPauseContainer.setVisibility(View.GONE);
+ if (playPauseProgressButton != null) {
+ View playPauseContainer = holder.mPlayPauseProgressContainer.get();
+
+ if (mCurrentlyPlayingSongId == dataHolder.mItemId) {
+ // make it visible
+ playPauseProgressButton.enableAndShow();
+ playPauseContainer.setVisibility(View.VISIBLE);
+ } else {
+ // hide it
+ playPauseProgressButton.disableAndHide();
+ playPauseContainer.setVisibility(View.GONE);
+ }
}
return convertView;
diff --git a/src/com/cyngn/eleven/cache/ImageFetcher.java b/src/com/cyngn/eleven/cache/ImageFetcher.java
index 0d7c7dc..e647693 100644
--- a/src/com/cyngn/eleven/cache/ImageFetcher.java
+++ b/src/com/cyngn/eleven/cache/ImageFetcher.java
@@ -25,6 +25,7 @@ import com.cyngn.eleven.lastfm.MusicEntry;
import com.cyngn.eleven.lastfm.ImageSize;
import com.cyngn.eleven.utils.MusicUtils;
import com.cyngn.eleven.utils.PreferenceUtils;
+import com.cyngn.eleven.widgets.BlurScrimImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -160,6 +161,15 @@ public class ImageFetcher extends ImageWorker {
}
/**
+ * Used to fetch the current artwork blurred.
+ */
+ public void loadCurrentBlurredArtwork(final BlurScrimImage image) {
+ loadBlurImage(generateAlbumCacheKey(MusicUtils.getAlbumName(), MusicUtils.getArtistName()),
+ MusicUtils.getArtistName(), MusicUtils.getAlbumName(), MusicUtils.getCurrentAlbumId(),
+ image, ImageType.ALBUM);
+ }
+
+ /**
* Used to fetch artist images.
*/
public void loadArtistImage(final String key, final ImageView imageView) {
diff --git a/src/com/cyngn/eleven/cache/ImageWorker.java b/src/com/cyngn/eleven/cache/ImageWorker.java
index 68553f4..2e63e4c 100644
--- a/src/com/cyngn/eleven/cache/ImageWorker.java
+++ b/src/com/cyngn/eleven/cache/ImageWorker.java
@@ -20,10 +20,17 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.os.AsyncTask;
+import android.support.v7.graphics.Palette;
+import android.support.v7.graphics.PaletteItem;
+import android.support.v8.renderscript.Allocation;
+import android.support.v8.renderscript.Element;
+import android.support.v8.renderscript.RenderScript;
+import android.support.v8.renderscript.ScriptIntrinsicBlur;
import android.widget.ImageView;
import com.cyngn.eleven.R;
import com.cyngn.eleven.utils.ApolloUtils;
+import com.cyngn.eleven.widgets.BlurScrimImage;
import java.lang.ref.WeakReference;
import java.util.concurrent.RejectedExecutionException;
@@ -37,9 +44,19 @@ import java.util.concurrent.RejectedExecutionException;
public abstract class ImageWorker {
/**
+ * Render script
+ */
+ private static RenderScript sRenderScript = null;
+
+ /**
* Default transition drawable fade time
*/
- private static final int FADE_IN_TIME = 200;
+ public static final int FADE_IN_TIME = 200;
+
+ /**
+ * Default transition drawable fade time slow
+ */
+ public static final int FADE_IN_TIME_SLOW = 1000;
/**
* The resources to use
@@ -49,17 +66,17 @@ public abstract class ImageWorker {
/**
* First layer of the transition drawable
*/
- private final ColorDrawable mCurrentDrawable;
+ private final ColorDrawable mTransparentDrawable;
/**
- * Layer drawable used to cross fade the result from the worker
+ * Default album art
*/
- private final Drawable[] mArrayDrawable;
+ private final Bitmap mDefault;
/**
- * Default album art
+ * Default album art blurred
*/
- private final Bitmap mDefault;
+ private final Bitmap mDefaultBlur;
/**
* The Context to use
@@ -78,15 +95,18 @@ public abstract class ImageWorker {
*/
protected ImageWorker(final Context context) {
mContext = context.getApplicationContext();
+
+ if (sRenderScript == null) {
+ sRenderScript = RenderScript.create(mContext);
+ }
+
mResources = mContext.getResources();
// Create the default artwork
mDefault = ((BitmapDrawable) mResources.getDrawable(R.drawable.default_artwork)).getBitmap();
+ // Create the default blurred artwork
+ mDefaultBlur = ((BitmapDrawable) mResources.getDrawable(R.drawable.default_artwork_blur)).getBitmap();
// Create the transparent layer for the transition drawable
- mCurrentDrawable = new ColorDrawable(mResources.getColor(R.color.transparent));
- // A transparent image (layer 0) and the new result (layer 1)
- mArrayDrawable = new Drawable[2];
- mArrayDrawable[0] = mCurrentDrawable;
- // XXX The second layer is set in the worker task.
+ mTransparentDrawable = new ColorDrawable(Color.TRANSPARENT);
}
/**
@@ -153,7 +173,7 @@ public abstract class ImageWorker {
/**
* The actual {@link AsyncTask} that will process the image.
*/
- private final class BitmapWorkerTask extends AsyncTask<String, Void, TransitionDrawable> {
+ private class BitmapWorkerTask extends AsyncTask<String, Void, Object> {
/**
* The {@link ImageView} used to set the result
@@ -191,6 +211,11 @@ public abstract class ImageWorker {
private String mUrl;
/**
+ * Layer drawable used to cross fade the result from the worker
+ */
+ protected Drawable mFromDrawable;
+
+ /**
* Constructor of <code>BitmapWorkerTask</code>
*
* @param imageView The {@link ImageView} to use.
@@ -200,13 +225,12 @@ public abstract class ImageWorker {
public BitmapWorkerTask(final ImageView imageView, final ImageType imageType) {
mImageReference = new WeakReference<ImageView>(imageView);
mImageType = imageType;
+
+ // A transparent image (layer 0) and the new result (layer 1)
+ mFromDrawable = mTransparentDrawable;
}
- /**
- * {@inheritDoc}
- */
- @Override
- protected TransitionDrawable doInBackground(final String... params) {
+ protected Bitmap getBitmapInBackground(final String... params) {
// Define the key
mKey = params[0];
@@ -246,33 +270,33 @@ public abstract class ImageWorker {
addBitmapToCache(mKey, bitmap);
}
- // Add the second layer to the transiation drawable
- if (bitmap != null) {
- final BitmapDrawable layerTwo = new BitmapDrawable(mResources, bitmap);
- layerTwo.setFilterBitmap(false);
- layerTwo.setDither(false);
- mArrayDrawable[1] = layerTwo;
-
- // Finally, return the image
- final TransitionDrawable result = new TransitionDrawable(mArrayDrawable);
- result.setCrossFadeEnabled(true);
- result.startTransition(FADE_IN_TIME);
- return result;
- }
- return null;
+ return bitmap;
}
/**
* {@inheritDoc}
*/
@Override
- protected void onPostExecute(TransitionDrawable result) {
+ protected Object doInBackground(final String... params) {
+ final Bitmap bitmap = getBitmapInBackground(params);
+ return createImageTransitionDrawable(mResources, mFromDrawable, bitmap,
+ FADE_IN_TIME, false, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onPostExecute(Object result) {
if (isCancelled()) {
result = null;
}
+
+ TransitionDrawable transitionDrawable = (TransitionDrawable)result;
+
final ImageView imageView = getAttachedImageView();
- if (result != null && imageView != null) {
- imageView.setImageDrawable(result);
+ if (transitionDrawable != null && imageView != null) {
+ imageView.setImageDrawable(transitionDrawable);
}
}
@@ -281,7 +305,7 @@ public abstract class ImageWorker {
* the ImageView's task still points to this task as well.
* Returns null otherwise.
*/
- private final ImageView getAttachedImageView() {
+ protected ImageView getAttachedImageView() {
final ImageView imageView = mImageReference.get();
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
if (this == bitmapWorkerTask) {
@@ -292,6 +316,258 @@ public abstract class ImageWorker {
}
/**
+ * This will download the image (if needed) and create a blur and set the scrim as well on the
+ * BlurScrimImage
+ */
+ private class BlurBitmapWorkerTask extends BitmapWorkerTask {
+ // if the image is too small, the blur will look bad post scale up so we use the min size
+ // to scale up before bluring
+ private static final int MIN_BITMAP_SIZE = 500;
+ // number of times to run the blur
+ private static final int NUM_BLUR_RUNS = 8;
+ // 25f is the max blur radius possible
+ private static final float BLUR_RADIUS = 25f;
+
+ // container for the result
+ private class ResultContainer {
+ public TransitionDrawable mImageViewBitmapDrawable;
+ public int mPaletteColor;
+ }
+
+ /**
+ * The {@link BlurScrimImage} used to set the result
+ */
+ private final WeakReference<BlurScrimImage> mBlurScrimImage;
+
+ /**
+ * Constructor of <code>BitmapWorkerTask</code>
+ *
+ * @param blurScrimImage The {@link BlurScrimImage} to use.
+ * @param imageType The type of image URL to fetch for.
+ */
+ @SuppressWarnings("deprecation")
+ public BlurBitmapWorkerTask(final BlurScrimImage blurScrimImage, final ImageType imageType) {
+ super(blurScrimImage.getImageView(), imageType);
+ mBlurScrimImage = new WeakReference<BlurScrimImage>(blurScrimImage);
+
+ // use the existing image as the drawable and if it doesn't exist fallback to transparent
+ mFromDrawable = blurScrimImage.getImageView().getDrawable();
+ if (mFromDrawable == null) {
+ mFromDrawable = mTransparentDrawable;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected Object doInBackground(final String... params) {
+ Bitmap bitmap = getBitmapInBackground(params);
+
+ ResultContainer result = new ResultContainer();
+
+ Bitmap output = null;
+
+ if (bitmap != null) {
+ // now create the blur bitmap
+ Bitmap input = bitmap;
+
+ // if the image is too small, scale it up before running through the blur
+ if (input.getWidth() < MIN_BITMAP_SIZE || input.getHeight() < MIN_BITMAP_SIZE) {
+ float multiplier = Math.max(MIN_BITMAP_SIZE / (float)input.getWidth(),
+ MIN_BITMAP_SIZE / (float)input.getHeight());
+ input = input.createScaledBitmap(bitmap, (int)(input.getWidth() * multiplier),
+ (int)(input.getHeight() * multiplier), true);
+ // since we created a new bitmap, we can re-use the bitmap for our output
+ output = input;
+ } else {
+ // if we aren't creating a new bitmap, create a new output bitmap
+ output = Bitmap.createBitmap(input.getWidth(), input.getHeight(), input.getConfig());
+ }
+
+ // run the blur multiple times
+ for (int i = 0; i < NUM_BLUR_RUNS; i++) {
+ final Allocation inputAlloc = Allocation.createFromBitmap(sRenderScript, input);
+ final Allocation outputAlloc = Allocation.createTyped(sRenderScript,
+ inputAlloc.getType());
+ final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(sRenderScript,
+ Element.U8_4(sRenderScript));
+
+ script.setRadius(BLUR_RADIUS);
+ script.setInput(inputAlloc);
+ script.forEach(outputAlloc);
+ outputAlloc.copyTo(output);
+
+ // if we run more than 1 blur, the new input should be the old output
+ input = output;
+ }
+
+ // calculate the palette color
+ result.mPaletteColor = getPaletteColorInBackground(output);
+ } else {
+ // else transition to the default blur bitmap
+ output = mDefaultBlur;
+ }
+
+ // create the bitmap transition drawable
+ result.mImageViewBitmapDrawable = createImageTransitionDrawable(mResources, mFromDrawable,
+ output, FADE_IN_TIME_SLOW, true, true);
+
+ return result;
+ }
+
+ /**
+ * This will get the most vibrant palette color for a bitmap
+ * @param input to process
+ * @return the most vibrant color or transparent if none found
+ */
+ private int getPaletteColorInBackground(Bitmap input) {
+ int color = Color.TRANSPARENT;
+
+ if (input != null) {
+ Palette palette = Palette.generate(input);
+ PaletteItem paletteItem = palette.getVibrantColor();
+
+ // keep walking through the palette items to find a color if we don't have any
+ if (paletteItem == null) {
+ paletteItem = palette.getVibrantColor();
+ }
+
+ if (paletteItem == null) {
+ paletteItem = palette.getLightVibrantColor();
+ }
+
+ if (paletteItem == null) {
+ paletteItem = palette.getLightMutedColor();
+ }
+
+ if (paletteItem == null) {
+ paletteItem = palette.getLightMutedColor();
+ }
+
+ if (paletteItem == null) {
+ paletteItem = palette.getDarkVibrantColor();
+ }
+
+ if (paletteItem == null) {
+ paletteItem = palette.getMutedColor();
+ }
+
+ if (paletteItem == null) {
+ paletteItem = palette.getDarkMutedColor();
+ }
+
+ if (paletteItem != null) {
+ // grab the rgb values
+ color = paletteItem.getRgb() | 0xFFFFFF;
+
+ // make it 20% opacity
+ color &= 0x33000000;
+ }
+ }
+
+ return color;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void onPostExecute(Object result) {
+ if (isCancelled()) {
+ result = null;
+ }
+
+ ResultContainer resultContainer = (ResultContainer)result;
+
+ BlurScrimImage blurScrimImage = mBlurScrimImage.get();
+ if (blurScrimImage != null) {
+ TransitionDrawable paletteTransition = createPaletteTransition(blurScrimImage,
+ resultContainer.mPaletteColor);
+
+ blurScrimImage.setTransitionDrawable(resultContainer.mImageViewBitmapDrawable,
+ paletteTransition);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected final ImageView getAttachedImageView() {
+ final BlurScrimImage blurImage = mBlurScrimImage.get();
+ final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(blurImage);
+ if (this == bitmapWorkerTask) {
+ return blurImage.getImageView();
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Creates a transition drawable to Bitmap with params
+ * @param resources Android Resources!
+ * @param fromDrawable the drawable to transition from
+ * @param bitmap the bitmap to transition to
+ * @param fadeTime the fade time in MS to fade in
+ * @param dither setting
+ * @param force force create a transition even if bitmap == null (fade to transparent)
+ * @return the drawable if created, null otherwise
+ */
+ public static TransitionDrawable createImageTransitionDrawable(final Resources resources,
+ final Drawable fromDrawable, final Bitmap bitmap, final int fadeTime,
+ final boolean dither, final boolean force) {
+ if (bitmap != null || force) {
+ final Drawable[] arrayDrawable = new Drawable[2];
+ arrayDrawable[0] = fromDrawable;
+
+ // Add the transition to drawable
+ Drawable layerTwo;
+ if (bitmap != null) {
+ layerTwo = new BitmapDrawable(resources, bitmap);
+ layerTwo.setFilterBitmap(false);
+ layerTwo.setDither(dither);
+ } else {
+ // if no bitmap (forced) then transition to transparent
+ layerTwo = new ColorDrawable(Color.TRANSPARENT);
+ }
+
+ arrayDrawable[1] = layerTwo;
+
+ // Finally, return the image
+ final TransitionDrawable result = new TransitionDrawable(arrayDrawable);
+ result.setCrossFadeEnabled(true);
+ result.startTransition(fadeTime);
+ return result;
+ }
+
+ return null;
+ }
+
+ /**
+ * This will create the palette transition from the original color to the new one
+ * @param scrimImage the container to change the color for
+ * @param color the color to transition to
+ * @return the transition to run
+ */
+ public static TransitionDrawable createPaletteTransition(BlurScrimImage scrimImage, int color) {
+ final Drawable[] arrayDrawable = new Drawable[2];
+ arrayDrawable[0] = scrimImage.getBackground();
+
+ if (arrayDrawable[0] == null) {
+ arrayDrawable[0] = new ColorDrawable(Color.TRANSPARENT);
+ }
+
+ arrayDrawable[1] = new ColorDrawable(color);
+
+ // create the transition
+ final TransitionDrawable result = new TransitionDrawable(arrayDrawable);
+ result.setCrossFadeEnabled(true);
+ result.startTransition(FADE_IN_TIME_SLOW);
+ return result;
+ }
+
+ /**
* Calls {@code cancel()} in the worker task
*
* @param imageView the {@link ImageView} to use
@@ -310,6 +586,26 @@ public abstract class ImageWorker {
*/
public static final boolean executePotentialWork(final Object data, final ImageView imageView) {
final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
+ return executePotentialWork(data, bitmapWorkerTask);
+ }
+
+ /**
+ * Returns true if the current work has been canceled or if there was no
+ * work in progress on this image view. Returns false if the work in
+ * progress deals with the same data. The work is not stopped in that case.
+ */
+ public static final boolean executePotentialWork(final Object data, final BlurScrimImage image) {
+ final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(image);
+ return executePotentialWork(data, bitmapWorkerTask);
+ }
+
+ /**
+ * Returns true if the current work has been canceled or if there was no
+ * work in progress on this image view. Returns false if the work in
+ * progress deals with the same data. The work is not stopped in that case.
+ */
+ public static final boolean executePotentialWork(final Object data,
+ final BitmapWorkerTask bitmapWorkerTask) {
if (bitmapWorkerTask != null) {
final Object bitmapData = bitmapWorkerTask.mKey;
if (bitmapData == null || !bitmapData.equals(data)) {
@@ -342,6 +638,24 @@ public abstract class ImageWorker {
}
/**
+ * Used to determine if the current image drawable has an instance of
+ * {@link BitmapWorkerTask}
+ *
+ * @param image Any {@link BlurScrimImage}.
+ * @return Retrieve the currently active work task (if any) associated with
+ * this {@link BlurScrimImage}. null if there is no such task.
+ */
+ private static final BitmapWorkerTask getBitmapWorkerTask(final BlurScrimImage image) {
+ if (image != null) {
+ final AsyncDrawable asyncDrawable = (AsyncDrawable)image.getTag();
+ if (asyncDrawable != null) {
+ return asyncDrawable.getBitmapWorkerTask();
+ }
+ }
+ return null;
+ }
+
+ /**
* A custom {@link BitmapDrawable} that will be attached to the
* {@link ImageView} while the work is in progress. Contains a reference to
* the actual worker task, so that it can be stopped if a new binding is
@@ -417,6 +731,44 @@ public abstract class ImageWorker {
}
/**
+ * Called to fetch the blurred artist or album art.
+ *
+ * @param key The unique identifier for the image.
+ * @param artistName The artist name for the Last.fm API.
+ * @param albumName The album name for the Last.fm API.
+ * @param albumId The album art index, to check for missing artwork.
+ * @param blurScrimImage The {@link BlurScrimImage} used to set the cached
+ * {@link Bitmap}.
+ * @param imageType The type of image URL to fetch for.
+ */
+ protected void loadBlurImage(final String key, final String artistName, final String albumName,
+ final long albumId, final BlurScrimImage blurScrimImage, final ImageType imageType) {
+ if (key == null || mImageCache == null || blurScrimImage == null) {
+ return;
+ }
+
+ // Create the blur key
+ final String blurKey = key + "_blur";
+
+ if (executePotentialWork(blurKey, blurScrimImage)
+ && blurScrimImage != null && !mImageCache.isDiskCachePaused()) {
+ // Otherwise run the worker task
+ final BlurBitmapWorkerTask blurWorkerTask = new BlurBitmapWorkerTask(blurScrimImage, imageType);
+ final AsyncDrawable asyncDrawable = new AsyncDrawable(mResources, mDefault,
+ blurWorkerTask);
+ blurScrimImage.setTag(asyncDrawable);
+
+ try {
+ ApolloUtils.execute(false, blurWorkerTask, key,
+ artistName, albumName, String.valueOf(albumId));
+ } catch (RejectedExecutionException e) {
+ // Executor has exhausted queue space, show default artwork
+ blurScrimImage.transitionToDefaultState();
+ }
+ }
+ }
+
+ /**
* Subclasses should override this to define any processing or work that
* must happen to produce the final {@link Bitmap}. This will be executed in
* a background thread and be long running.
diff --git a/src/com/cyngn/eleven/slidinguppanel/SlidingUpPanelLayout.java b/src/com/cyngn/eleven/slidinguppanel/SlidingUpPanelLayout.java
index 49f7f0b..a1b823d 100644
--- a/src/com/cyngn/eleven/slidinguppanel/SlidingUpPanelLayout.java
+++ b/src/com/cyngn/eleven/slidinguppanel/SlidingUpPanelLayout.java
@@ -160,6 +160,11 @@ public class SlidingUpPanelLayout extends ViewGroup {
private View mMainView;
/**
+ * The background view
+ */
+ private View mBackgroundView;
+
+ /**
* Current state of the slideable view.
*/
private enum SlideState {
@@ -572,7 +577,7 @@ public class SlidingUpPanelLayout extends ViewGroup {
} else {
left = right = top = bottom = 0;
}
- View child = getChildAt(0);
+ View child = mMainView;
final int clampedChildLeft = Math.max(leftBound, child.getLeft());
final int clampedChildTop = Math.max(topBound, child.getTop());
final int clampedChildRight = Math.min(rightBound, child.getRight());
@@ -628,12 +633,19 @@ public class SlidingUpPanelLayout extends ViewGroup {
final int childCount = getChildCount();
- if (childCount != 2) {
- throw new IllegalStateException("Sliding up panel layout must have exactly 2 children!");
+ if (childCount != 2 && childCount != 3) {
+ throw new IllegalStateException("Sliding up panel layout must have exactly 2 or 3 children!");
+ }
+
+ if (childCount == 2) {
+ mMainView = getChildAt(0);
+ mSlideableView = getChildAt(1);
+ } else {
+ mBackgroundView = getChildAt(0);
+ mMainView = getChildAt(1);
+ mSlideableView = getChildAt(2);
}
- mMainView = getChildAt(0);
- mSlideableView = getChildAt(1);
if (mDragView == null) {
setDragView(mSlideableView);
}
@@ -651,7 +663,7 @@ public class SlidingUpPanelLayout extends ViewGroup {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
// We always measure the sliding panel in order to know it's height (needed for show panel)
- if (child.getVisibility() == GONE && i == 0) {
+ if (child.getVisibility() == GONE && child == mMainView) {
continue;
}
@@ -718,7 +730,7 @@ public class SlidingUpPanelLayout extends ViewGroup {
final View child = getChildAt(i);
// Always layout the sliding view on the first layout
- if (child.getVisibility() == GONE && (i == 0 || mFirstLayout)) {
+ if (child.getVisibility() == GONE && (child == mMainView || mFirstLayout)) {
continue;
}
@@ -1027,7 +1039,7 @@ public class SlidingUpPanelLayout extends ViewGroup {
boolean result;
final int save = canvas.save(Canvas.CLIP_SAVE_FLAG);
- if (isSlidingEnabled() && mSlideableView != child) {
+ if (isSlidingEnabled() && mMainView == child) {
// Clip against the slider; no sense drawing what will immediately be covered,
// Unless the panel is set to overlay content
if (!mOverlayContent) {
diff --git a/src/com/cyngn/eleven/ui/activities/HomeActivity.java b/src/com/cyngn/eleven/ui/activities/HomeActivity.java
index 5744c6c..98dc16e 100644
--- a/src/com/cyngn/eleven/ui/activities/HomeActivity.java
+++ b/src/com/cyngn/eleven/ui/activities/HomeActivity.java
@@ -12,26 +12,27 @@
package com.cyngn.eleven.ui.activities;
import android.content.Intent;
+import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.View;
-import android.widget.TextView;
+import android.widget.ImageView;
import com.cyngn.eleven.R;
import com.cyngn.eleven.slidinguppanel.SlidingUpPanelLayout;
import com.cyngn.eleven.slidinguppanel.SlidingUpPanelLayout.SimplePanelSlideListener;
import com.cyngn.eleven.ui.HeaderBar;
import com.cyngn.eleven.ui.fragments.AudioPlayerFragment;
-import com.cyngn.eleven.ui.fragments.QueueFragment;
import com.cyngn.eleven.ui.fragments.phone.MusicBrowserPhoneFragment;
import com.cyngn.eleven.utils.ApolloUtils;
import com.cyngn.eleven.utils.MusicUtils;
+import com.cyngn.eleven.widgets.BlurScrimImage;
/**
* This class is used to display the {@link ViewPager} used to swipe between the
* main {@link Fragment}s used to browse the user's music.
- *
+ *
* @author Andrew Neal (andrewdneal@gmail.com)
*/
public class HomeActivity extends BaseActivity {
@@ -50,6 +51,9 @@ public class HomeActivity extends BaseActivity {
private SlidingUpPanelLayout mSecondPanel;
private HeaderBar mSecondHeaderBar;
+ // this is the blurred image that goes behind the now playing and queue fragments
+ private BlurScrimImage mBlurScrimImage;
+
/**
* {@inheritDoc}
*/
@@ -65,6 +69,10 @@ public class HomeActivity extends BaseActivity {
setupFirstPanel();
setupSecondPanel();
+ // get the blur scrim image
+ findViewById(R.id.bottom_action_bar_parent).setBackgroundColor(Color.TRANSPARENT);
+ mBlurScrimImage = (BlurScrimImage)findViewById(R.id.blurScrimImage);
+
// if we've been launched by an intent, parse it
Intent launchIntent = getIntent();
if (launchIntent != null) {
@@ -215,6 +223,9 @@ public class HomeActivity extends BaseActivity {
protected void updateMetaInfo() {
super.updateMetaInfo();
+ // load the blurred image
+ mBlurScrimImage.loadBlurImage(ApolloUtils.getImageFetcher(this));
+
// Set the artist name
mFirstHeaderBar.setTitleText(MusicUtils.getArtistName());
}
@@ -228,6 +239,7 @@ public class HomeActivity extends BaseActivity {
final HeaderBar headerBar = (HeaderBar) findViewById(containerId);
headerBar.setTitleText(textId);
headerBar.setupCustomButton(customIconId, listener);
+ headerBar.setBackgroundColor(Color.TRANSPARENT);
return headerBar;
}
diff --git a/src/com/cyngn/eleven/ui/fragments/QueueFragment.java b/src/com/cyngn/eleven/ui/fragments/QueueFragment.java
index 2f06b62..1aafce8 100644
--- a/src/com/cyngn/eleven/ui/fragments/QueueFragment.java
+++ b/src/com/cyngn/eleven/ui/fragments/QueueFragment.java
@@ -130,7 +130,7 @@ public class QueueFragment extends Fragment implements LoaderCallbacks<List<Song
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create the adpater
- mAdapter = new SongAdapter(getActivity(), R.layout.edit_track_list_item);
+ mAdapter = new SongAdapter(getActivity(), R.layout.edit_queue_list_item);
}
/**
diff --git a/src/com/cyngn/eleven/ui/fragments/SongFragment.java b/src/com/cyngn/eleven/ui/fragments/SongFragment.java
index 444d81f..cc35a3b 100644
--- a/src/com/cyngn/eleven/ui/fragments/SongFragment.java
+++ b/src/com/cyngn/eleven/ui/fragments/SongFragment.java
@@ -134,7 +134,7 @@ public class SongFragment extends Fragment implements LoaderCallbacks<SectionLis
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create the adpater
- mAdapter = new SectionAdapter<Song, SongAdapter>(getActivity(), new SongAdapter(getActivity(), R.layout.list_item_song));
+ mAdapter = new SectionAdapter<Song, SongAdapter>(getActivity(), new SongAdapter(getActivity(), R.layout.list_item_simple));
}
/**
diff --git a/src/com/cyngn/eleven/utils/MusicUtils.java b/src/com/cyngn/eleven/utils/MusicUtils.java
index d8b5e98..698a9b4 100644
--- a/src/com/cyngn/eleven/utils/MusicUtils.java
+++ b/src/com/cyngn/eleven/utils/MusicUtils.java
@@ -1367,6 +1367,10 @@ public final class MusicUtils {
* @return the localized label of the bucket that the name falls into
*/
public static String getLocalizedBucketLetter(String name, boolean trimName) {
+ if (name == null || name.length() == 0) {
+ return null;
+ }
+
if (trimName) {
name = name.trim().toLowerCase();
if (name.startsWith("the ")) {
@@ -1387,7 +1391,21 @@ public final class MusicUtils {
}
if (name.length() > 0) {
- return LocaleUtils.getInstance().getLabel(name);
+ String lbl = LocaleUtils.getInstance().getLabel(name);
+ // For now let's cap it to latin alphabet and the # sign
+ // since chinese characters are resulting in " " and other random
+ // characters but the sort doesn't match the sql sort so it is
+ // not quite sorted
+ if (lbl != null && lbl.length() > 0) {
+ char ch = lbl.charAt(0);
+ if (ch < 'A' && ch > 'Z' && ch != '#') {
+ return null;
+ }
+ }
+
+ if (lbl != null && lbl.length() > 0) {
+ return lbl;
+ }
}
return null;
diff --git a/src/com/cyngn/eleven/utils/SectionCreatorUtils.java b/src/com/cyngn/eleven/utils/SectionCreatorUtils.java
index 8247cb9..9d563d2 100644
--- a/src/com/cyngn/eleven/utils/SectionCreatorUtils.java
+++ b/src/com/cyngn/eleven/utils/SectionCreatorUtils.java
@@ -50,8 +50,13 @@ public class SectionCreatorUtils {
@Override
public String createSectionSeparator(T first, T second) {
String secondLabel = createLabel(second);
- if (first == null || !createLabel(first).equals(secondLabel)) {
- return createLabel(second);
+ // if we can't determine a good label then don't bother creating a section
+ if (secondLabel == null) {
+ return null;
+ }
+
+ if (first == null || !secondLabel.equals(createLabel(first))) {
+ return secondLabel;
}
return null;
diff --git a/src/com/cyngn/eleven/widgets/BlurScrimImage.java b/src/com/cyngn/eleven/widgets/BlurScrimImage.java
new file mode 100644
index 0000000..e9be8f9
--- /dev/null
+++ b/src/com/cyngn/eleven/widgets/BlurScrimImage.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 Cyanogen, Inc.
+ */
+package com.cyngn.eleven.widgets;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.TransitionDrawable;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.cyngn.eleven.R;
+import com.cyngn.eleven.cache.ImageFetcher;
+import com.cyngn.eleven.cache.ImageWorker;
+
+public class BlurScrimImage extends FrameLayout {
+ private ImageView mImageView;
+
+ public BlurScrimImage(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mImageView = (ImageView)findViewById(R.id.blurImage);
+ }
+
+ public ImageView getImageView() {
+ return mImageView;
+ }
+
+ /**
+ * Transitions the image to the default state (default blur artwork)
+ */
+ public void transitionToDefaultState() {
+ Bitmap blurredBitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.default_artwork_blur)).getBitmap();
+
+ TransitionDrawable imageTransition = ImageWorker.createImageTransitionDrawable(getResources(),
+ mImageView.getDrawable(), blurredBitmap, ImageWorker.FADE_IN_TIME_SLOW, true, true);
+
+ TransitionDrawable paletteTransition = ImageWorker.createPaletteTransition(this,
+ Color.TRANSPARENT);
+
+
+ setTransitionDrawable(imageTransition, paletteTransition);
+ }
+
+ /**
+ * Sets the transition drawable
+ * @param imageTransition the transition for the imageview
+ * @param paletteTransition the transition for the scrim overlay
+ */
+ public void setTransitionDrawable(TransitionDrawable imageTransition,
+ TransitionDrawable paletteTransition) {
+ setBackground(paletteTransition);
+ mImageView.setImageDrawable(imageTransition);
+ }
+
+ /**
+ * Loads the current artwork into this BlurScrimImage
+ * @param imageFetcher an ImageFetcher instance
+ */
+ public void loadBlurImage(ImageFetcher imageFetcher) {
+ imageFetcher.loadCurrentBlurredArtwork(this);
+ }
+}