Allow NowPlayingActivity to stop the playback service

This commit is contained in:
Christopher Eby 2010-02-21 16:34:13 -06:00
parent 197d529fe6
commit 40ebd4ec1b
4 changed files with 149 additions and 51 deletions

View File

@ -26,6 +26,6 @@
android:id="@+id/kill_button" android:id="@+id/kill_button"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:text="Kill Service" /> android:text="Quit Service" />
</LinearLayout> </LinearLayout>
</org.kreed.tumult.RemoteLayout> </org.kreed.tumult.RemoteLayout>

View File

@ -5,6 +5,7 @@ import org.kreed.tumult.IMusicPlayerWatcher;
interface IPlaybackService { interface IPlaybackService {
void registerWatcher(IMusicPlayerWatcher watcher); void registerWatcher(IMusicPlayerWatcher watcher);
void unregisterWatcher(IMusicPlayerWatcher watcher);
Song[] getCurrentSongs(); Song[] getCurrentSongs();
Song getSong(int delta); Song getSong(int delta);

View File

@ -90,6 +90,12 @@ public class MusicPlayer implements Runnable, MediaPlayer.OnCompletionListener,
mWatchers.register(watcher); mWatchers.register(watcher);
} }
public void unregisterWatcher(IMusicPlayerWatcher watcher)
{
if (watcher != null)
mWatchers.unregister(watcher);
}
public void seekToProgress(int progress) public void seekToProgress(int progress)
{ {
if (mMediaPlayer == null || !mMediaPlayer.isPlaying()) if (mMediaPlayer == null || !mMediaPlayer.isPlaying())

View File

@ -12,14 +12,15 @@ import android.os.IBinder;
import android.os.Message; 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.KeyEvent; 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.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
@ -28,7 +29,7 @@ public class NowPlayingActivity extends Activity implements ServiceConnection, V
private ViewGroup mLayout; private ViewGroup mLayout;
private CoverView mCoverView; private CoverView mCoverView;
private LinearLayout mMessageBox; private RelativeLayout mMessageOverlay;
private View mControlsTop; private View mControlsTop;
private View mControlsBottom; private View mControlsBottom;
@ -37,11 +38,13 @@ public class NowPlayingActivity extends Activity implements ServiceConnection, V
private ImageButton mNextButton; private ImageButton mNextButton;
private SeekBar mSeekBar; private SeekBar mSeekBar;
private TextView mSeekText; private TextView mSeekText;
private Button mReconnectButton;
private int mState; private int mState;
private int mDuration; private int mDuration;
private boolean mSeekBarTracking; private boolean mSeekBarTracking;
private static final int MENU_KILL = 0;
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;
@ -76,89 +79,156 @@ public class NowPlayingActivity extends Activity implements ServiceConnection, V
mSeekBar.setOnSeekBarChangeListener(this); mSeekBar.setOnSeekBarChangeListener(this);
mSeekBar.setOnFocusChangeListener(this); mSeekBar.setOnFocusChangeListener(this);
} }
private void makeMessageOverlay()
{
if (mMessageOverlay != null) {
mMessageOverlay.removeAllViews();
return;
}
ViewGroup.LayoutParams layoutParams =
new ViewGroup.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.FILL_PARENT);
mMessageOverlay = new RelativeLayout(this);
mMessageOverlay.setLayoutParams(layoutParams);
mMessageOverlay.setBackgroundColor(Color.BLACK);
mLayout.addView(mMessageOverlay);
}
private void removeMessageOverlay()
{
mReconnectButton = null;
if (mMessageOverlay != null) {
mLayout.removeView(mMessageOverlay);
mMessageOverlay = null;
}
}
public void setState(int state) public void setState(int state)
{ {
mState = state; mState = state;
if (mService == null) {
makeMessageOverlay();
RelativeLayout.LayoutParams layoutParams =
new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
mReconnectButton = new Button(this);
mReconnectButton.setText("Connect to Service");
mReconnectButton.setLayoutParams(layoutParams);
mReconnectButton.setOnClickListener(this);
mMessageOverlay.addView(mReconnectButton);
return;
}
switch (state) { switch (state) {
case MusicPlayer.STATE_NORMAL: case MusicPlayer.STATE_NORMAL:
mControlsBottom.setVisibility(View.VISIBLE); mControlsBottom.setVisibility(View.VISIBLE);
// fall through // fall through
case MusicPlayer.STATE_PLAYING: case MusicPlayer.STATE_PLAYING:
if (mMessageBox != null) { removeMessageOverlay();
mLayout.removeView(mMessageBox);
mMessageBox = null; if (!mHandler.hasMessages(HIDE))
} mControlsBottom.setVisibility(View.GONE);
mSeekBar.setEnabled(state == MusicPlayer.STATE_PLAYING); mSeekBar.setEnabled(state == MusicPlayer.STATE_PLAYING);
mPlayPauseButton.setImageResource(state == MusicPlayer.STATE_PLAYING ? R.drawable.pause : R.drawable.play); mPlayPauseButton.setImageResource(state == MusicPlayer.STATE_PLAYING ? R.drawable.pause : R.drawable.play);
break; break;
case MusicPlayer.STATE_NO_MEDIA: case MusicPlayer.STATE_NO_MEDIA:
LinearLayout.LayoutParams layoutParams = makeMessageOverlay();
new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.FILL_PARENT); RelativeLayout.LayoutParams layoutParams =
layoutParams.gravity = Gravity.CENTER; new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
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.setLayoutParams(layoutParams); text.setLayoutParams(layoutParams);
mMessageOverlay.addView(text);
mMessageBox = new LinearLayout(this);
mMessageBox.setLayoutParams(layoutParams);
mMessageBox.setBackgroundColor(Color.BLACK);
mMessageBox.addView(text);
mLayout.addView(mMessageBox);
break; break;
} }
} }
@Override @Override
public void onResume() public void onStart()
{ {
super.onResume(); super.onStart();
reconnect(); prepareService();
} }
private void reconnect() @Override
public void onStop()
{
super.onStop();
if (mService != null) {
unbindService(this);
mHandler.sendEmptyMessage(UNSET_SERVICE);
}
}
private void prepareService()
{ {
Intent intent = new Intent(this, PlaybackService.class); Intent intent = new Intent(this, PlaybackService.class);
startService(intent); startService(intent);
bindService(intent, this, Context.BIND_AUTO_CREATE); bindService(intent, this, Context.BIND_AUTO_CREATE);
} }
@Override private void setService(IPlaybackService service)
public void onPause()
{ {
super.onPause(); if (service == mService)
return;
unbindService(this); int state = mState;
if (service == null) {
if (mService != null)
try {
mService.unregisterWatcher(mWatcher);
} catch (RemoteException e) {
}
} else {
try {
service.registerWatcher(mWatcher);
mCoverView.setPlaybackService(service);
state = service.getState();
mDuration = service.getDuration();
} catch (RemoteException e) {
Log.i("Tumult", "Failed to initialize connection to playback service", e);
return;
}
}
mService = service;
setState(state);
} }
public void onServiceConnected(ComponentName name, IBinder service) public void onServiceConnected(ComponentName name, IBinder service)
{ {
mService = IPlaybackService.Stub.asInterface(service); setService(IPlaybackService.Stub.asInterface(service));
try {
mService.registerWatcher(mWatcher);
mCoverView.setPlaybackService(mService);
setState(mService.getState());
mDuration = mService.getDuration();
} catch (RemoteException e) {
Log.i("Tumult", "Failed to initialize connection to playback service", e);
}
} }
public void onServiceDisconnected(ComponentName name) public void onServiceDisconnected(ComponentName name)
{ {
mService = null; setService(null);
reconnect();
} }
private IMusicPlayerWatcher mWatcher = new IMusicPlayerWatcher.Stub() { private IMusicPlayerWatcher mWatcher = new IMusicPlayerWatcher.Stub() {
public void songChanged(Song playingSong) public void songChanged(Song playingSong)
{ {
if (mService == null)
return;
try { try {
mDuration = mService.getDuration(); mDuration = mService.getDuration();
mHandler.sendEmptyMessage(UPDATE_PROGRESS); mHandler.sendEmptyMessage(UPDATE_PROGRESS);
@ -182,13 +252,26 @@ public class NowPlayingActivity extends Activity implements ServiceConnection, V
{ {
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");
menu.add(0, MENU_KILL, 0, "Quit Service");
return true; return true;
} }
@Override
public boolean onPrepareOptionsMenu(Menu menu)
{
menu.findItem(MENU_KILL).setEnabled(mService != null);
return true;
}
@Override @Override
public boolean onOptionsItemSelected(final MenuItem item) public boolean onOptionsItemSelected(final MenuItem item)
{ {
switch (item.getItemId()) { switch (item.getItemId()) {
case MENU_KILL:
setService(null);
unbindService(this);
stopService(new Intent(this, PlaybackService.class));
break;
case MENU_PREFS: case MENU_PREFS:
startActivity(new Intent(this, PreferencesActivity.class)); startActivity(new Intent(this, PreferencesActivity.class));
break; break;
@ -240,11 +323,12 @@ public class NowPlayingActivity extends Activity implements ServiceConnection, V
if (mControlsTop.getVisibility() != View.VISIBLE) if (mControlsTop.getVisibility() != View.VISIBLE)
return; return;
int position; int position = 0;
try { if (mService != null) {
position = mService.getPosition(); try {
} catch (RemoteException e) { position = mService.getPosition();
return; } catch (RemoteException e) {
}
} }
if (!mSeekBarTracking) if (!mSeekBarTracking)
@ -285,11 +369,14 @@ public class NowPlayingActivity extends Activity implements ServiceConnection, V
mCoverView.previousCover(); mCoverView.previousCover();
} else if (view == mPlayPauseButton) { } else if (view == mPlayPauseButton) {
mCoverView.togglePlayback(); mCoverView.togglePlayback();
} else if (view == mReconnectButton) {
prepareService();
} }
} }
private static final int HIDE = 0; private static final int HIDE = 0;
private static final int UPDATE_PROGRESS = 1; private static final int UPDATE_PROGRESS = 1;
private static final int UNSET_SERVICE = 2;
private Handler mHandler = new Handler() { private Handler mHandler = new Handler() {
public void handleMessage(Message message) { public void handleMessage(Message message) {
@ -302,17 +389,21 @@ public class NowPlayingActivity extends Activity implements ServiceConnection, V
case UPDATE_PROGRESS: case UPDATE_PROGRESS:
updateProgress(); updateProgress();
break; break;
case UNSET_SERVICE:
setService(null);
break;
} }
} }
}; };
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{ {
if (fromUser) { if (!fromUser || mService == null)
try { return;
mService.seekToProgress(progress);
} catch (RemoteException e) { try {
} mService.seekToProgress(progress);
} catch (RemoteException e) {
} }
} }