summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorlinus_lee <llee@cyngn.com>2014-11-19 17:52:53 -0800
committerlinus_lee <llee@cyngn.com>2014-12-08 15:19:02 -0800
commit8274981ad06f75f5c2ab15879083d9ee5f031554 (patch)
treec047db76e23e8aa260e76d8918653e8aa759f148 /src
parenta81b94d5f5cbdbad0a5d83b81021ab45ed66c109 (diff)
downloadandroid_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')
-rw-r--r--src/com/cyngn/eleven/ui/activities/SlidingPanelActivity.java43
-rw-r--r--src/com/cyngn/eleven/ui/fragments/AudioPlayerFragment.java50
-rw-r--r--src/com/cyngn/eleven/utils/PreferenceUtils.java7
-rw-r--r--src/com/cyngn/eleven/widgets/EqualizerView.java165
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();
+ }
+ }
+}