Android Open Source - fiction Album Swiper






From Project

Back to project page fiction.

License

The source code is released under:

GNU General Public License

If you think the Android project fiction listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.lithiumli.fiction.ui;
/*from  ww  w .  ja va  2 s  . com*/
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.widget.Scroller;

import com.lithiumli.fiction.FictionActivity;
import com.lithiumli.fiction.PlaybackQueue;
import com.lithiumli.fiction.R;
import com.lithiumli.fiction.Song;

import java.util.ArrayList;

public class AlbumSwiper extends View {
    Context mContext;
    PlaybackQueue mQueue;
    ArrayList<Cover> mCovers = new ArrayList<Cover>(3);
    double mTheta;
    FictionActivity mListener;

    float mStartX, mStartY;

    public AlbumSwiper(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
    }

    public void setQueue(PlaybackQueue queue) {
        mQueue = queue;
    }

    public void setListener(FictionActivity activity) {
        mListener = activity;
    }

    public int getRadius() {
        return (int) (getWidth() / 3f);
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        ArrayList<Cover> covers = (ArrayList<Cover>) mCovers.clone();
        java.util.Collections.sort(covers);

        for (Cover c : covers) {
            c.draw(canvas);
        }
    }

    @Override
    protected void onSizeChanged(int width, int height, int oldw, int oldh) {
        if (width == 0 || height == 0) return;
        updateCovers();
    }

  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mStartX = ev.getX();
            mStartY = ev.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            float dx = ev.getX() - mStartX;

            if (mQueue != null) {
                int pos = mQueue.getCurrentPosition();
                if (pos == 0 && dx > 0) {
                    break;
                }
                else if (pos == mQueue.getCount() - 1 && dx < 0) {
                    break;
                }
            }

