move the media session handling from the PlaybackServiceMediaPlayer and into the PlaybackService
This commit is contained in:
parent
9b563c1c87
commit
5105cdd7c3
@ -4,22 +4,26 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
|
||||||
public class MediaButtonIntentReceiver extends BroadcastReceiver {
|
public class MediaButtonIntentReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
private static final String TAG = "MediaButtonIntentRcver";
|
private static final String TAG = "MediaButtonIntentRcver";
|
||||||
|
|
||||||
private static PlaybackServiceMediaPlayer mMediaPlayer;
|
private static PlaybackService mPlaybackService;
|
||||||
|
|
||||||
public static void setMediaPlayer(PlaybackServiceMediaPlayer mediaPlayer) {
|
public static void setMediaPlayer(PlaybackService playbackService) {
|
||||||
mMediaPlayer = mediaPlayer;
|
mPlaybackService = playbackService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
Log.d(TAG, "onReceive(Context, " + intent.toString() +")");
|
Log.d(TAG, "onReceive(Context, " + intent.toString() +")");
|
||||||
if (mMediaPlayer != null && Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
|
if (mPlaybackService != null && Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
|
||||||
mMediaPlayer.handleMediaKey(intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT));
|
KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
|
||||||
|
if (event != null && event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
|
||||||
|
mPlaybackService.handleKeycode(event.getKeyCode(), event.getSource());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import android.app.PendingIntent;
|
|||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.bluetooth.BluetoothA2dp;
|
import android.bluetooth.BluetoothA2dp;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
@ -19,12 +20,18 @@ import android.os.Build;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.v4.media.MediaMetadataCompat;
|
||||||
|
import android.support.v4.media.session.MediaSessionCompat;
|
||||||
|
import android.support.v4.media.session.PlaybackStateCompat;
|
||||||
import android.support.v7.app.NotificationCompat;
|
import android.support.v7.app.NotificationCompat;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import android.view.Display;
|
||||||
|
import android.view.InputDevice;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
|
import android.view.WindowManager;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
@ -54,7 +61,7 @@ import de.danoeh.antennapod.core.util.playback.Playable;
|
|||||||
/**
|
/**
|
||||||
* Controls the MediaPlayer that plays a FeedMedia-file
|
* Controls the MediaPlayer that plays a FeedMedia-file
|
||||||
*/
|
*/
|
||||||
public class PlaybackService extends Service {
|
public class PlaybackService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
public static final String FORCE_WIDGET_UPDATE = "de.danoeh.antennapod.FORCE_WIDGET_UPDATE";
|
public static final String FORCE_WIDGET_UPDATE = "de.danoeh.antennapod.FORCE_WIDGET_UPDATE";
|
||||||
public static final String STOP_WIDGET_UPDATE = "de.danoeh.antennapod.STOP_WIDGET_UPDATE";
|
public static final String STOP_WIDGET_UPDATE = "de.danoeh.antennapod.STOP_WIDGET_UPDATE";
|
||||||
/**
|
/**
|
||||||
@ -169,6 +176,10 @@ public class PlaybackService extends Service {
|
|||||||
|
|
||||||
private PlaybackServiceMediaPlayer mediaPlayer;
|
private PlaybackServiceMediaPlayer mediaPlayer;
|
||||||
private PlaybackServiceTaskManager taskManager;
|
private PlaybackServiceTaskManager taskManager;
|
||||||
|
/**
|
||||||
|
* Only used for Lollipop notifications.
|
||||||
|
*/
|
||||||
|
private MediaSessionCompat mediaSession;
|
||||||
|
|
||||||
private int startPosition;
|
private int startPosition;
|
||||||
|
|
||||||
@ -239,6 +250,28 @@ public class PlaybackService extends Service {
|
|||||||
taskManager = new PlaybackServiceTaskManager(this, taskManagerCallback);
|
taskManager = new PlaybackServiceTaskManager(this, taskManagerCallback);
|
||||||
mediaPlayer = new PlaybackServiceMediaPlayer(this, mediaPlayerCallback);
|
mediaPlayer = new PlaybackServiceMediaPlayer(this, mediaPlayerCallback);
|
||||||
|
|
||||||
|
MediaButtonIntentReceiver.setMediaPlayer(this);
|
||||||
|
ComponentName eventReceiver = new ComponentName(getPackageName(), MediaButtonIntentReceiver.class.getName());
|
||||||
|
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
|
||||||
|
mediaButtonIntent.setComponent(eventReceiver);
|
||||||
|
PendingIntent buttonReceiverIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||||
|
|
||||||
|
mediaSession = new MediaSessionCompat(this, TAG, eventReceiver, buttonReceiverIntent);
|
||||||
|
|
||||||
|
try {
|
||||||
|
mediaSession.setCallback(sessionCallback);
|
||||||
|
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
||||||
|
mediaSession.setActive(true);
|
||||||
|
} catch (NullPointerException npe) {
|
||||||
|
// on some devices (Huawei) setting active can cause a NullPointerException
|
||||||
|
// even with correct use of the api.
|
||||||
|
// See http://stackoverflow.com/questions/31556679/android-huawei-mediassessioncompat
|
||||||
|
// and https://plus.google.com/+IanLake/posts/YgdTkKFxz7d
|
||||||
|
Log.e(TAG, "NullPointerException while setting up MediaSession");
|
||||||
|
npe.printStackTrace();
|
||||||
|
}
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
.registerOnSharedPreferenceChangeListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -249,6 +282,8 @@ public class PlaybackService extends Service {
|
|||||||
started = false;
|
started = false;
|
||||||
currentMediaType = MediaType.UNKNOWN;
|
currentMediaType = MediaType.UNKNOWN;
|
||||||
|
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
.unregisterOnSharedPreferenceChangeListener(this);
|
||||||
unregisterReceiver(headsetDisconnected);
|
unregisterReceiver(headsetDisconnected);
|
||||||
unregisterReceiver(shutdownReceiver);
|
unregisterReceiver(shutdownReceiver);
|
||||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||||
@ -260,6 +295,9 @@ public class PlaybackService extends Service {
|
|||||||
unregisterReceiver(pauseResumeCurrentEpisodeReceiver);
|
unregisterReceiver(pauseResumeCurrentEpisodeReceiver);
|
||||||
mediaPlayer.shutdown();
|
mediaPlayer.shutdown();
|
||||||
taskManager.shutdown();
|
taskManager.shutdown();
|
||||||
|
if (mediaSession != null) {
|
||||||
|
mediaSession.release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -268,6 +306,13 @@ public class PlaybackService extends Service {
|
|||||||
return mBinder;
|
return mBinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
|
if(key.equals(UserPreferences.PREF_LOCKSCREEN_BACKGROUND)) {
|
||||||
|
updateMediaSessionMetadata(getPlayable());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
super.onStartCommand(intent, flags, startId);
|
super.onStartCommand(intent, flags, startId);
|
||||||
@ -287,7 +332,7 @@ public class PlaybackService extends Service {
|
|||||||
|
|
||||||
if (keycode != -1) {
|
if (keycode != -1) {
|
||||||
Log.d(TAG, "Received media button event");
|
Log.d(TAG, "Received media button event");
|
||||||
handleKeycode(keycode);
|
handleKeycode(keycode, InputDevice.SOURCE_CLASS_NONE);
|
||||||
} else {
|
} else {
|
||||||
started = true;
|
started = true;
|
||||||
boolean stream = intent.getBooleanExtra(EXTRA_SHOULD_STREAM,
|
boolean stream = intent.getBooleanExtra(EXTRA_SHOULD_STREAM,
|
||||||
@ -305,7 +350,7 @@ public class PlaybackService extends Service {
|
|||||||
/**
|
/**
|
||||||
* Handles media button events
|
* Handles media button events
|
||||||
*/
|
*/
|
||||||
private void handleKeycode(int keycode) {
|
public void handleKeycode(int keycode, int source) {
|
||||||
Log.d(TAG, "Handling keycode: " + keycode);
|
Log.d(TAG, "Handling keycode: " + keycode);
|
||||||
final PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo();
|
final PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo();
|
||||||
final PlayerStatus status = info.playerStatus;
|
final PlayerStatus status = info.playerStatus;
|
||||||
@ -347,7 +392,16 @@ public class PlaybackService extends Service {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||||
mediaPlayer.endPlayback(true);
|
if(source == InputDevice.SOURCE_CLASS_NONE ||
|
||||||
|
UserPreferences.shouldHardwareButtonSkip()) {
|
||||||
|
// assume the skip command comes from a notification or the lockscreen
|
||||||
|
// a >| skip button should actually skip
|
||||||
|
mediaPlayer.endPlayback(true);
|
||||||
|
} else {
|
||||||
|
// assume skip command comes from a (bluetooth) media button
|
||||||
|
// user actually wants to fast-forward
|
||||||
|
seekDelta(UserPreferences.getFastFowardSecs() * 1000);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
|
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
|
||||||
mediaPlayer.seekDelta(UserPreferences.getFastFowardSecs() * 1000);
|
mediaPlayer.seekDelta(UserPreferences.getFastFowardSecs() * 1000);
|
||||||
@ -365,6 +419,7 @@ public class PlaybackService extends Service {
|
|||||||
stopForeground(true); // gets rid of persistent notification
|
stopForeground(true); // gets rid of persistent notification
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
Log.d(TAG, "Unhandled key code: " + keycode);
|
||||||
if (info.playable != null && info.playerStatus == PlayerStatus.PLAYING) { // only notify the user about an unknown key event if it is actually doing something
|
if (info.playable != null && info.playerStatus == PlayerStatus.PLAYING) { // only notify the user about an unknown key event if it is actually doing something
|
||||||
String message = String.format(getResources().getString(R.string.unknown_media_key), keycode);
|
String message = String.format(getResources().getString(R.string.unknown_media_key), keycode);
|
||||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
||||||
@ -439,6 +494,7 @@ public class PlaybackService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
|
public void statusChanged(PlaybackServiceMediaPlayer.PSMPInfo newInfo) {
|
||||||
currentMediaType = mediaPlayer.getCurrentMediaType();
|
currentMediaType = mediaPlayer.getCurrentMediaType();
|
||||||
|
updateMediaSession(newInfo.playerStatus);
|
||||||
switch (newInfo.playerStatus) {
|
switch (newInfo.playerStatus) {
|
||||||
case INITIALIZED:
|
case INITIALIZED:
|
||||||
writePlaybackPreferences();
|
writePlaybackPreferences();
|
||||||
@ -529,6 +585,11 @@ public class PlaybackService extends Service {
|
|||||||
sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_UPDATE, percent);
|
sendNotificationBroadcast(NOTIFICATION_TYPE_BUFFER_UPDATE, percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateMediaSessionMetadata(Playable p) {
|
||||||
|
PlaybackService.this.updateMediaSessionMetadata(p);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onMediaPlayerInfo(int code) {
|
public boolean onMediaPlayerInfo(int code) {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
@ -795,6 +856,86 @@ public class PlaybackService extends Service {
|
|||||||
*/
|
*/
|
||||||
private Thread notificationSetupThread;
|
private Thread notificationSetupThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the Media Session with current media player info.
|
||||||
|
* @param playerStatus the current {@link PlayerStatus}
|
||||||
|
*/
|
||||||
|
private void updateMediaSession(final PlayerStatus playerStatus) {
|
||||||
|
PlaybackStateCompat.Builder sessionState = new PlaybackStateCompat.Builder();
|
||||||
|
|
||||||
|
int state;
|
||||||
|
if (playerStatus != null) {
|
||||||
|
switch (playerStatus) {
|
||||||
|
case PLAYING:
|
||||||
|
state = PlaybackStateCompat.STATE_PLAYING;
|
||||||
|
break;
|
||||||
|
case PREPARED:
|
||||||
|
case PAUSED:
|
||||||
|
state = PlaybackStateCompat.STATE_PAUSED;
|
||||||
|
break;
|
||||||
|
case STOPPED:
|
||||||
|
state = PlaybackStateCompat.STATE_STOPPED;
|
||||||
|
break;
|
||||||
|
case SEEKING:
|
||||||
|
state = PlaybackStateCompat.STATE_FAST_FORWARDING;
|
||||||
|
break;
|
||||||
|
case PREPARING:
|
||||||
|
case INITIALIZING:
|
||||||
|
state = PlaybackStateCompat.STATE_CONNECTING;
|
||||||
|
break;
|
||||||
|
case INITIALIZED:
|
||||||
|
case INDETERMINATE:
|
||||||
|
state = PlaybackStateCompat.STATE_NONE;
|
||||||
|
break;
|
||||||
|
case ERROR:
|
||||||
|
state = PlaybackStateCompat.STATE_ERROR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
state = PlaybackStateCompat.STATE_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state = PlaybackStateCompat.STATE_NONE;
|
||||||
|
}
|
||||||
|
sessionState.setState(state, mediaPlayer.getPosition(), mediaPlayer.getPlaybackSpeed());
|
||||||
|
sessionState.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE
|
||||||
|
| PlaybackStateCompat.ACTION_REWIND
|
||||||
|
| PlaybackStateCompat.ACTION_FAST_FORWARD
|
||||||
|
| PlaybackStateCompat.ACTION_SKIP_TO_NEXT);
|
||||||
|
mediaSession.setPlaybackState(sessionState.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateMediaSessionMetadata(Playable p) {
|
||||||
|
if (p == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
|
||||||
|
builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, p.getFeedTitle());
|
||||||
|
builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, p.getEpisodeTitle());
|
||||||
|
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration());
|
||||||
|
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
|
||||||
|
builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
|
||||||
|
|
||||||
|
if (p.getImageUri() != null && UserPreferences.setLockscreenBackground()) {
|
||||||
|
builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, p.getImageUri().toString());
|
||||||
|
try {
|
||||||
|
WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
Display display = wm.getDefaultDisplay();
|
||||||
|
Bitmap art = Glide.with(this)
|
||||||
|
.load(p.getImageUri())
|
||||||
|
.asBitmap()
|
||||||
|
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
||||||
|
.centerCrop()
|
||||||
|
.into(display.getWidth(), display.getHeight())
|
||||||
|
.get();
|
||||||
|
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, art);
|
||||||
|
} catch (Throwable tr) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(tr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mediaSession.setMetadata(builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares notification and starts the service in the foreground.
|
* Prepares notification and starts the service in the foreground.
|
||||||
*/
|
*/
|
||||||
@ -913,7 +1054,7 @@ public class PlaybackService extends Service {
|
|||||||
PendingIntent stopButtonPendingIntent = getPendingIntentForMediaAction(
|
PendingIntent stopButtonPendingIntent = getPendingIntentForMediaAction(
|
||||||
KeyEvent.KEYCODE_MEDIA_STOP, numActions);
|
KeyEvent.KEYCODE_MEDIA_STOP, numActions);
|
||||||
notificationBuilder.setStyle(new android.support.v7.app.NotificationCompat.MediaStyle()
|
notificationBuilder.setStyle(new android.support.v7.app.NotificationCompat.MediaStyle()
|
||||||
.setMediaSession(mediaPlayer.getSessionToken())
|
.setMediaSession(mediaSession.getSessionToken())
|
||||||
.setShowActionsInCompactView(compactActionList.toArray())
|
.setShowActionsInCompactView(compactActionList.toArray())
|
||||||
.setShowCancelButton(true)
|
.setShowCancelButton(true)
|
||||||
.setCancelButtonIntent(stopButtonPendingIntent))
|
.setCancelButtonIntent(stopButtonPendingIntent))
|
||||||
@ -1287,4 +1428,89 @@ public class PlaybackService extends Service {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() {
|
||||||
|
|
||||||
|
private static final String TAG = "MediaSessionCompat";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPlay() {
|
||||||
|
Log.d(TAG, "onPlay()");
|
||||||
|
PlayerStatus status = getStatus();
|
||||||
|
if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) {
|
||||||
|
resume();
|
||||||
|
} else if (status == PlayerStatus.INITIALIZED) {
|
||||||
|
setStartWhenPrepared(true);
|
||||||
|
prepare();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause() {
|
||||||
|
Log.d(TAG, "onPause()");
|
||||||
|
if (getStatus() == PlayerStatus.PLAYING) {
|
||||||
|
pause(false, true);
|
||||||
|
}
|
||||||
|
if (UserPreferences.isPersistNotify()) {
|
||||||
|
pause(false, true);
|
||||||
|
} else {
|
||||||
|
pause(true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
Log.d(TAG, "onStop()");
|
||||||
|
mediaPlayer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSkipToPrevious() {
|
||||||
|
Log.d(TAG, "onSkipToPrevious()");
|
||||||
|
seekDelta(-UserPreferences.getRewindSecs() * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRewind() {
|
||||||
|
Log.d(TAG, "onRewind()");
|
||||||
|
seekDelta(-UserPreferences.getRewindSecs() * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFastForward() {
|
||||||
|
Log.d(TAG, "onFastForward()");
|
||||||
|
seekDelta(UserPreferences.getFastFowardSecs() * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSkipToNext() {
|
||||||
|
Log.d(TAG, "onSkipToNext()");
|
||||||
|
if(UserPreferences.shouldHardwareButtonSkip()) {
|
||||||
|
mediaPlayer.endPlayback(true);
|
||||||
|
} else {
|
||||||
|
seekDelta(UserPreferences.getFastFowardSecs() * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSeekTo(long pos) {
|
||||||
|
Log.d(TAG, "onSeekTo()");
|
||||||
|
seekTo((int) pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMediaButtonEvent(final Intent mediaButton) {
|
||||||
|
Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")");
|
||||||
|
if (mediaButton != null) {
|
||||||
|
KeyEvent keyEvent = (KeyEvent) mediaButton.getExtras().get(Intent.EXTRA_KEY_EVENT);
|
||||||
|
if (keyEvent != null &&
|
||||||
|
keyEvent.getAction() == KeyEvent.ACTION_DOWN &&
|
||||||
|
keyEvent.getRepeatCount() == 0){
|
||||||
|
handleKeycode(keyEvent.getKeyCode(), keyEvent.getSource());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,14 @@
|
|||||||
package de.danoeh.antennapod.core.service.playback;
|
package de.danoeh.antennapod.core.service.playback;
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.media.MediaMetadataCompat;
|
|
||||||
import android.support.v4.media.session.MediaSessionCompat;
|
|
||||||
import android.support.v4.media.session.PlaybackStateCompat;
|
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.view.Display;
|
|
||||||
import android.view.InputDevice;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.WindowManager;
|
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
|
|
||||||
import org.antennapod.audio.MediaPlayer;
|
import org.antennapod.audio.MediaPlayer;
|
||||||
|
|
||||||
@ -40,7 +25,6 @@ import de.danoeh.antennapod.core.feed.Chapter;
|
|||||||
import de.danoeh.antennapod.core.feed.FeedItem;
|
import de.danoeh.antennapod.core.feed.FeedItem;
|
||||||
import de.danoeh.antennapod.core.feed.FeedMedia;
|
import de.danoeh.antennapod.core.feed.FeedMedia;
|
||||||
import de.danoeh.antennapod.core.feed.MediaType;
|
import de.danoeh.antennapod.core.feed.MediaType;
|
||||||
import de.danoeh.antennapod.core.glide.ApGlideSettings;
|
|
||||||
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
import de.danoeh.antennapod.core.preferences.UserPreferences;
|
||||||
import de.danoeh.antennapod.core.storage.DBWriter;
|
import de.danoeh.antennapod.core.storage.DBWriter;
|
||||||
import de.danoeh.antennapod.core.util.RewindAfterPauseUtils;
|
import de.danoeh.antennapod.core.util.RewindAfterPauseUtils;
|
||||||
@ -52,7 +36,7 @@ import de.danoeh.antennapod.core.util.playback.VideoPlayer;
|
|||||||
/**
|
/**
|
||||||
* Manages the MediaPlayer object of the PlaybackService.
|
* Manages the MediaPlayer object of the PlaybackService.
|
||||||
*/
|
*/
|
||||||
public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPreferenceChangeListener {
|
public class PlaybackServiceMediaPlayer {
|
||||||
public static final String TAG = "PlaybackSvcMediaPlayer";
|
public static final String TAG = "PlaybackSvcMediaPlayer";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,10 +50,6 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
private volatile PlayerStatus statusBeforeSeeking;
|
private volatile PlayerStatus statusBeforeSeeking;
|
||||||
private volatile IPlayer mediaPlayer;
|
private volatile IPlayer mediaPlayer;
|
||||||
private volatile Playable media;
|
private volatile Playable media;
|
||||||
/**
|
|
||||||
* Only used for Lollipop notifications.
|
|
||||||
*/
|
|
||||||
private final MediaSessionCompat mediaSession;
|
|
||||||
|
|
||||||
private volatile boolean stream;
|
private volatile boolean stream;
|
||||||
private volatile MediaType mediaType;
|
private volatile MediaType mediaType;
|
||||||
@ -110,43 +90,12 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
MediaButtonIntentReceiver.setMediaPlayer(this);
|
|
||||||
ComponentName eventReceiver = new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName());
|
|
||||||
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
|
|
||||||
mediaButtonIntent.setComponent(eventReceiver);
|
|
||||||
PendingIntent buttonReceiverIntent = PendingIntent.getBroadcast(context, 0, mediaButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
|
||||||
|
|
||||||
mediaSession = new MediaSessionCompat(context, TAG, eventReceiver, buttonReceiverIntent);
|
|
||||||
|
|
||||||
try {
|
|
||||||
mediaSession.setCallback(sessionCallback);
|
|
||||||
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
|
||||||
mediaSession.setActive(true);
|
|
||||||
} catch (NullPointerException npe) {
|
|
||||||
// on some devices (Huawei) setting active can cause a NullPointerException
|
|
||||||
// even with correct use of the api.
|
|
||||||
// See http://stackoverflow.com/questions/31556679/android-huawei-mediassessioncompat
|
|
||||||
// and https://plus.google.com/+IanLake/posts/YgdTkKFxz7d
|
|
||||||
Log.e(TAG, "NullPointerException while setting up MediaSession");
|
|
||||||
npe.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaPlayer = null;
|
mediaPlayer = null;
|
||||||
statusBeforeSeeking = null;
|
statusBeforeSeeking = null;
|
||||||
pausedBecauseOfTransientAudiofocusLoss = false;
|
pausedBecauseOfTransientAudiofocusLoss = false;
|
||||||
mediaType = MediaType.UNKNOWN;
|
mediaType = MediaType.UNKNOWN;
|
||||||
playerStatus = PlayerStatus.STOPPED;
|
playerStatus = PlayerStatus.STOPPED;
|
||||||
videoSize = null;
|
videoSize = null;
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
|
||||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
|
||||||
if(key.equals(UserPreferences.PREF_LOCKSCREEN_BACKGROUND)) {
|
|
||||||
updateMediaSessionMetadata();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,7 +198,7 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
setPlayerStatus(PlayerStatus.INITIALIZING, media);
|
setPlayerStatus(PlayerStatus.INITIALIZING, media);
|
||||||
try {
|
try {
|
||||||
media.loadMetadata();
|
media.loadMetadata();
|
||||||
updateMediaSessionMetadata();
|
executor.submit(() -> callback.updateMediaSessionMetadata(media));
|
||||||
if (stream) {
|
if (stream) {
|
||||||
mediaPlayer.setDataSource(media.getStreamUrl());
|
mediaPlayer.setDataSource(media.getStreamUrl());
|
||||||
} else {
|
} else {
|
||||||
@ -269,41 +218,6 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateMediaSessionMetadata() {
|
|
||||||
executor.execute(() -> {
|
|
||||||
final Playable p = this.media;
|
|
||||||
if (p == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
|
|
||||||
builder.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, p.getFeedTitle());
|
|
||||||
builder.putString(MediaMetadataCompat.METADATA_KEY_TITLE, p.getEpisodeTitle());
|
|
||||||
builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, p.getDuration());
|
|
||||||
builder.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, p.getEpisodeTitle());
|
|
||||||
builder.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, p.getFeedTitle());
|
|
||||||
|
|
||||||
if (p.getImageUri() != null && UserPreferences.setLockscreenBackground()) {
|
|
||||||
builder.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, p.getImageUri().toString());
|
|
||||||
try {
|
|
||||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
|
||||||
Display display = wm.getDefaultDisplay();
|
|
||||||
Bitmap art = Glide.with(context)
|
|
||||||
.load(p.getImageUri())
|
|
||||||
.asBitmap()
|
|
||||||
.diskCacheStrategy(ApGlideSettings.AP_DISK_CACHE_STRATEGY)
|
|
||||||
.centerCrop()
|
|
||||||
.into(display.getWidth(), display.getHeight())
|
|
||||||
.get();
|
|
||||||
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, art);
|
|
||||||
} catch (Throwable tr) {
|
|
||||||
Log.e(TAG, Log.getStackTraceString(tr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mediaSession.setMetadata(builder.build());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resumes playback if the PSMP object is in PREPARED or PAUSED state. If the PSMP object is in an invalid state.
|
* Resumes playback if the PSMP object is in PREPARED or PAUSED state. If the PSMP object is in an invalid state.
|
||||||
* nothing will happen.
|
* nothing will happen.
|
||||||
@ -718,9 +632,6 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
if (mediaPlayer != null) {
|
if (mediaPlayer != null) {
|
||||||
mediaPlayer.release();
|
mediaPlayer.release();
|
||||||
}
|
}
|
||||||
if (mediaSession != null) {
|
|
||||||
mediaSession.release();
|
|
||||||
}
|
|
||||||
releaseWifiLockIfNecessary();
|
releaseWifiLockIfNecessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -797,16 +708,6 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
return media;
|
return media;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a token to this object's MediaSession. The MediaSession should only be used for notifications
|
|
||||||
* at the moment.
|
|
||||||
*
|
|
||||||
* @return The MediaSessionCompat.Token object.
|
|
||||||
*/
|
|
||||||
public MediaSessionCompat.Token getSessionToken() {
|
|
||||||
return mediaSession.getSessionToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the player status of the PSMP object. PlayerStatus and media attributes have to be set at the same time
|
* Sets the player status of the PSMP object. PlayerStatus and media attributes have to be set at the same time
|
||||||
* so that getPSMPInfo can't return an invalid state (e.g. status is PLAYING, but media is null).
|
* so that getPSMPInfo can't return an invalid state (e.g. status is PLAYING, but media is null).
|
||||||
@ -822,50 +723,9 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
|
|
||||||
this.playerStatus = newStatus;
|
this.playerStatus = newStatus;
|
||||||
this.media = newMedia;
|
this.media = newMedia;
|
||||||
|
|
||||||
PlaybackStateCompat.Builder sessionState = new PlaybackStateCompat.Builder();
|
|
||||||
|
|
||||||
int state;
|
|
||||||
if (playerStatus != null) {
|
if (playerStatus != null) {
|
||||||
Log.d(TAG, "playerStatus: " + playerStatus.toString());
|
Log.d(TAG, "playerStatus: " + playerStatus.toString());
|
||||||
switch (playerStatus) {
|
|
||||||
case PLAYING:
|
|
||||||
state = PlaybackStateCompat.STATE_PLAYING;
|
|
||||||
break;
|
|
||||||
case PREPARED:
|
|
||||||
case PAUSED:
|
|
||||||
state = PlaybackStateCompat.STATE_PAUSED;
|
|
||||||
break;
|
|
||||||
case STOPPED:
|
|
||||||
state = PlaybackStateCompat.STATE_STOPPED;
|
|
||||||
break;
|
|
||||||
case SEEKING:
|
|
||||||
state = PlaybackStateCompat.STATE_FAST_FORWARDING;
|
|
||||||
break;
|
|
||||||
case PREPARING:
|
|
||||||
case INITIALIZING:
|
|
||||||
state = PlaybackStateCompat.STATE_CONNECTING;
|
|
||||||
break;
|
|
||||||
case INITIALIZED:
|
|
||||||
case INDETERMINATE:
|
|
||||||
state = PlaybackStateCompat.STATE_NONE;
|
|
||||||
break;
|
|
||||||
case ERROR:
|
|
||||||
state = PlaybackStateCompat.STATE_ERROR;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
state = PlaybackStateCompat.STATE_NONE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
state = PlaybackStateCompat.STATE_NONE;
|
|
||||||
}
|
}
|
||||||
sessionState.setState(state, getPosition(), getPlaybackSpeed());
|
|
||||||
sessionState.setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE
|
|
||||||
| PlaybackStateCompat.ACTION_REWIND
|
|
||||||
| PlaybackStateCompat.ACTION_FAST_FORWARD
|
|
||||||
| PlaybackStateCompat.ACTION_SKIP_TO_NEXT);
|
|
||||||
mediaSession.setPlaybackState(sessionState.build());
|
|
||||||
|
|
||||||
callback.statusChanged(new PSMPInfo(playerStatus, media));
|
callback.statusChanged(new PSMPInfo(playerStatus, media));
|
||||||
}
|
}
|
||||||
@ -1022,6 +882,8 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
|
|
||||||
void onBufferingUpdate(int percent);
|
void onBufferingUpdate(int percent);
|
||||||
|
|
||||||
|
void updateMediaSessionMetadata(Playable p);
|
||||||
|
|
||||||
boolean onMediaPlayerInfo(int code);
|
boolean onMediaPlayerInfo(int code);
|
||||||
|
|
||||||
boolean onMediaPlayerError(Object inObj, int what, int extra);
|
boolean onMediaPlayerError(Object inObj, int what, int extra);
|
||||||
@ -1130,153 +992,4 @@ public class PlaybackServiceMediaPlayer implements SharedPreferences.OnSharedPre
|
|||||||
});
|
});
|
||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final MediaSessionCompat.Callback sessionCallback = new MediaSessionCompat.Callback() {
|
|
||||||
|
|
||||||
private static final String TAG = "MediaSessionCompat";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPlay() {
|
|
||||||
Log.d(TAG, "onPlay()");
|
|
||||||
if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
|
|
||||||
resume();
|
|
||||||
} else if (playerStatus == PlayerStatus.INITIALIZED) {
|
|
||||||
setStartWhenPrepared(true);
|
|
||||||
prepare();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPause() {
|
|
||||||
Log.d(TAG, "onPause()");
|
|
||||||
if (playerStatus == PlayerStatus.PLAYING) {
|
|
||||||
pause(false, true);
|
|
||||||
}
|
|
||||||
if (UserPreferences.isPersistNotify()) {
|
|
||||||
pause(false, true);
|
|
||||||
} else {
|
|
||||||
pause(true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onStop() {
|
|
||||||
Log.d(TAG, "onStop()");
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSkipToPrevious() {
|
|
||||||
Log.d(TAG, "onSkipToPrevious()");
|
|
||||||
seekDelta(-UserPreferences.getRewindSecs() * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRewind() {
|
|
||||||
Log.d(TAG, "onRewind()");
|
|
||||||
seekDelta(-UserPreferences.getRewindSecs() * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFastForward() {
|
|
||||||
Log.d(TAG, "onFastForward()");
|
|
||||||
seekDelta(UserPreferences.getFastFowardSecs() * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSkipToNext() {
|
|
||||||
Log.d(TAG, "onSkipToNext()");
|
|
||||||
if(UserPreferences.shouldHardwareButtonSkip()) {
|
|
||||||
endPlayback(true);
|
|
||||||
} else {
|
|
||||||
seekDelta(UserPreferences.getFastFowardSecs() * 1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSeekTo(long pos) {
|
|
||||||
Log.d(TAG, "onSeekTo()");
|
|
||||||
seekTo((int) pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onMediaButtonEvent(final Intent mediaButton) {
|
|
||||||
Log.d(TAG, "onMediaButtonEvent(" + mediaButton + ")");
|
|
||||||
if (mediaButton != null) {
|
|
||||||
KeyEvent keyEvent = (KeyEvent) mediaButton.getExtras().get(Intent.EXTRA_KEY_EVENT);
|
|
||||||
handleMediaKey(keyEvent);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public boolean handleMediaKey(KeyEvent event) {
|
|
||||||
Log.d(TAG, "handleMediaKey(" + event +")");
|
|
||||||
if (event != null
|
|
||||||
&& event.getAction() == KeyEvent.ACTION_DOWN
|
|
||||||
&& event.getRepeatCount() == 0) {
|
|
||||||
switch (event.getKeyCode()) {
|
|
||||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
|
||||||
case KeyEvent.KEYCODE_HEADSETHOOK: {
|
|
||||||
Log.d(TAG, "Received Play/Pause event from RemoteControlClient");
|
|
||||||
if (playerStatus == PlayerStatus.PAUSED || playerStatus == PlayerStatus.PREPARED) {
|
|
||||||
resume();
|
|
||||||
} else if (playerStatus == PlayerStatus.INITIALIZED) {
|
|
||||||
setStartWhenPrepared(true);
|
|
||||||
prepare();
|
|
||||||
} else if (playerStatus == PlayerStatus.PLAYING) {
|
|
||||||
pause(false, true);
|
|
||||||
if (UserPreferences.isPersistNotify()) {
|
|
||||||
pause(false, true);
|
|
||||||
} else {
|
|
||||||
pause(true, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case KeyEvent.KEYCODE_MEDIA_PLAY: {
|
|
||||||
sessionCallback.onPlay();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case KeyEvent.KEYCODE_MEDIA_PAUSE: {
|
|
||||||
sessionCallback.onPause();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case KeyEvent.KEYCODE_MEDIA_STOP: {
|
|
||||||
sessionCallback.onStop();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case KeyEvent.KEYCODE_MEDIA_PREVIOUS: {
|
|
||||||
sessionCallback.onSkipToPrevious();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case KeyEvent.KEYCODE_MEDIA_REWIND: {
|
|
||||||
sessionCallback.onRewind();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
|
|
||||||
sessionCallback.onFastForward();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case KeyEvent.KEYCODE_MEDIA_NEXT: {
|
|
||||||
if(event.getSource() == InputDevice.SOURCE_CLASS_NONE ||
|
|
||||||
UserPreferences.shouldHardwareButtonSkip()) {
|
|
||||||
// assume the skip command comes from a notification or the lockscreen
|
|
||||||
// a >| skip button should actually skip
|
|
||||||
endPlayback(true);
|
|
||||||
} else {
|
|
||||||
// assume skip command comes from a (bluetooth) media button
|
|
||||||
// user actually wants to fast-forward
|
|
||||||
seekDelta(UserPreferences.getFastFowardSecs() * 1000);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
Log.d(TAG, "Unhandled key code: " + event.getKeyCode());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user