From 80a6cbd201e4258c5b0015f80a820d3c2df727a9 Mon Sep 17 00:00:00 2001 From: Christopher Eby Date: Wed, 7 Apr 2010 22:26:08 -0500 Subject: [PATCH] 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. --- .../kreed/vanilla/MediaButtonReceiver.java | 95 +-------- src/org/kreed/vanilla/PlaybackService.java | 194 ++++++++++++------ 2 files changed, 142 insertions(+), 147 deletions(-) diff --git a/src/org/kreed/vanilla/MediaButtonReceiver.java b/src/org/kreed/vanilla/MediaButtonReceiver.java index e0c687ca..c5f3a3f7 100644 --- a/src/org/kreed/vanilla/MediaButtonReceiver.java +++ b/src/org/kreed/vanilla/MediaButtonReceiver.java @@ -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); } } -} +} \ No newline at end of file diff --git a/src/org/kreed/vanilla/PlaybackService.java b/src/org/kreed/vanilla/PlaybackService.java index 9452bb5b..8eea2904 100644 --- a/src/org/kreed/vanilla/PlaybackService.java +++ b/src/org/kreed/vanilla/PlaybackService.java @@ -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);