Rework the media controls, adding a seek bar
The media controls now appear after clicking on the cover view and disppear after a period of inactivity. The previous and next menu entries have been removed in favor of the previous and next buttons and the media control view.
10
res/drawable/next.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/next_focused" />
|
||||||
|
<item
|
||||||
|
android:state_focused="true"
|
||||||
|
android:drawable="@drawable/next_focused" />
|
||||||
|
<item android:drawable="@drawable/next_normal" />
|
||||||
|
</selector>
|
BIN
res/drawable/next_focused.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
res/drawable/next_normal.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
10
res/drawable/pause.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/pause_focused" />
|
||||||
|
<item
|
||||||
|
android:state_focused="true"
|
||||||
|
android:drawable="@drawable/pause_focused" />
|
||||||
|
<item android:drawable="@drawable/pause_normal" />
|
||||||
|
</selector>
|
BIN
res/drawable/pause_focused.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
res/drawable/pause_normal.png
Normal file
After Width: | Height: | Size: 1003 B |
10
res/drawable/play.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/play_focused" />
|
||||||
|
<item
|
||||||
|
android:state_focused="true"
|
||||||
|
android:drawable="@drawable/play_focused" />
|
||||||
|
<item android:drawable="@drawable/play_normal" />
|
||||||
|
</selector>
|
BIN
res/drawable/play_focused.png
Normal file
After Width: | Height: | Size: 910 B |
BIN
res/drawable/play_normal.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
10
res/drawable/previous.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:state_pressed="true"
|
||||||
|
android:drawable="@drawable/previous_focused" />
|
||||||
|
<item
|
||||||
|
android:state_focused="true"
|
||||||
|
android:drawable="@drawable/previous_focused" />
|
||||||
|
<item android:drawable="@drawable/previous_normal" />
|
||||||
|
</selector>
|
BIN
res/drawable/previous_focused.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
res/drawable/previous_normal.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
59
res/layout/nowplaying.xml
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<org.kreed.tumult.CoverView
|
||||||
|
android:id="@+id/cover_view"
|
||||||
|
android:layout_height="fill_parent"
|
||||||
|
android:layout_width="fill_parent" />
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/controls"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_gravity="bottom|center_horizontal"
|
||||||
|
android:background="#000"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/previous"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:background="@null"
|
||||||
|
android:src="@drawable/previous" />
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/play_pause"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_marginLeft="25px"
|
||||||
|
android:background="@null"
|
||||||
|
android:src="@drawable/play" />
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/next"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_marginLeft="25px"
|
||||||
|
android:background="@null"
|
||||||
|
android:src="@drawable/next" />
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<SeekBar
|
||||||
|
android:id="@+id/seek_bar"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/seek_text"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="0:00 / 0:00" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</merge>
|
@ -8,6 +8,7 @@ import android.graphics.Paint;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.RectF;
|
import android.graphics.RectF;
|
||||||
import android.graphics.Region;
|
import android.graphics.Region;
|
||||||
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.VelocityTracker;
|
import android.view.VelocityTracker;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -32,17 +33,17 @@ public class CoverView extends View {
|
|||||||
public interface CoverViewWatcher {
|
public interface CoverViewWatcher {
|
||||||
public void next();
|
public void next();
|
||||||
public void previous();
|
public void previous();
|
||||||
public void togglePlayback();
|
public void clicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
public CoverView(Context context)
|
public CoverView(Context context, AttributeSet attributes)
|
||||||
{
|
{
|
||||||
super(context);
|
super(context, attributes);
|
||||||
|
|
||||||
mScroller = new Scroller(context);
|
mScroller = new Scroller(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCoverSwapListener(CoverViewWatcher listener)
|
public void setWatcher(CoverViewWatcher listener)
|
||||||
{
|
{
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
}
|
}
|
||||||
@ -254,7 +255,7 @@ public class CoverView extends View {
|
|||||||
break;
|
break;
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
if (Math.abs(mStartX - x) + Math.abs(mStartY - ev.getY()) < 10) {
|
if (Math.abs(mStartX - x) + Math.abs(mStartY - ev.getY()) < 10) {
|
||||||
mListener.togglePlayback();
|
mListener.clicked();
|
||||||
} else {
|
} else {
|
||||||
VelocityTracker velocityTracker = mVelocityTracker;
|
VelocityTracker velocityTracker = mVelocityTracker;
|
||||||
velocityTracker.computeCurrentVelocity(1000);
|
velocityTracker.computeCurrentVelocity(1000);
|
||||||
|
@ -6,4 +6,5 @@ oneway interface IMusicPlayerWatcher {
|
|||||||
void previousSong(in Song playingSong, in Song nextForwardSong);
|
void previousSong(in Song playingSong, in Song nextForwardSong);
|
||||||
void nextSong(in Song playingSong, in Song nextBackwardSong);
|
void nextSong(in Song playingSong, in Song nextBackwardSong);
|
||||||
void stateChanged(in int oldState, in int newState);
|
void stateChanged(in int oldState, in int newState);
|
||||||
|
void mediaLengthChanged(in long startTime, in int duration);
|
||||||
}
|
}
|
@ -7,8 +7,12 @@ interface IPlaybackService {
|
|||||||
void registerWatcher(IMusicPlayerWatcher watcher);
|
void registerWatcher(IMusicPlayerWatcher watcher);
|
||||||
|
|
||||||
Song[] getCurrentSongs();
|
Song[] getCurrentSongs();
|
||||||
|
int getState();
|
||||||
|
long getStartTime();
|
||||||
|
int getDuration();
|
||||||
|
|
||||||
void previousSong();
|
void previousSong();
|
||||||
void togglePlayback();
|
void togglePlayback();
|
||||||
void nextSong();
|
void nextSong();
|
||||||
|
void seekToProgress(int progress);
|
||||||
}
|
}
|
@ -29,6 +29,7 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
|||||||
|
|
||||||
public static final int STATE_NORMAL = 0;
|
public static final int STATE_NORMAL = 0;
|
||||||
public static final int STATE_NO_MEDIA = 1;
|
public static final int STATE_NO_MEDIA = 1;
|
||||||
|
public static final int STATE_PLAYING = 2;
|
||||||
|
|
||||||
public IPlaybackService.Stub mBinder = new IPlaybackService.Stub() {
|
public IPlaybackService.Stub mBinder = new IPlaybackService.Stub() {
|
||||||
public Song[] getCurrentSongs()
|
public Song[] getCurrentSongs()
|
||||||
@ -36,6 +37,25 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
|||||||
return new Song[] { getSong(-1), getSong(0), getSong(1) };
|
return new Song[] { getSong(-1), getSong(0), getSong(1) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getState()
|
||||||
|
{
|
||||||
|
return mState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getStartTime()
|
||||||
|
{
|
||||||
|
if (mMediaPlayer == null)
|
||||||
|
return 0;
|
||||||
|
return MusicPlayer.this.getStartTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDuration()
|
||||||
|
{
|
||||||
|
if (mMediaPlayer == null)
|
||||||
|
return 0;
|
||||||
|
return mMediaPlayer.getDuration();
|
||||||
|
}
|
||||||
|
|
||||||
public void nextSong()
|
public void nextSong()
|
||||||
{
|
{
|
||||||
if (mHandler == null)
|
if (mHandler == null)
|
||||||
@ -62,6 +82,16 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
|||||||
if (watcher != null)
|
if (watcher != null)
|
||||||
mWatchers.register(watcher);
|
mWatchers.register(watcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void seekToProgress(int progress)
|
||||||
|
{
|
||||||
|
if (mMediaPlayer == null || !mMediaPlayer.isPlaying())
|
||||||
|
return;
|
||||||
|
|
||||||
|
long position = (long)mMediaPlayer.getDuration() * progress / 1000;
|
||||||
|
mMediaPlayer.seekTo((int)position);
|
||||||
|
mediaLengthChanged();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public void queueSong(int songId)
|
public void queueSong(int songId)
|
||||||
@ -201,6 +231,9 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
|||||||
|
|
||||||
public void setState(int state)
|
public void setState(int state)
|
||||||
{
|
{
|
||||||
|
if (mState == state)
|
||||||
|
return;
|
||||||
|
|
||||||
int oldState = mState;
|
int oldState = mState;
|
||||||
mState = state;
|
mState = state;
|
||||||
|
|
||||||
@ -244,12 +277,15 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
|||||||
notification.contentIntent = PendingIntent.getActivity(mService, 0, intent, 0);
|
notification.contentIntent = PendingIntent.getActivity(mService, 0, intent, 0);
|
||||||
|
|
||||||
mService.startForegroundCompat(NOTIFICATION_ID, notification);
|
mService.startForegroundCompat(NOTIFICATION_ID, notification);
|
||||||
|
|
||||||
|
setState(STATE_PLAYING);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pause()
|
private void pause()
|
||||||
{
|
{
|
||||||
mMediaPlayer.pause();
|
mMediaPlayer.pause();
|
||||||
mService.stopForegroundCompat(NOTIFICATION_ID);
|
mService.stopForegroundCompat(NOTIFICATION_ID);
|
||||||
|
setState(STATE_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPlaying(boolean play)
|
private void setPlaying(boolean play)
|
||||||
@ -291,6 +327,8 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
|||||||
Log.e("Tumult", "IOException", e);
|
Log.e("Tumult", "IOException", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mediaLengthChanged();
|
||||||
|
|
||||||
getSong(+2);
|
getSong(+2);
|
||||||
|
|
||||||
while (mCurrentSong > 15) {
|
while (mCurrentSong > 15) {
|
||||||
@ -299,6 +337,28 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getStartTime()
|
||||||
|
{
|
||||||
|
int position = mMediaPlayer.getCurrentPosition();
|
||||||
|
return System.currentTimeMillis() - position;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mediaLengthChanged()
|
||||||
|
{
|
||||||
|
long start = getStartTime();
|
||||||
|
int duration = mMediaPlayer.getDuration();
|
||||||
|
|
||||||
|
int i = mWatchers.beginBroadcast();
|
||||||
|
while (--i != -1) {
|
||||||
|
try {
|
||||||
|
mWatchers.getBroadcastItem(i).mediaLengthChanged(start, duration);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// Null elements will be removed automatically
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mWatchers.finishBroadcast();
|
||||||
|
}
|
||||||
|
|
||||||
public void onCompletion(MediaPlayer player)
|
public void onCompletion(MediaPlayer player)
|
||||||
{
|
{
|
||||||
setCurrentSong(+1);
|
setCurrentSong(+1);
|
||||||
|
@ -8,22 +8,41 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.os.Message;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
|
import android.view.KeyEvent;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageButton;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
public class NowPlayingActivity extends Activity implements CoverViewWatcher, ServiceConnection {
|
public class NowPlayingActivity extends Activity implements CoverViewWatcher, ServiceConnection, View.OnClickListener, SeekBar.OnSeekBarChangeListener {
|
||||||
private IPlaybackService mService;
|
private IPlaybackService mService;
|
||||||
|
|
||||||
|
private ViewGroup mLayout;
|
||||||
private CoverView mCoverView;
|
private CoverView mCoverView;
|
||||||
private LinearLayout mMessageBox;
|
private LinearLayout mMessageBox;
|
||||||
|
private View mControls;
|
||||||
|
|
||||||
|
private ImageButton mPreviousButton;
|
||||||
|
private ImageButton mPlayPauseButton;
|
||||||
|
private ImageButton mNextButton;
|
||||||
|
private SeekBar mSeekBar;
|
||||||
|
private TextView mSeekText;
|
||||||
|
|
||||||
|
private int mState;
|
||||||
|
private long mStartTime;
|
||||||
|
private int mDuration;
|
||||||
|
private boolean mSeekBarTracking;
|
||||||
|
|
||||||
private static final int MENU_PREVIOUS = 0;
|
|
||||||
private static final int MENU_NEXT = 1;
|
|
||||||
private static final int MENU_PREFS = 2;
|
private static final int MENU_PREFS = 2;
|
||||||
private static final int MENU_QUEUE = 3;
|
private static final int MENU_QUEUE = 3;
|
||||||
|
|
||||||
@ -32,18 +51,40 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
|||||||
{
|
{
|
||||||
super.onCreate(icicle);
|
super.onCreate(icicle);
|
||||||
|
|
||||||
mCoverView = new CoverView(this);
|
setContentView(R.layout.nowplaying);
|
||||||
mCoverView.setCoverSwapListener(this);;
|
|
||||||
setContentView(mCoverView);
|
mCoverView = (CoverView)findViewById(R.id.cover_view);
|
||||||
// Bundle extras = getIntent().getExtras();
|
mCoverView.setWatcher(this);
|
||||||
|
|
||||||
|
mLayout = (ViewGroup)mCoverView.getParent();
|
||||||
|
|
||||||
|
mControls = findViewById(R.id.controls);
|
||||||
|
|
||||||
|
mPreviousButton = (ImageButton)findViewById(R.id.previous);
|
||||||
|
mPreviousButton.setOnClickListener(this);
|
||||||
|
mPlayPauseButton = (ImageButton)findViewById(R.id.play_pause);
|
||||||
|
mPlayPauseButton.setOnClickListener(this);
|
||||||
|
mNextButton = (ImageButton)findViewById(R.id.next);
|
||||||
|
mNextButton.setOnClickListener(this);
|
||||||
|
|
||||||
|
mSeekText = (TextView)findViewById(R.id.seek_text);
|
||||||
|
mSeekBar = (SeekBar)findViewById(R.id.seek_bar);
|
||||||
|
mSeekBar.setMax(1000);
|
||||||
|
mSeekBar.setOnSeekBarChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setState(int state)
|
public void setState(int state)
|
||||||
{
|
{
|
||||||
|
mState = state;
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case MusicPlayer.STATE_NORMAL:
|
case MusicPlayer.STATE_NORMAL:
|
||||||
setContentView(mCoverView);
|
case MusicPlayer.STATE_PLAYING:
|
||||||
|
if (mMessageBox != null) {
|
||||||
|
mLayout.removeView(mMessageBox);
|
||||||
mMessageBox = null;
|
mMessageBox = null;
|
||||||
|
}
|
||||||
|
mPlayPauseButton.setImageResource(state == MusicPlayer.STATE_PLAYING ? R.drawable.pause : R.drawable.play);
|
||||||
break;
|
break;
|
||||||
case MusicPlayer.STATE_NO_MEDIA:
|
case MusicPlayer.STATE_NO_MEDIA:
|
||||||
mMessageBox = new LinearLayout(this);
|
mMessageBox = new LinearLayout(this);
|
||||||
@ -51,11 +92,11 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
|||||||
TextView text = new TextView(this);
|
TextView text = new TextView(this);
|
||||||
text.setText("No songs found on your device.");
|
text.setText("No songs found on your device.");
|
||||||
text.setGravity(Gravity.CENTER);
|
text.setGravity(Gravity.CENTER);
|
||||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
|
||||||
layoutParams.gravity = Gravity.CENTER;
|
layoutParams.gravity = Gravity.CENTER;
|
||||||
text.setLayoutParams(layoutParams);
|
text.setLayoutParams(layoutParams);
|
||||||
mMessageBox.addView(text);
|
mMessageBox.addView(text);
|
||||||
setContentView(mMessageBox);
|
mLayout.addView(mMessageBox);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,6 +139,7 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
|||||||
try {
|
try {
|
||||||
mService.registerWatcher(mWatcher);
|
mService.registerWatcher(mWatcher);
|
||||||
refreshSongs();
|
refreshSongs();
|
||||||
|
setState(mService.getState());
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
Log.i("Tumult", "Failed to initialize connection to playback service", e);
|
Log.i("Tumult", "Failed to initialize connection to playback service", e);
|
||||||
}
|
}
|
||||||
@ -147,6 +189,12 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void mediaLengthChanged(long startTime, int duration)
|
||||||
|
{
|
||||||
|
mStartTime = startTime;
|
||||||
|
mDuration = duration;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public void next()
|
public void next()
|
||||||
@ -167,7 +215,7 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void togglePlayback()
|
private void togglePlayback()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
mService.togglePlayback();
|
mService.togglePlayback();
|
||||||
@ -178,8 +226,6 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
|||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu)
|
public boolean onCreateOptionsMenu(Menu menu)
|
||||||
{
|
{
|
||||||
menu.add(0, MENU_PREVIOUS, 0, "Previous");
|
|
||||||
menu.add(0, MENU_NEXT, 0, "Next");
|
|
||||||
menu.add(0, MENU_PREFS, 0, "Preferences");
|
menu.add(0, MENU_PREFS, 0, "Preferences");
|
||||||
menu.add(0, MENU_QUEUE, 0, "Add to Queue");
|
menu.add(0, MENU_QUEUE, 0, "Add to Queue");
|
||||||
return true;
|
return true;
|
||||||
@ -187,26 +233,15 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item)
|
public boolean onOptionsItemSelected(final MenuItem item)
|
||||||
{
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
public void run()
|
|
||||||
{
|
{
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case MENU_PREVIOUS:
|
|
||||||
previous();
|
|
||||||
break;
|
|
||||||
case MENU_NEXT:
|
|
||||||
next();
|
|
||||||
break;
|
|
||||||
case MENU_PREFS:
|
case MENU_PREFS:
|
||||||
startActivity(new Intent(NowPlayingActivity.this, PreferencesActivity.class));
|
startActivity(new Intent(this, PreferencesActivity.class));
|
||||||
break;
|
break;
|
||||||
case MENU_QUEUE:
|
case MENU_QUEUE:
|
||||||
onSearchRequested();
|
onSearchRequested();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -217,4 +252,121 @@ public class NowPlayingActivity extends Activity implements CoverViewWatcher, Se
|
|||||||
startActivity(new Intent(this, SongSelector.class));
|
startActivity(new Intent(this, SongSelector.class));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyUp(int keyCode, KeyEvent event)
|
||||||
|
{
|
||||||
|
switch (keyCode) {
|
||||||
|
case KeyEvent.KEYCODE_DPAD_CENTER:
|
||||||
|
case KeyEvent.KEYCODE_ENTER:
|
||||||
|
clicked();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clicked()
|
||||||
|
{
|
||||||
|
mControls.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
if (mStartTime == 0) {
|
||||||
|
try {
|
||||||
|
mStartTime = mService.getStartTime();
|
||||||
|
mDuration = mService.getDuration();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateProgress();
|
||||||
|
sendHideMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String stringForTime(int ms)
|
||||||
|
{
|
||||||
|
int seconds = ms / 1000;
|
||||||
|
|
||||||
|
int hours = seconds / 3600;
|
||||||
|
seconds -= hours * 3600;
|
||||||
|
int minutes = seconds / 60;
|
||||||
|
seconds -= minutes * 60;
|
||||||
|
|
||||||
|
if (hours > 0)
|
||||||
|
return String.format("%d:%02d:%02d", hours, minutes, seconds);
|
||||||
|
else
|
||||||
|
return String.format("%02d:%02d", minutes, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateProgress()
|
||||||
|
{
|
||||||
|
if (mState != MusicPlayer.STATE_PLAYING || mControls.getVisibility() != View.VISIBLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
long position = System.currentTimeMillis() - mStartTime;
|
||||||
|
if (!mSeekBarTracking)
|
||||||
|
mSeekBar.setProgress((int)(1000 * position / mDuration));
|
||||||
|
mSeekText.setText(stringForTime((int)position) + " / " + stringForTime(mDuration));
|
||||||
|
|
||||||
|
long next = 1000 - position % 1000;
|
||||||
|
mHandler.sendMessageDelayed(mHandler.obtainMessage(UPDATE_PROGRESS), next);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendHideMessage()
|
||||||
|
{
|
||||||
|
Message message = mHandler.obtainMessage(HIDE);
|
||||||
|
mHandler.removeMessages(HIDE);
|
||||||
|
mHandler.sendMessageDelayed(message, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onClick(View view)
|
||||||
|
{
|
||||||
|
sendHideMessage();
|
||||||
|
|
||||||
|
if (view == mNextButton) {
|
||||||
|
next();
|
||||||
|
} else if (view == mPreviousButton) {
|
||||||
|
previous();
|
||||||
|
} else if (view == mPlayPauseButton) {
|
||||||
|
togglePlayback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int HIDE = 0;
|
||||||
|
private static final int UPDATE_PROGRESS = 1;
|
||||||
|
|
||||||
|
private Handler mHandler = new Handler() {
|
||||||
|
public void handleMessage(Message message) {
|
||||||
|
switch (message.what) {
|
||||||
|
case HIDE:
|
||||||
|
mControls.setVisibility(View.GONE);
|
||||||
|
break;
|
||||||
|
case UPDATE_PROGRESS:
|
||||||
|
updateProgress();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
|
||||||
|
{
|
||||||
|
if (fromUser) {
|
||||||
|
try {
|
||||||
|
mService.seekToProgress(progress);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onStartTrackingTouch(SeekBar seekBar)
|
||||||
|
{
|
||||||
|
mHandler.removeMessages(HIDE);
|
||||||
|
mSeekBarTracking = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onStopTrackingTouch(SeekBar seekBar)
|
||||||
|
{
|
||||||
|
sendHideMessage();
|
||||||
|
mSeekBarTracking = false;
|
||||||
|
}
|
||||||
}
|
}
|