diff options
-rw-r--r-- | src/com/cyanogenmod/eleven/MediaButtonIntentReceiver.java | 160 | ||||
-rw-r--r-- | src/com/cyanogenmod/eleven/MusicPlaybackService.java | 92 |
2 files changed, 94 insertions, 158 deletions
diff --git a/src/com/cyanogenmod/eleven/MediaButtonIntentReceiver.java b/src/com/cyanogenmod/eleven/MediaButtonIntentReceiver.java index d4b8bc7..b7982e7 100644 --- a/src/com/cyanogenmod/eleven/MediaButtonIntentReceiver.java +++ b/src/com/cyanogenmod/eleven/MediaButtonIntentReceiver.java @@ -14,81 +14,14 @@ package com.cyanogenmod.eleven; import android.content.Context; import android.content.Intent; import android.media.AudioManager; -import android.os.Handler; -import android.os.Message; -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; import android.support.v4.content.WakefulBroadcastReceiver; import android.util.Log; import android.view.KeyEvent; -import com.cyanogenmod.eleven.ui.activities.HomeActivity; - -/** - * Used to control headset playback. - * Single press: pause/resume - * Double press: next track - * Triple press: previous track - * Long press: voice search - */ public class MediaButtonIntentReceiver extends WakefulBroadcastReceiver { private static final boolean DEBUG = false; private static final String TAG = "MediaButtonIntentReceiver"; - private static final int MSG_LONGPRESS_TIMEOUT = 1; - private static final int MSG_HEADSET_DOUBLE_CLICK_TIMEOUT = 2; - - private static final int LONG_PRESS_DELAY = 1000; - private static final int DOUBLE_CLICK = 800; - - private static WakeLock mWakeLock = null; - private static int mClickCounter = 0; - private static long mLastClickTime = 0; - private static boolean mDown = false; - private static boolean mLaunched = false; - - private static Handler mHandler = new Handler() { - - /** - * {@inheritDoc} - */ - @Override - public void handleMessage(final Message msg) { - switch (msg.what) { - case MSG_LONGPRESS_TIMEOUT: - if (DEBUG) Log.v(TAG, "Handling longpress timeout, launched " + mLaunched); - if (!mLaunched) { - final Context context = (Context)msg.obj; - final Intent i = new Intent(); - i.setClass(context, HomeActivity.class); - i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - context.startActivity(i); - mLaunched = true; - } - break; - - case MSG_HEADSET_DOUBLE_CLICK_TIMEOUT: - final int clickCount = msg.arg1; - final String command; - - if (DEBUG) Log.v(TAG, "Handling headset click, count = " + clickCount); - switch (clickCount) { - case 1: command = MusicPlaybackService.CMDTOGGLEPAUSE; break; - case 2: command = MusicPlaybackService.CMDNEXT; break; - case 3: command = MusicPlaybackService.CMDPREVIOUS; break; - default: command = null; break; - } - - if (command != null) { - final Context context = (Context)msg.obj; - startService(context, command); - } - break; - } - releaseWakeLockIfHandlerIdle(); - } - }; - /** * {@inheritDoc} */ @@ -97,23 +30,21 @@ public class MediaButtonIntentReceiver extends WakefulBroadcastReceiver { if (DEBUG) Log.v(TAG, "Received intent: " + intent); final String intentAction = intent.getAction(); if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction)) { - startService(context, MusicPlaybackService.CMDPAUSE); + startService(context, MusicPlaybackService.CMDPAUSE, System.currentTimeMillis()); } else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) { final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); - if (event == null) { + if (event == null || event.getAction() != KeyEvent.ACTION_UP) { return; } - final int keycode = event.getKeyCode(); - final int action = event.getAction(); - final long eventtime = event.getEventTime(); - String command = null; - switch (keycode) { + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_HEADSETHOOK: + command = MusicPlaybackService.CMDHEADSETHOOK; + break; case KeyEvent.KEYCODE_MEDIA_STOP: command = MusicPlaybackService.CMDSTOP; break; - case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: command = MusicPlaybackService.CMDTOGGLEPAUSE; break; @@ -131,93 +62,20 @@ public class MediaButtonIntentReceiver extends WakefulBroadcastReceiver { break; } if (command != null) { - if (action == KeyEvent.ACTION_DOWN) { - if (mDown) { - if (MusicPlaybackService.CMDTOGGLEPAUSE.equals(command) - || MusicPlaybackService.CMDPLAY.equals(command)) { - if (mLastClickTime != 0 - && eventtime - mLastClickTime > LONG_PRESS_DELAY) { - acquireWakeLockAndSendMessage(context, - mHandler.obtainMessage(MSG_LONGPRESS_TIMEOUT, context), 0); - } - } - } else if (event.getRepeatCount() == 0) { - // Only consider the first event in a sequence, not the repeat events, - // so that we don't trigger in cases where the first event went to - // a different app (e.g. when the user ends a phone call by - // long pressing the headset button) - - // The service may or may not be running, but we need to send it - // a command. - if (keycode == KeyEvent.KEYCODE_HEADSETHOOK) { - if (eventtime - mLastClickTime >= DOUBLE_CLICK) { - mClickCounter = 0; - } - - mClickCounter++; - if (DEBUG) Log.v(TAG, "Got headset click, count = " + mClickCounter); - mHandler.removeMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT); - - Message msg = mHandler.obtainMessage( - MSG_HEADSET_DOUBLE_CLICK_TIMEOUT, mClickCounter, 0, context); - - long delay = mClickCounter < 3 ? DOUBLE_CLICK : 0; - if (mClickCounter >= 3) { - mClickCounter = 0; - } - mLastClickTime = eventtime; - acquireWakeLockAndSendMessage(context, msg, delay); - } else { - startService(context, command); - } - mLaunched = false; - mDown = true; - } - } else { - mHandler.removeMessages(MSG_LONGPRESS_TIMEOUT); - mDown = false; - } + startService(context, command, event.getEventTime()); if (isOrderedBroadcast()) { abortBroadcast(); } - releaseWakeLockIfHandlerIdle(); } } } - private static void startService(Context context, String command) { + private static void startService(Context context, String command, long timestamp) { final Intent i = new Intent(context, MusicPlaybackService.class); i.setAction(MusicPlaybackService.SERVICECMD); i.putExtra(MusicPlaybackService.CMDNAME, command); i.putExtra(MusicPlaybackService.FROM_MEDIA_BUTTON, true); + i.putExtra(MusicPlaybackService.TIMESTAMP, timestamp); startWakefulService(context, i); } - - private static void acquireWakeLockAndSendMessage(Context context, Message msg, long delay) { - if (mWakeLock == null) { - Context appContext = context.getApplicationContext(); - PowerManager pm = (PowerManager) appContext.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Eleven headset button"); - mWakeLock.setReferenceCounted(false); - } - if (DEBUG) Log.v(TAG, "Acquiring wake lock and sending " + msg.what); - // Make sure we don't indefinitely hold the wake lock under any circumstances - mWakeLock.acquire(10000); - - mHandler.sendMessageDelayed(msg, delay); - } - - private static void releaseWakeLockIfHandlerIdle() { - if (mHandler.hasMessages(MSG_LONGPRESS_TIMEOUT) - || mHandler.hasMessages(MSG_HEADSET_DOUBLE_CLICK_TIMEOUT)) { - if (DEBUG) Log.v(TAG, "Handler still has messages pending, not releasing wake lock"); - return; - } - - if (mWakeLock != null) { - if (DEBUG) Log.v(TAG, "Releasing wake lock"); - mWakeLock.release(); - mWakeLock = null; - } - } } diff --git a/src/com/cyanogenmod/eleven/MusicPlaybackService.java b/src/com/cyanogenmod/eleven/MusicPlaybackService.java index d8163a8..bed0afa 100644 --- a/src/com/cyanogenmod/eleven/MusicPlaybackService.java +++ b/src/com/cyanogenmod/eleven/MusicPlaybackService.java @@ -13,6 +13,7 @@ package com.cyanogenmod.eleven; +import android.annotation.NonNull; import android.annotation.SuppressLint; import android.app.AlarmManager; import android.app.Notification; @@ -53,6 +54,7 @@ import android.provider.MediaStore.Audio.AlbumColumns; import android.provider.MediaStore.Audio.AudioColumns; import android.text.TextUtils; import android.util.Log; +import android.view.KeyEvent; import com.cyanogenmod.eleven.Config.IdType; import com.cyanogenmod.eleven.appwidgets.AppWidgetLarge; @@ -183,6 +185,8 @@ public class MusicPlaybackService extends Service { public static final String FROM_MEDIA_BUTTON = "frommediabutton"; + public static final String TIMESTAMP = "timestamp"; + /** * Used to easily notify a list that it should refresh. i.e. A playlist * changes @@ -218,7 +222,7 @@ public class MusicPlaybackService extends Service { public static final String CMDNEXT = "next"; - public static final String CMDNOTIF = "buttonId"; + public static final String CMDHEADSETHOOK = "headsethook"; private static final int IDCOLIDX = 0; @@ -298,6 +302,16 @@ public class MusicPlaybackService extends Service { private static final int LYRICS = 7; /** + * Indicates a headset hook key event + */ + private static final int HEADSET_HOOK_EVENT = 8; + + /** + * Indicates waiting for another headset hook event has timed out + */ + private static final int HEADSET_HOOK_MULTI_CLICK_TIMEOUT = 9; + + /** * Idle time before stopping the foreground notfication (5 minutes) */ private static final int IDLE_DELAY = 5 * 60 * 1000; @@ -515,6 +529,8 @@ public class MusicPlaybackService extends Service { */ private boolean mShowAlbumArtOnLockscreen; + private PowerManager.WakeLock mHeadsetHookWakeLock; + private ShakeDetector.Listener mShakeDetectorListener=new ShakeDetector.Listener() { @Override @@ -697,6 +713,19 @@ public class MusicPlaybackService extends Service { seek(0); releaseServiceUiAndStop(); } + @Override + public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) { + if (Intent.ACTION_MEDIA_BUTTON.equals(mediaButtonIntent.getAction())) { + KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); + if (ke != null && ke.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK) { + if (ke.getAction() == KeyEvent.ACTION_UP) { + handleHeadsetHookClick(ke.getEventTime()); + } + return true; + } + } + return super.onMediaButtonEvent(mediaButtonIntent); + } }); PendingIntent pi = PendingIntent.getBroadcast(this, 0, @@ -816,12 +845,7 @@ public class MusicPlaybackService extends Service { || PREVIOUS_FORCE_ACTION.equals(action)) { prev(PREVIOUS_FORCE_ACTION.equals(action)); } else if (CMDTOGGLEPAUSE.equals(command) || TOGGLEPAUSE_ACTION.equals(action)) { - if (isPlaying()) { - pause(); - mPausedByTransientLossOfFocus = false; - } else { - play(); - } + togglePlayPause(); } else if (CMDPAUSE.equals(command) || PAUSE_ACTION.equals(action)) { pause(); mPausedByTransientLossOfFocus = false; @@ -836,7 +860,24 @@ public class MusicPlaybackService extends Service { cycleRepeat(); } else if (SHUFFLE_ACTION.equals(action)) { cycleShuffle(); + } else if (CMDHEADSETHOOK.equals(command)) { + long timestamp = intent.getLongExtra(TIMESTAMP, 0); + handleHeadsetHookClick(timestamp); + } + } + + private void handleHeadsetHookClick(long timestamp) { + if (mHeadsetHookWakeLock == null) { + PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); + mHeadsetHookWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, + "Eleven headset button"); + mHeadsetHookWakeLock.setReferenceCounted(false); } + // Make sure we don't indefinitely hold the wake lock under any circumstances + mHeadsetHookWakeLock.acquire(10000); + + Message msg = mPlayerHandler.obtainMessage(HEADSET_HOOK_EVENT, Long.valueOf(timestamp)); + msg.sendToTarget(); } /** @@ -2421,6 +2462,15 @@ public class MusicPlaybackService extends Service { } } + private void togglePlayPause() { + if (isPlaying()) { + pause(); + mPausedByTransientLossOfFocus = false; + } else { + play(); + } + } + /** * Temporarily pauses playback. */ @@ -2874,6 +2924,9 @@ public class MusicPlaybackService extends Service { private final WeakReference<MusicPlaybackService> mService; private float mCurrentVolume = 1.0f; + private static final int DOUBLE_CLICK_TIMEOUT = 800; + private int mHeadsetHookClickCounter = 0; + /** * Constructor of <code>MusicPlayerHandler</code> * @@ -2980,6 +3033,31 @@ public class MusicPlaybackService extends Service { default: } break; + case HEADSET_HOOK_EVENT: { + long eventTime = (Long) msg.obj; + + mHeadsetHookClickCounter = Math.min(mHeadsetHookClickCounter + 1, 3); + if (D) Log.d(TAG, "Got headset click, count = " + mHeadsetHookClickCounter); + removeMessages(HEADSET_HOOK_MULTI_CLICK_TIMEOUT); + + if (mHeadsetHookClickCounter == 3) { + sendEmptyMessage(HEADSET_HOOK_MULTI_CLICK_TIMEOUT); + } else { + sendEmptyMessageAtTime(HEADSET_HOOK_MULTI_CLICK_TIMEOUT, + eventTime + DOUBLE_CLICK_TIMEOUT); + } + break; + } + case HEADSET_HOOK_MULTI_CLICK_TIMEOUT: + if (D) Log.d(TAG, "Handling headset click"); + switch (mHeadsetHookClickCounter) { + case 1: service.togglePlayPause(); break; + case 2: service.gotoNext(true); break; + case 3: service.prev(false); break; + } + mHeadsetHookClickCounter = 0; + service.mHeadsetHookWakeLock.release(); + break; default: break; } |