Tripple click headset button to rewind. Close #63
Also fixed the multiple instance bug when opening the player from the notification or widget.
This commit is contained in:
parent
4afa159dd0
commit
79eee79ab7
4 changed files with 150 additions and 33 deletions
|
|
@ -138,7 +138,7 @@ public class WidgetMedium extends AppWidgetProvider {
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case 0:
|
case 0:
|
||||||
intent = new Intent(context, MainActivity.class);
|
intent = new Intent(context, MainActivity.class);
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
case 1:
|
case 1:
|
||||||
intent = new Intent(MusicService.ACTION_TOGGLE_PAUSE);
|
intent = new Intent(MusicService.ACTION_TOGGLE_PAUSE);
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ public class PlayingNotificationHelper {
|
||||||
|
|
||||||
private PendingIntent getOpenMusicControllerPendingIntent() {
|
private PendingIntent getOpenMusicControllerPendingIntent() {
|
||||||
Intent intent = new Intent(service, MainActivity.class);
|
Intent intent = new Intent(service, MainActivity.class);
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
return PendingIntent.getActivity(service, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
return PendingIntent.getActivity(service, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2007 The Android Open Source Project Licensed under the Apache
|
||||||
|
* License, Version 2.0 (the "License"); you may not use this file except in
|
||||||
|
* compliance with the License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
|
||||||
|
* or agreed to in writing, software distributed under the License is
|
||||||
|
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the specific language
|
||||||
|
* governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Modified for Phonograph by Karim Abou Zeid (kabouzeid).
|
||||||
|
|
||||||
package com.kabouzeid.gramophone.service;
|
package com.kabouzeid.gramophone.service;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.support.annotation.NonNull;
|
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 android.view.KeyEvent;
|
||||||
|
|
||||||
public class MediaButtonIntentReceiver extends BroadcastReceiver {
|
import com.kabouzeid.gramophone.BuildConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to control headset playback.
|
||||||
|
* Single press: pause/resume
|
||||||
|
* Double press: next track
|
||||||
|
* Triple press: previous track
|
||||||
|
*/
|
||||||
|
public class MediaButtonIntentReceiver extends WakefulBroadcastReceiver {
|
||||||
|
private static final boolean DEBUG = BuildConfig.DEBUG;
|
||||||
public static final String TAG = MediaButtonIntentReceiver.class.getSimpleName();
|
public static final String TAG = MediaButtonIntentReceiver.class.getSimpleName();
|
||||||
|
|
||||||
private static final int DOUBLE_CLICK = 500;
|
private static final int MSG_HEADSET_DOUBLE_CLICK_TIMEOUT = 2;
|
||||||
|
|
||||||
|
private static final int DOUBLE_CLICK = 400;
|
||||||
|
|
||||||
|
private static WakeLock mWakeLock = null;
|
||||||
|
private static int mClickCounter = 0;
|
||||||
private static long mLastClickTime = 0;
|
private static long mLastClickTime = 0;
|
||||||
|
|
||||||
|
@SuppressLint("HandlerLeak") // false alarm, handler is already static
|
||||||
|
private static Handler mHandler = new Handler() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(final Message msg) {
|
||||||
|
switch (msg.what) {
|
||||||
|
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 = MusicService.ACTION_TOGGLE_PAUSE;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
command = MusicService.ACTION_SKIP;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
command = MusicService.ACTION_REWIND;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
command = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command != null) {
|
||||||
|
final Context context = (Context) msg.obj;
|
||||||
|
startService(context, command);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
releaseWakeLockIfHandlerIdle();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
|
public void onReceive(final Context context, final Intent intent) {
|
||||||
if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON)) {
|
if (DEBUG) Log.v(TAG, "Received intent: " + intent);
|
||||||
|
final String intentAction = intent.getAction();
|
||||||
|
if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) {
|
||||||
final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
|
final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
|
||||||
if (event == null)
|
if (event == null) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final int keycode = event.getKeyCode();
|
final int keycode = event.getKeyCode();
|
||||||
final int action = event.getAction();
|
final int action = event.getAction();
|
||||||
final long eventTime = event.getEventTime();
|
final long eventTime = event.getEventTime();
|
||||||
|
|
@ -31,9 +103,6 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver {
|
||||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||||
command = MusicService.ACTION_TOGGLE_PAUSE;
|
command = MusicService.ACTION_TOGGLE_PAUSE;
|
||||||
break;
|
break;
|
||||||
case KeyEvent.KEYCODE_MEDIA_PLAY:
|
|
||||||
command = MusicService.ACTION_PLAY;
|
|
||||||
break;
|
|
||||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||||
command = MusicService.ACTION_SKIP;
|
command = MusicService.ACTION_SKIP;
|
||||||
break;
|
break;
|
||||||
|
|
@ -43,29 +112,81 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver {
|
||||||
case KeyEvent.KEYCODE_MEDIA_PAUSE:
|
case KeyEvent.KEYCODE_MEDIA_PAUSE:
|
||||||
command = MusicService.ACTION_PAUSE;
|
command = MusicService.ACTION_PAUSE;
|
||||||
break;
|
break;
|
||||||
|
case KeyEvent.KEYCODE_MEDIA_PLAY:
|
||||||
|
command = MusicService.ACTION_PLAY;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (command != null) {
|
if (command != null) {
|
||||||
if (action == KeyEvent.ACTION_DOWN) {
|
if (action == KeyEvent.ACTION_DOWN) {
|
||||||
if (event.getRepeatCount() == 0) {
|
if (event.getRepeatCount() == 0) {
|
||||||
/**
|
// Only consider the first event in a sequence, not the repeat events,
|
||||||
* If another app received the broadcast first, this if statement will skip.
|
// 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
|
||||||
//TODO triple click to rewind
|
// long pressing the headset button)
|
||||||
final Intent i = new Intent(context, MusicService.class);
|
|
||||||
if (keycode == KeyEvent.KEYCODE_HEADSETHOOK
|
// The service may or may not be running, but we need to send it
|
||||||
&& eventTime - mLastClickTime < DOUBLE_CLICK) {
|
// a command.
|
||||||
i.setAction(MusicService.ACTION_SKIP);
|
if (keycode == KeyEvent.KEYCODE_HEADSETHOOK) {
|
||||||
mLastClickTime = 0;
|
if (eventTime - mLastClickTime >= DOUBLE_CLICK) {
|
||||||
} else {
|
mClickCounter = 0;
|
||||||
i.setAction(command);
|
}
|
||||||
|
|
||||||
|
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;
|
mLastClickTime = eventTime;
|
||||||
|
acquireWakeLockAndSendMessage(context, msg, delay);
|
||||||
|
} else {
|
||||||
|
startService(context, command);
|
||||||
}
|
}
|
||||||
context.startService(i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isOrderedBroadcast())
|
if (isOrderedBroadcast()) {
|
||||||
abortBroadcast();
|
abortBroadcast();
|
||||||
|
}
|
||||||
|
releaseWakeLockIfHandlerIdle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private static void startService(Context context, String command) {
|
||||||
|
final Intent intent = new Intent(context, MusicService.class);
|
||||||
|
intent.setAction(command);
|
||||||
|
startWakefulService(context, intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
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, "Phonograph 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_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -212,7 +212,9 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
private void initRemoteControlClient() {
|
private void initRemoteControlClient() {
|
||||||
remoteControlClient = new RemoteControlClient(getMediaButtonIntent());
|
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
|
||||||
|
mediaButtonIntent.setComponent(new ComponentName(getApplicationContext(), MediaButtonIntentReceiver.class));
|
||||||
|
remoteControlClient = new RemoteControlClient(PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0));
|
||||||
remoteControlClient.setTransportControlFlags(
|
remoteControlClient.setTransportControlFlags(
|
||||||
RemoteControlClient.FLAG_KEY_MEDIA_PLAY |
|
RemoteControlClient.FLAG_KEY_MEDIA_PLAY |
|
||||||
RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
|
RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
|
||||||
|
|
@ -221,12 +223,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
getAudioManager().registerRemoteControlClient(remoteControlClient);
|
getAudioManager().registerRemoteControlClient(remoteControlClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PendingIntent getMediaButtonIntent() {
|
|
||||||
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
|
|
||||||
mediaButtonIntent.setComponent(new ComponentName(getApplicationContext(), MediaButtonIntentReceiver.class));
|
|
||||||
return PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
|
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
|
||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue