summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/cyanogenmod/eleven/MediaButtonIntentReceiver.java160
-rw-r--r--src/com/cyanogenmod/eleven/MusicPlaybackService.java92
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;
}