diff options
author | linus_lee <llee@cyngn.com> | 2014-11-19 17:52:53 -0800 |
---|---|---|
committer | linus_lee <llee@cyngn.com> | 2014-12-08 15:19:02 -0800 |
commit | 8274981ad06f75f5c2ab15879083d9ee5f031554 (patch) | |
tree | c047db76e23e8aa260e76d8918653e8aa759f148 /src | |
parent | a81b94d5f5cbdbad0a5d83b81021ab45ed66c109 (diff) | |
download | android_packages_apps_Eleven-8274981ad06f75f5c2ab15879083d9ee5f031554.tar.gz android_packages_apps_Eleven-8274981ad06f75f5c2ab15879083d9ee5f031554.tar.bz2 android_packages_apps_Eleven-8274981ad06f75f5c2ab15879083d9ee5f031554.zip |
Eleven: Add equalizer visualization
Change-Id: I9a3112cf4138e916ed53571236e54b67c30b53c4
Diffstat (limited to 'src')
4 files changed, 259 insertions, 6 deletions
diff --git a/src/com/cyngn/eleven/ui/activities/SlidingPanelActivity.java b/src/com/cyngn/eleven/ui/activities/SlidingPanelActivity.java index 717a101..eb9b904 100644 --- a/src/com/cyngn/eleven/ui/activities/SlidingPanelActivity.java +++ b/src/com/cyngn/eleven/ui/activities/SlidingPanelActivity.java @@ -28,6 +28,8 @@ import com.cyngn.eleven.utils.ApolloUtils; import com.cyngn.eleven.utils.MusicUtils; import com.cyngn.eleven.widgets.BlurScrimImage; +import java.util.HashSet; + /** * 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. @@ -43,9 +45,16 @@ public abstract class SlidingPanelActivity extends BaseActivity { None, } + public static interface ISlidingPanelListener { + public void onBeginSlide(); + public void onFinishSlide(SlidingPanelActivity.Panel visiblePanel); + } + private SlidingUpPanelLayout mFirstPanel; private SlidingUpPanelLayout mSecondPanel; protected Panel mTargetNavigatePanel; + private HashSet<ISlidingPanelListener> mSlidingPanelListeners + = new HashSet<ISlidingPanelListener>(); private final ShowPanelClickListener mShowBrowse = new ShowPanelClickListener(Panel.Browse); private final ShowPanelClickListener mShowMusicPlayer = new ShowPanelClickListener(Panel.MusicPlayer); @@ -107,6 +116,8 @@ public abstract class SlidingPanelActivity extends BaseActivity { } else if (slideOffset < 0.75f) { getActionBar().show(); } + + onSlide(); } @Override @@ -131,6 +142,8 @@ public abstract class SlidingPanelActivity extends BaseActivity { if (mTargetNavigatePanel == Panel.None) { mFirstPanel.setSlidingEnabled(false); } + + onSlide(); } @Override @@ -213,6 +226,11 @@ public abstract class SlidingPanelActivity extends BaseActivity { } public void showPanel(Panel panel) { + // if we are already at our target panel, then don't do anything + if (panel == getCurrentPanel()) { + return; + } + // TODO: Add ability to do this instantaneously as opposed to animate switch (panel) { case Browse: @@ -236,13 +254,28 @@ public abstract class SlidingPanelActivity extends BaseActivity { } } + protected void onSlide() { + for (ISlidingPanelListener listener : mSlidingPanelListeners) { + listener.onBeginSlide(); + } + } + /** * This checks if we are at our target panel and resets our flag if we are there */ protected void checkTargetNavigation() { - if (mTargetNavigatePanel == getCurrentPanel()) { + final Panel currentPanel = getCurrentPanel(); + // This checks if we are at our target panel and resets our flag if we are there + if (mTargetNavigatePanel == currentPanel) { mTargetNavigatePanel = Panel.None; } + + // if we are at the target panel + if (mTargetNavigatePanel == Panel.None) { + for (ISlidingPanelListener listener : mSlidingPanelListeners) { + listener.onFinishSlide(currentPanel); + } + } } protected Panel getCurrentPanel() { @@ -309,4 +342,12 @@ public abstract class SlidingPanelActivity extends BaseActivity { showPanel(mTargetPanel); } } + + public void addSlidingPanelListener(final ISlidingPanelListener listener) { + mSlidingPanelListeners.add(listener); + } + + public void removeSlidingPanelListener(final ISlidingPanelListener listener) { + mSlidingPanelListeners.remove(listener); + } } diff --git a/src/com/cyngn/eleven/ui/fragments/AudioPlayerFragment.java b/src/com/cyngn/eleven/ui/fragments/AudioPlayerFragment.java index 44690c6..98a1be0 100644 --- a/src/com/cyngn/eleven/ui/fragments/AudioPlayerFragment.java +++ b/src/com/cyngn/eleven/ui/fragments/AudioPlayerFragment.java @@ -10,14 +10,10 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.media.AudioManager; -import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; -import android.provider.MediaStore.Audio.Albums; -import android.provider.MediaStore.Audio.Artists; -import android.provider.MediaStore.Audio.Playlists; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.util.Log; @@ -41,10 +37,13 @@ import com.cyngn.eleven.loaders.QueueLoader; import com.cyngn.eleven.menu.CreateNewPlaylist; import com.cyngn.eleven.menu.DeleteDialog; import com.cyngn.eleven.menu.FragmentMenuItems; +import com.cyngn.eleven.ui.activities.SlidingPanelActivity; import com.cyngn.eleven.utils.ApolloUtils; import com.cyngn.eleven.utils.MusicUtils; import com.cyngn.eleven.utils.NavUtils; +import com.cyngn.eleven.utils.PreferenceUtils; import com.cyngn.eleven.widgets.BrowseButton; +import com.cyngn.eleven.widgets.EqualizerView; import com.cyngn.eleven.widgets.LoadingEmptyContainer; import com.cyngn.eleven.widgets.NoResultsContainer; import com.cyngn.eleven.widgets.PlayPauseProgressButton; @@ -58,7 +57,8 @@ import java.lang.ref.WeakReference; import static com.cyngn.eleven.utils.MusicUtils.mService; -public class AudioPlayerFragment extends Fragment implements ServiceConnection { +public class AudioPlayerFragment extends Fragment implements ServiceConnection, + SlidingPanelActivity.ISlidingPanelListener { private static final String TAG = AudioPlayerFragment.class.getSimpleName(); /** @@ -115,6 +115,12 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { // Total time private TextView mTotalTime; + // Equalizer View + private EqualizerView mEqualizerView; + + // Equalizer Gradient + private View mEqualizerGradient; + // Broadcast receiver private PlaybackStatus mPlaybackStatus; @@ -151,6 +157,9 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { // Initialize the broadcast receiver mPlaybackStatus = new PlaybackStatus(this); + + // add a listener for the sliding + ((SlidingPanelActivity)getActivity()).addSlidingPanelListener(this); } /** @@ -166,6 +175,11 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { initHeaderBar(); initPlaybackControls(); + + mEqualizerView = (EqualizerView) mRootView.findViewById(R.id.equalizerView); + mEqualizerView.initialize(getActivity()); + mEqualizerGradient = mRootView.findViewById(R.id.equalizerGradient); + return mRootView; } @@ -210,6 +224,8 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { // resumes the update callback for the play pause progress button mPlayPauseProgressButton.resume(); + + mEqualizerView.onStart(); } @Override @@ -220,6 +236,8 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { mPlayPauseProgressButton.pause(); mImageFetcher.flush(); + + mEqualizerView.onStop(); } @Override @@ -234,6 +252,8 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { mToken = null; } + ((SlidingPanelActivity)getActivity()).removeSlidingPanelListener(this); + // Unregister the receiver try { getActivity().unregisterReceiver(mPlaybackStatus); @@ -423,10 +443,18 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { if(queueSize == 0) { mAlbumArtViewPager.setVisibility(View.GONE); mQueueEmpty.showNoResults(); + mEqualizerGradient.setVisibility(View.GONE); + mEqualizerView.checkStateChanged(); mAddToPlaylistButton.setVisibility(View.GONE); } else { mAlbumArtViewPager.setVisibility(View.VISIBLE); mQueueEmpty.hideAll(); + if (PreferenceUtils.getInstance(getActivity()).getShowVisualizer()) { + mEqualizerGradient.setVisibility(View.VISIBLE); + } else { + mEqualizerGradient.setVisibility(View.GONE); + } + mEqualizerView.checkStateChanged(); mAddToPlaylistButton.setVisibility(View.VISIBLE); } } @@ -657,6 +685,18 @@ public class AudioPlayerFragment extends Fragment implements ServiceConnection { return super.onContextItemSelected(item); } + @Override + public void onBeginSlide() { + mEqualizerView.setPanelVisible(false); + } + + @Override + public void onFinishSlide(SlidingPanelActivity.Panel visiblePanel) { + if (visiblePanel == SlidingPanelActivity.Panel.MusicPlayer) { + mEqualizerView.setPanelVisible(true); + } + } + /** * Used to update the current time string */ diff --git a/src/com/cyngn/eleven/utils/PreferenceUtils.java b/src/com/cyngn/eleven/utils/PreferenceUtils.java index 903371f..61351cc 100644 --- a/src/com/cyngn/eleven/utils/PreferenceUtils.java +++ b/src/com/cyngn/eleven/utils/PreferenceUtils.java @@ -69,6 +69,9 @@ public final class PreferenceUtils { // datetime cutoff for determining which songs go in last added playlist public static final String LAST_ADDED_CUTOFF = "last_added_cutoff"; + // show visualizer flag + public static final String SHOW_VISUALIZER = "music_visualization"; + private static PreferenceUtils sInstance; private final SharedPreferences mPreferences; @@ -303,4 +306,8 @@ public final class PreferenceUtils { public long getLastAddedCutoff() { return mPreferences.getLong(LAST_ADDED_CUTOFF, 0L); } + + public boolean getShowVisualizer() { + return mPreferences.getBoolean(SHOW_VISUALIZER, true); + } } diff --git a/src/com/cyngn/eleven/widgets/EqualizerView.java b/src/com/cyngn/eleven/widgets/EqualizerView.java new file mode 100644 index 0000000..5814692 --- /dev/null +++ b/src/com/cyngn/eleven/widgets/EqualizerView.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2014 Cyanogen, Inc. + */ +package com.cyngn.eleven.widgets; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.DashPathEffect; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.Log; + +import com.cyngn.eleven.R; +import com.cyngn.eleven.utils.MusicUtils; +import com.cyngn.eleven.utils.PreferenceUtils; +import com.pheelicks.visualizer.AudioData; +import com.pheelicks.visualizer.FFTData; +import com.pheelicks.visualizer.VisualizerView; +import com.pheelicks.visualizer.renderer.Renderer; + +public class EqualizerView extends VisualizerView { + private boolean mLinked = false; + private boolean mStarted = false; + private boolean mPanelVisible = false; + + private final Runnable mLinkVisualizer = new Runnable() { + @Override + public void run() { + if (!mLinked) { + animate().alpha(1).setDuration(300); + link(0); + mLinked = true; + } + } + }; + + private final Runnable mUnlinkVisualizer = new Runnable() { + @Override + public void run() { + if (mLinked) { + animate().alpha(0).setDuration(300); + unlink(); + mLinked = false; + } + } + }; + + private static class TileBarGraphRenderer extends Renderer { + private int mDivisions; + private Paint mPaint; + private int mDbFuzz; + private int mDbFuzzFactor; + + /** + * Renders the FFT data as a series of lines, in histogram form + * + * @param divisions - must be a power of 2. Controls how many lines to draw + * @param paint - Paint to draw lines with + * @param dbfuzz - final dB display adjustment + * @param dbFactor - dbfuzz is multiplied by dbFactor. + */ + public TileBarGraphRenderer(int divisions, Paint paint, int dbfuzz, int dbFactor) { + super(); + mDivisions = divisions; + mPaint = paint; + mDbFuzz = dbfuzz; + mDbFuzzFactor = dbFactor; + } + + @Override + public void onRender(Canvas canvas, AudioData data, Rect rect) { + // Do nothing, we only display FFT data + } + + @Override + public void onRender(Canvas canvas, FFTData data, Rect rect) { + for (int i = 0; i < data.bytes.length / mDivisions; i++) { + mFFTPoints[i * 4] = i * 4 * mDivisions; + mFFTPoints[i * 4 + 2] = i * 4 * mDivisions; + byte rfk = data.bytes[mDivisions * i]; + byte ifk = data.bytes[mDivisions * i + 1]; + float magnitude = (rfk * rfk + ifk * ifk); + int dbValue = (int) (10 * Math.log10(magnitude)); + + mFFTPoints[i * 4 + 1] = rect.height(); + mFFTPoints[i * 4 + 3] = rect.height() - (dbValue * mDbFuzzFactor + mDbFuzz); + } + + canvas.drawLines(mFFTPoints, mPaint); + } + } + + public EqualizerView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public EqualizerView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public EqualizerView(Context context) { + this(context, null, 0); + } + + public void initialize(Context context) { + setEnabled(false); + + Resources res = mContext.getResources(); + Paint paint = new Paint(); + paint.setStrokeWidth(res.getDimensionPixelSize(R.dimen.eqalizer_path_stroke_width)); + paint.setAntiAlias(true); + paint.setColor(res.getColor(R.color.equalizer_fill_color)); + paint.setPathEffect(new DashPathEffect(new float[]{ + res.getDimensionPixelSize(R.dimen.eqalizer_path_effect_1), + res.getDimensionPixelSize(R.dimen.eqalizer_path_effect_2) + }, 0)); + + int bars = res.getInteger(R.integer.equalizer_divisions); + addRenderer(new TileBarGraphRenderer(bars, paint, + res.getInteger(R.integer.equalizer_db_fuzz), + res.getInteger(R.integer.equalizer_db_fuzz_factor))); + } + + /** + * Follows Fragment onStart to determine if the containing fragment/activity is started + */ + public void onStart() { + mStarted = true; + checkStateChanged(); + } + + /** + * Follows Fragment onStop to determine if the containing fragment/activity is stopped + */ + public void onStop() { + mStarted = false; + checkStateChanged(); + } + + /** + * Separate method to toggle panel visibility - currently used when the user slides to + * improve performance of the sliding panel + */ + public void setPanelVisible(boolean panelVisible) { + if (mPanelVisible != panelVisible) { + mPanelVisible = panelVisible; + checkStateChanged(); + } + } + + /** + * Checks the state of the EqualizerView to determine whether we want to link up the equalizer + */ + public void checkStateChanged() { + if (mPanelVisible && mStarted + && PreferenceUtils.getInstance(mContext).getShowVisualizer() + && MusicUtils.getQueueSize() > 0) { + mLinkVisualizer.run(); + } else { + mUnlinkVisualizer.run(); + } + } +} |