            double theta = dx / getRadius();
            scroll(theta);
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            mStartX = 0f;
            mStartY = 0f;
            if (mTheta >= Math.PI / 5) {
                scrollTo(Math.PI / 4, new Runnable() {
                        @Override
                        public void run() {
                            if (mListener != null) {
                                mListener.prevButton(AlbumSwiper.this);
                            }
                        }
                    });
            }
            else if (mTheta <= -Math.PI / 5) {
                scrollTo(-Math.PI / 4, new Runnable() {
                        @Override
                        public void run() {
                            if (mListener != null) {
                                mListener.nextButton(AlbumSwiper.this);
                            }
                        }
                    });
            }
            else {
                scrollTo(0.0, null);
            }
            break;
        default:
            break;
        }
        return true;
    }

    private void scroll(double theta) {
        mTheta = theta;
        int r = getRadius();

        for (Cover c : mCovers) {
            c.setAngle(theta);
            c.setAlphaByAngle();
        }
    }

    private void scrollTo(double theta, final Runnable callback) {
        ValueAnimator a = ValueAnimator.ofFloat((float) mTheta, (float) theta);
        a.setDuration(200);
        a.addUpdateListener(
            new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator a) {
                    Float angle = (Float) a.getAnimatedValue();
                    scroll(angle.doubleValue());
                    invalidate();
                }
            });

        if (callback != null) {
            a.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator a) {
                        // TODO: reset cover angles after animation end
                        callback.run();
                    }
                });
        }

        a.start();
    }

    public void updateCovers() {
        if (mQueue == null) return;

        int count = mQueue.getCount();
        if (count <= 0) return;

        int position = mQueue.getCurrentPosition();
        Song prev = null, current = null, next = null;

        double r = (int) (getWidth() / 3.0);
        double theta = -Math.PI / 4;
        mCovers = new ArrayList<Cover>(3);
        for (int posOffset = -1; posOffset <= 1; posOffset ++) {
            int index = position + posOffset;
            int coverOffset = posOffset + 1;

            if (index >= 0) {
                Song song = mQueue.getItem(index);
                Cover c = resolve(this, song.getAlbumArt(), theta, posOffset);
                c.setAlpha((int) (255 * Math.cos(theta)));

                mCovers.add(c);
            }
            theta += Math.PI / 4;
        }
    }

    private Cover resolve(AlbumSwiper v, Uri uri, double angle, int position) {
        Drawable d = null;

        if (uri != null) {
            String scheme = uri.getScheme();

            if (ContentResolver.SCHEME_CONTENT.equals(scheme) ||
                ContentResolver.SCHEME_FILE.equals(scheme)) {
                try {
                    d = Drawable.createFromStream(
                        mContext.getContentResolver().openInputStream(uri),
                        null);
                }
                catch (Exception e) {
                }
            }
            else {
                d = Drawable.createFromPath(uri.toString());
            }
        }

        if (d == null) {
            return new Cover(
                (BitmapDrawable)
                mContext.getResources().getDrawable(R.drawable.filler_album),
                400, 400, angle, position);
        }
        else {
            BitmapDrawable b = (BitmapDrawable) d;
            int w = (int) (0.9 * getWidth());
            int h = getHeight();
            int bw = b.getIntrinsicWidth();
            int bh = b.getIntrinsicHeight();

            int fw, fh;
            if (bw > bh) {
                fw = w;
                fh = (int) (((float) bh / (float) bw) * fw);

                if (fh > h) {
                    fw = (int) (((float) h / fh) * fw);
                    fh = h;
                }
            }
            else {
                fh = h;
                fw = (int) (((float) bw / (float) bh) * fh);

                if (fw > w) {
                    fh = (int) (((float) w / fw) * fh);
                    fw = w;
                }
            }

            return new Cover(b, fw, fh, angle, position);
        }
    }

    class Cover implements Comparable {
        int width, height;
        BitmapDrawable b;
        double theta;
        int position;

        final float MIN_SCALE = (float) Math.cos(Math.PI / 4);
        final double OFFSET = Math.PI / 4;

        public Cover(BitmapDrawable _b, int _width, int _height,
                     double _theta, int _position) {
            b = _b;
            width = _width;
            height = _height;
            theta = _theta;
            position = _position;

            setBounds();
        }

        public void setBounds() {
            int r = AlbumSwiper.this.getRadius();
            int viewHeight = AlbumSwiper.this.getHeight();
            int viewWidth = AlbumSwiper.this.getWidth();
            float scale = (float) Math.cos(theta);

            if (scale < MIN_SCALE) scale = MIN_SCALE;

            int fw = (int) (scale * width);
            int fh = (int) (scale * height);
            int offsetX = (int) ((viewWidth / 2f) - (fw / 2f) +  (r * Math.sin(theta)));
            int offsetY = (viewHeight - fh) / 2;

            b.setBounds(offsetX, offsetY, fw + offsetX, fh + offsetY);
        }

        public void setAlpha(int alpha) {
            b.setAlpha(alpha);
        }

        public void setAlphaByAngle() {
            int alpha = (int) (320 * Math.cos(theta));
            if (alpha > 255) alpha = 255;
            else if (alpha < 192) alpha = 192;

            setAlpha(alpha);
        }

        public double getAngle() {
            return theta;
        }

        public void setAngle(double _theta) {
            theta = _theta + position * OFFSET;
        }

        public BitmapDrawable getDrawable() {
            return b;
        }

        public void draw(Canvas c) {
            setBounds();
            b.draw(c);
        }

        public int compareTo(Object o) {
            if (o == null) {
                return -1;
            }
            Cover c = (Cover) o;
            double a1 = Math.abs(getAngle());
            double a2 = Math.abs(c.getAngle());

            // angle of 0 is "largest"
            if (a1 > a2) {
                return -1;
            }
            else if (a2 > a1) {
                return 1;
            }
            return 0;
        }
    }
}




Java Source Code List

com.lithiumli.fiction.ArtistImageCache.java
com.lithiumli.fiction.FictionActivity.java
com.lithiumli.fiction.LibraryActivity.java
com.lithiumli.fiction.NowPlayingActivity.java
com.lithiumli.fiction.PlaybackQueue.java
com.lithiumli.fiction.PlaybackService.java
com.lithiumli.fiction.Playlist.java
com.lithiumli.fiction.PlaylistsSublibraryActivity.java
com.lithiumli.fiction.Song.java
com.lithiumli.fiction.SublibraryActivity.java
com.lithiumli.fiction.fragments.ArtistsGridFragment.java
com.lithiumli.fiction.fragments.FictionCursorAdapter.java
com.lithiumli.fiction.fragments.FictionGridFragment.java
com.lithiumli.fiction.fragments.FictionListFragment.java
com.lithiumli.fiction.fragments.PlaylistsListFragment.java
com.lithiumli.fiction.fragments.SongsListFragment.java
com.lithiumli.fiction.ui.AlbumSwiper.java
com.lithiumli.fiction.ui.SongsAlphabetIndexer.java
com.lithiumli.fiction.ui.UiUtils.java
com.lithiumli.fiction.util.BitmapLruCache.java