Handle the media buttons inside the service
It seems to be faster and cheaper to do this. External receiver is still necessary to fire up the service however.
This commit is contained in:
parent
fe3cfe8bc6
commit
80a6cbd201
@ -18,100 +18,23 @@
|
||||
|
||||
package org.kreed.vanilla;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.view.KeyEvent;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
public class MediaButtonReceiver extends BroadcastReceiver {
|
||||
public static final String ENABLE = "org.kreed.vanilla.action.ENABLE_RECEIVER";
|
||||
|
||||
private static final int MSG_MEDIA_CLICK = 2;
|
||||
private static final int DOUBLE_CLICK_DELAY = 300;
|
||||
|
||||
private static boolean mEnabled = true;
|
||||
private static boolean mIgnoreNextUp;
|
||||
|
||||
private static Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg)
|
||||
{
|
||||
switch (msg.what) {
|
||||
case MSG_MEDIA_CLICK:
|
||||
try {
|
||||
((PendingIntent)msg.obj).send();
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static Intent getCommand(Context context, String action)
|
||||
{
|
||||
return new Intent(context, PlaybackService.class).setAction(action).putExtra("autoplay", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
String intentAction = intent.getAction();
|
||||
|
||||
if (mEnabled && Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
|
||||
KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
|
||||
if (event == null)
|
||||
return;
|
||||
|
||||
int action = event.getAction();
|
||||
|
||||
switch (event.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_HEADSETHOOK:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
// single quick press: pause/resume.
|
||||
// double press: next track
|
||||
// long press: unused (could also do next track? open player?)
|
||||
|
||||
if (action == KeyEvent.ACTION_UP && mIgnoreNextUp) {
|
||||
mIgnoreNextUp = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mHandler.hasMessages(MSG_MEDIA_CLICK)) {
|
||||
// double press
|
||||
if (action == KeyEvent.ACTION_DOWN) {
|
||||
mHandler.removeMessages(MSG_MEDIA_CLICK);
|
||||
context.startService(getCommand(context, PlaybackService.NEXT_SONG));
|
||||
mIgnoreNextUp = true;
|
||||
}
|
||||
} else {
|
||||
// single press
|
||||
if (action == KeyEvent.ACTION_UP) {
|
||||
Intent command = getCommand(context, PlaybackService.TOGGLE_PLAYBACK);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(context, 0, command, 0);
|
||||
Message message = mHandler.obtainMessage(MSG_MEDIA_CLICK, pendingIntent);
|
||||
mHandler.sendMessageDelayed(message, DOUBLE_CLICK_DELAY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||
if (action == KeyEvent.ACTION_DOWN)
|
||||
context.startService(getCommand(context, PlaybackService.NEXT_SONG));
|
||||
break;
|
||||
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
|
||||
if (action == KeyEvent.ACTION_DOWN)
|
||||
context.startService(getCommand(context, PlaybackService.PREVIOUS_SONG));
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
if (settings.getBoolean("media_button", true)) {
|
||||
intent.setClass(context, PlaybackService.class);
|
||||
context.startService(intent);
|
||||
abortBroadcast();
|
||||
}
|
||||
|
||||
abortBroadcast();
|
||||
} else if (ENABLE.equals(intentAction)) {
|
||||
// this approach does not seem elegant.
|
||||
mEnabled = intent.getBooleanExtra("enabled", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -50,10 +50,12 @@ import android.provider.MediaStore;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class PlaybackService extends Service implements Runnable, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
private static final int NOTIFICATION_ID = 2;
|
||||
private static final int DOUBLE_CLICK_DELAY = 400;
|
||||
|
||||
public static final String TOGGLE_PLAYBACK = "org.kreed.vanilla.action.TOGGLE_PLAYBACK";
|
||||
public static final String NEXT_SONG = "org.kreed.vanilla.action.NEXT_SONG";
|
||||
@ -94,12 +96,13 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
||||
private Object mStateLock = new Object();
|
||||
private boolean mPlayingBeforeCall;
|
||||
private int mPendingSeek;
|
||||
private int mPendingGo = -1;
|
||||
private int mPendingGo = -2;
|
||||
private Song mLastSongBroadcast;
|
||||
private boolean mPlugged;
|
||||
private ContentObserver mMediaObserver;
|
||||
public Receiver mReceiver;
|
||||
public InCallListener mCallListener;
|
||||
private boolean mIgnoreNextUp;
|
||||
|
||||
private Method mIsWiredHeadsetOn;
|
||||
private Method mStartForeground;
|
||||
@ -111,55 +114,30 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
||||
new Thread(this).start();
|
||||
}
|
||||
|
||||
private void go(Intent intent)
|
||||
{
|
||||
String action = intent.getAction();
|
||||
int delta = 0;
|
||||
|
||||
if (TOGGLE_PLAYBACK.equals(action))
|
||||
delta = 0;
|
||||
else if (NEXT_SONG.equals(action))
|
||||
delta = 1;
|
||||
else if (PREVIOUS_SONG.equals(action))
|
||||
delta = -1;
|
||||
else
|
||||
return;
|
||||
|
||||
if (mHandler == null) {
|
||||
Toast.makeText(this, R.string.starting, Toast.LENGTH_SHORT).show();
|
||||
mPendingGo = delta;
|
||||
return;
|
||||
}
|
||||
|
||||
if (delta != 0 && intent.hasExtra("autoplay")) {
|
||||
synchronized (mStateLock) {
|
||||
mState |= FLAG_PLAYING;
|
||||
}
|
||||
}
|
||||
|
||||
// check for double click
|
||||
if (intent.hasExtra("double")) {
|
||||
if (mHandler.hasMessages(GO)) {
|
||||
mHandler.removeMessages(GO);
|
||||
Intent launcher = new Intent(this, FullPlaybackActivity.class);
|
||||
launcher.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(launcher);
|
||||
} else {
|
||||
mHandler.sendMessageDelayed(mHandler.obtainMessage(GO, delta, 0), 400);
|
||||
}
|
||||
} else {
|
||||
if (delta == 0)
|
||||
toggleFlag(FLAG_PLAYING);
|
||||
else
|
||||
setCurrentSong(delta);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(Intent intent, int flags)
|
||||
{
|
||||
if (intent != null)
|
||||
go(intent);
|
||||
if (intent != null) {
|
||||
String action = intent.getAction();
|
||||
|
||||
if (Intent.ACTION_MEDIA_BUTTON.equals(action)) {
|
||||
handleMediaKey((KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
|
||||
return;
|
||||
}
|
||||
|
||||
int delta;
|
||||
|
||||
if (TOGGLE_PLAYBACK.equals(action))
|
||||
delta = 0;
|
||||
else if (NEXT_SONG.equals(action))
|
||||
delta = 1;
|
||||
else if (PREVIOUS_SONG.equals(action))
|
||||
delta = -1;
|
||||
else
|
||||
return;
|
||||
|
||||
go(delta, intent.getBooleanExtra("double", false), false);
|
||||
}
|
||||
|
||||
if (mHandler != null)
|
||||
mHandler.sendMessage(mHandler.obtainMessage(DO_ITEM, intent));
|
||||
@ -291,8 +269,8 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
||||
int go = 0;
|
||||
if (mPendingGo == 0)
|
||||
mState |= FLAG_PLAYING;
|
||||
else if (mPendingGo == 1)
|
||||
go = 1;
|
||||
else if (mPendingGo != -2)
|
||||
go = mPendingGo;
|
||||
setCurrentSong(go);
|
||||
|
||||
if (mPendingSeek != 0)
|
||||
@ -329,8 +307,7 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
||||
}
|
||||
}
|
||||
} else if ("media_button".equals(key)) {
|
||||
boolean value = mSettings.getBoolean("media_button", true);
|
||||
sendBroadcast(new Intent(MediaButtonReceiver.ENABLE).putExtra("enabled", value));
|
||||
setupReceiver();
|
||||
}
|
||||
}
|
||||
|
||||
@ -557,16 +534,101 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
||||
PlaybackServiceState.saveState(this, mSongTimeline, mCurrentSong, savePosition && mMediaPlayer != null ? mMediaPlayer.getCurrentPosition() : 0);
|
||||
}
|
||||
|
||||
private void go(int delta, boolean doubleLaunchesActivity, boolean autoPlay)
|
||||
{
|
||||
if (mHandler == null) {
|
||||
Toast.makeText(this, R.string.starting, Toast.LENGTH_SHORT).show();
|
||||
mPendingGo = delta;
|
||||
return;
|
||||
}
|
||||
|
||||
if (autoPlay) {
|
||||
synchronized (mStateLock) {
|
||||
mState |= FLAG_PLAYING;
|
||||
}
|
||||
}
|
||||
|
||||
// check for double click
|
||||
if (doubleLaunchesActivity) {
|
||||
if (mHandler.hasMessages(GO)) {
|
||||
mHandler.removeMessages(GO);
|
||||
Intent launcher = new Intent(this, FullPlaybackActivity.class);
|
||||
launcher.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(launcher);
|
||||
} else {
|
||||
mHandler.sendMessageDelayed(mHandler.obtainMessage(GO, delta, 0), DOUBLE_CLICK_DELAY);
|
||||
}
|
||||
} else {
|
||||
if (delta == 0)
|
||||
toggleFlag(FLAG_PLAYING);
|
||||
else
|
||||
setCurrentSong(delta);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean handleMediaKey(KeyEvent event)
|
||||
{
|
||||
int action = event.getAction();
|
||||
|
||||
switch (event.getKeyCode()) {
|
||||
case KeyEvent.KEYCODE_HEADSETHOOK:
|
||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||
// single quick press: pause/resume.
|
||||
// double press: next track
|
||||
// long press: unused (could also do next track? open player?)
|
||||
|
||||
if (action == KeyEvent.ACTION_UP && mIgnoreNextUp) {
|
||||
mIgnoreNextUp = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mHandler != null && mHandler.hasMessages(MEDIA_BUTTON)) {
|
||||
// double press
|
||||
if (action == KeyEvent.ACTION_DOWN) {
|
||||
mHandler.removeMessages(MEDIA_BUTTON);
|
||||
mIgnoreNextUp = true;
|
||||
go(1, false, true);
|
||||
}
|
||||
} else {
|
||||
// single press
|
||||
if (action == KeyEvent.ACTION_UP) {
|
||||
if (mHandler == null)
|
||||
go(0, false, false);
|
||||
else
|
||||
mHandler.sendEmptyMessageDelayed(MEDIA_BUTTON, DOUBLE_CLICK_DELAY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||
if (action == KeyEvent.ACTION_DOWN)
|
||||
go(1, false, true);
|
||||
break;
|
||||
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
|
||||
if (action == KeyEvent.ACTION_DOWN)
|
||||
go(-1, false, true);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private class Receiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context content, Intent intent)
|
||||
{
|
||||
String action = intent.getAction();
|
||||
|
||||
if (Intent.ACTION_HEADSET_PLUG.equals(action)) {
|
||||
boolean oldPlugged = mPlugged;
|
||||
mPlugged = intent.getIntExtra("state", 0) != 0;
|
||||
if (mPlugged != oldPlugged && (mHeadsetPause && !mPlugged || mHeadsetOnly && !isSpeakerOn()))
|
||||
unsetFlag(FLAG_PLAYING);
|
||||
} else if (Intent.ACTION_MEDIA_BUTTON.equals(action)) {
|
||||
KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
|
||||
if (event != null && handleMediaKey(event))
|
||||
abortBroadcast();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -609,8 +671,24 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
||||
loadPreference(key);
|
||||
}
|
||||
|
||||
private void setupReceiver()
|
||||
{
|
||||
if (mReceiver == null)
|
||||
mReceiver = new Receiver();
|
||||
else
|
||||
unregisterReceiver(mReceiver);
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_HEADSET_PLUG);
|
||||
if (mSettings.getBoolean("media_button", true))
|
||||
filter.addAction(Intent.ACTION_MEDIA_BUTTON);
|
||||
filter.setPriority(2000);
|
||||
registerReceiver(mReceiver, filter);
|
||||
}
|
||||
|
||||
private static final int GO = 0;
|
||||
private static final int POST_CREATE = 1;
|
||||
private static final int MEDIA_BUTTON = 2;
|
||||
private static final int DO_ITEM = 4;
|
||||
private static final int TRACK_CHANGED = 5;
|
||||
private static final int RELEASE_WAKE_LOCK = 6;
|
||||
@ -687,6 +765,9 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
||||
mHandler.sendEmptyMessageDelayed(SAVE_STATE, 5000);
|
||||
}
|
||||
break;
|
||||
case MEDIA_BUTTON:
|
||||
toggleFlag(FLAG_PLAYING);
|
||||
break;
|
||||
case TRACK_CHANGED:
|
||||
setCurrentSong(+1);
|
||||
setFlag(FLAG_PLAYING);
|
||||
@ -720,16 +801,7 @@ public class PlaybackService extends Service implements Runnable, MediaPlayer.On
|
||||
mHandler.sendEmptyMessageDelayed(SAVE_STATE, 5000);
|
||||
break;
|
||||
case POST_CREATE:
|
||||
loadPreference("media_button");
|
||||
|
||||
// Preload the receiver so we don't have an intial delay as it
|
||||
// loads for the first button press
|
||||
sendBroadcast(new Intent(Intent.ACTION_MEDIA_BUTTON));
|
||||
|
||||
mReceiver = new Receiver();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_HEADSET_PLUG);
|
||||
registerReceiver(mReceiver, filter);
|
||||
setupReceiver();
|
||||
|
||||
mCallListener = new InCallListener();
|
||||
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
|
||||
|
Loading…
x
Reference in New Issue
Block a user