/*
* Copyright 2008-2013, ETH Zürich, Samuel Welten, Michael Kuhn, Tobias Langner,
* Sandro Affentranger, Lukas Bossard, Michael Grob, Rahul Jain,
* Dominic Langenegger, Sonia Mayor Alonso, Roger Odermatt, Tobias Schlueter,
* Yannick Stucki, Sebastian Wendland, Samuel Zehnder, Samuel Zihlmann,
* Samuel Zweifel
*
* This file is part of Jukefox.
*
* Jukefox is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or any later version. Jukefox is
* distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* Jukefox. If not, see <http://www.gnu.org/licenses/>.
*/
package ch.ethz.dcg.jukefox.controller.player;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.preference.PreferenceManager;
import ch.ethz.dcg.jukefox.commons.AndroidConstants;
import ch.ethz.dcg.jukefox.commons.Constants;
import ch.ethz.dcg.jukefox.commons.DataUnavailableException;
import ch.ethz.dcg.jukefox.commons.utils.AndroidUtils;
import ch.ethz.dcg.jukefox.commons.utils.Log;
import ch.ethz.dcg.jukefox.controller.player.mediaplayer.AndroidMediaPlayerWrapper;
import ch.ethz.dcg.jukefox.controller.player.playbackcontroller.BasePlaybackController;
import ch.ethz.dcg.jukefox.controller.player.playbackcontroller.CrossfadingPlaybackController;
import ch.ethz.dcg.jukefox.controller.player.playbackcontroller.DurationBugfixPlaybackController;
import ch.ethz.dcg.jukefox.controller.player.playbackcontroller.GaplessPlaybackController;
import ch.ethz.dcg.jukefox.controller.player.playbackcontroller.IPlaybackController;
import ch.ethz.dcg.jukefox.controller.player.playlistmanager.IPlaylistManager;
import ch.ethz.dcg.jukefox.controller.player.playlistmanager.PlaylistManager;
import ch.ethz.dcg.jukefox.manager.AndroidSettingsManager;
import ch.ethz.dcg.jukefox.model.AbstractCollectionModelManager;
import ch.ethz.dcg.jukefox.model.AbstractPlayerModelManager;
import ch.ethz.dcg.jukefox.model.collection.BaseAlbum;
import ch.ethz.dcg.jukefox.model.collection.BaseArtist;
import ch.ethz.dcg.jukefox.model.collection.IReadOnlyPlaylist;
import ch.ethz.dcg.jukefox.model.collection.Playlist;
import ch.ethz.dcg.jukefox.model.collection.PlaylistSong;
import ch.ethz.dcg.jukefox.model.player.PlayModeType;
import ch.ethz.dcg.jukefox.model.player.PlayerState;
import ch.ethz.dcg.pancho3.commons.settings.ISettingsReader;
import ch.ethz.dcg.pancho3.controller.player.PlayerService;
import ch.ethz.dcg.pancho3.model.JukefoxApplication;
import ch.ethz.dcg.pancho3.view.web.ScrobbledroidPublisher;
import ch.ethz.dcg.pancho3.view.webpublisher.AudioScrobbler;
public class AndroidPlayerController extends AbstractPlayerController implements OnSharedPreferenceChangeListener {
private static final String TAG = AndroidPlayerController.class.getSimpleName();
private AudioScrobbler audioScrobbler = null;
private ScrobbledroidPublisher scrobbleDroidScrobbler = null;
private boolean scrobbleEnabled = AndroidSettingsManager.getAndroidSettingsReader().isInternalScrobblingEnabled();
private JukefoxApplication application;
private static PlayerService playerService;
public AndroidPlayerController(JukefoxApplication application, AbstractCollectionModelManager collectionModel,
AbstractPlayerModelManager playerModel) {
super(collectionModel, playerModel);
this.application = application;
loadLastPlaylist();
PreferenceManager.getDefaultSharedPreferences(application).registerOnSharedPreferenceChangeListener(this);
readAudioScrobblerSettings();
}
private void loadLastPlaylist() {
setPlayMode(PlayModeType.SMART_SHUFFLE, 0, Constants.SAME_SONG_AVOIDANCE_NUM);
// load the default playlist first
Playlist playlist;
try {
playlist = JukefoxApplication.getPlayerModel().getPlaylistManager().loadPlaylistFromFileByName(
AndroidConstants.CURRENT_PLAYLIST_NAME);
setPlaylist(playlist);
} catch (DataUnavailableException e) {
Log.w(TAG, e);
}
}
public void readAudioScrobblerSettings() {
if (AndroidSettingsManager.getAndroidSettingsReader().isInternalScrobblingEnabled()) {
scrobbleEnabled = true;
if (audioScrobbler == null) {
audioScrobbler = new AudioScrobbler(application.getController(), this);
}
audioScrobbler.readSettings();
} else if (AndroidSettingsManager.getAndroidSettingsReader().isScrobbledroidEnabled()) {
scrobbleEnabled = true;
if (scrobbleDroidScrobbler == null) {
scrobbleDroidScrobbler = new ScrobbledroidPublisher(this);
}
} else {
scrobbleEnabled = false;
if (scrobbleDroidScrobbler != null) {
scrobbleDroidScrobbler.onDestroy();
scrobbleDroidScrobbler = null;
}
if (audioScrobbler != null) {
audioScrobbler.onDestroy();
audioScrobbler = null;
}
}
}
@Override
public void informSongCompletedListeners(PlaylistSong<BaseArtist, BaseAlbum> song) {
super.informSongCompletedListeners(song);
}
@Override
public void informSongStartedListeners(PlaylistSong<BaseArtist, BaseAlbum> song) {
super.informSongStartedListeners(song);
}
public void stopPlayerService() {
Log.v(TAG, "stopService(): playerSerivce == null: " + (playerService == null));
if (playerService != null) {
playerService.stopSelf();
}
// Log.v(TAG, "stopService()");
}
private void startService() {
Log.v(TAG, "startService()");
Intent playButtonIntent = new Intent(JukefoxApplication.getAppContext(), PlayerService.class);
ComponentName tmp = JukefoxApplication.getAppContext().startService(playButtonIntent);
Log.v(TAG, "service started. ComponentName: " + tmp);
}
@Override
public void pause() {
super.pause();
JukefoxApplication.getWakeLockManager().releasePlayerWakeLock();
stopPlayerService();
}
@Override
public void play() {
super.play();
startService();
JukefoxApplication.getWakeLockManager().acquirePlayerWakeLock();
}
@Override
public void stop() {
super.stop();
JukefoxApplication.getWakeLockManager().releasePlayerWakeLock();
stopPlayerService();
}
public static void setPlayerService(PlayerService service) {
playerService = service;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences arg0, String key) {
Context ctx = JukefoxApplication.getAppContext();
String keyLockScreenControls = ctx.getString(ch.ethz.dcg.pancho3.R.string.KEY_LOCK_SCREEN_CONTROLS);
String keyGapless = ctx.getString(ch.ethz.dcg.pancho3.R.string.KEY_GAPLESS);
String keyGaplessOffset = ctx.getString(ch.ethz.dcg.pancho3.R.string.KEY_GAPLESS_OFFSET);
String keyScrobbleEnabled = ctx.getString(ch.ethz.dcg.pancho3.R.string.KEY_SCROBBLE_ENABLED);
String keyCrossfading = ctx.getString(ch.ethz.dcg.pancho3.R.string.KEY_CROSSFADING);
String keyBeatMatching = ctx.getString(ch.ethz.dcg.pancho3.R.string.KEY_BEAT_MATCHING);
String keyScrobbleType = ctx.getString(ch.ethz.dcg.pancho3.R.string.KEY_SCROBBLE_TYPE);
if (key.equals(keyLockScreenControls)) {
// if (application.getModel().getSettingsReader()
// .isLockScreenControls()) {
// // if (getPlayerState() == PlayerState.PLAY) {
// // disableStandardLockScreen();
// // }
// } else {
// JukefoxApplication.enableLockScreen();
// }
return;
} else if (key.equals(keyGapless)) {
recreatePlaybackController();
} else if (key.equals(keyCrossfading)) {
recreatePlaybackController();
} else if (key.equals(keyBeatMatching)) {
recreatePlaybackController();
} else if (key.equals(keyGaplessOffset)) {
recreatePlaybackController();
} else if (key.equals(keyScrobbleEnabled) || key.equals(keyScrobbleType)) {
readAudioScrobblerSettings();
}
}
private void recreatePlaybackController() {
// Kind of a hack to make the playlistManager write an updated value of
// position in song to the playlist
IReadOnlyPlaylist playlist = currentPlaylistManager.getCurrentPlaylist();
PlayerState state = getPlayerState();
stop();
playbackController.onDestroy();
playbackController = createPlaybackController(this, collectionModel, playerModel, currentPlaylistManager);
try {
if (state == PlayerState.PLAY) {
playSongAtPosition(playlist.getPositionInList());
seekTo(playlist.getPositionInSong());
}
} catch (Exception e) {
Log.w(TAG, e);
}
}
@Override
protected IPlaybackController createPlaybackController(IPlaybackInfoBroadcaster listenerInformer,
AbstractCollectionModelManager collectionModel, AbstractPlayerModelManager playerModel,
IPlaylistManager playlistManager) {
ISettingsReader settings = AndroidSettingsManager.getAndroidSettingsReader();
IPlaybackController player = null;
AndroidMediaPlayerWrapper mediaPlayer1 = new AndroidMediaPlayerWrapper();
if (AndroidUtils.isDurationProblemOs()) {
AndroidMediaPlayerWrapper mediaPlayer2 = new AndroidMediaPlayerWrapper();
player = new DurationBugfixPlaybackController(listenerInformer, collectionModel, playerModel,
currentPlaylistManager, settings.getAutoGaplessGapRemoveTime(), settings.getGaplessGapRemoveTime(),
mediaPlayer1, mediaPlayer2);
} else if (settings.isCrossfadingEnabled()) {
AndroidMediaPlayerWrapper mediaPlayer2 = new AndroidMediaPlayerWrapper();
player = new CrossfadingPlaybackController(listenerInformer, collectionModel, playerModel,
currentPlaylistManager, settings.getAutoGaplessGapRemoveTime(), settings.getGaplessGapRemoveTime(),
mediaPlayer1, mediaPlayer2, settings.isBeatMatchingEnabled());
} else if (settings.isGapless()) {
AndroidMediaPlayerWrapper mediaPlayer2 = new AndroidMediaPlayerWrapper();
player = new GaplessPlaybackController(listenerInformer, collectionModel, playerModel,
currentPlaylistManager, settings.getAutoGaplessGapRemoveTime(), settings.getGaplessGapRemoveTime(),
mediaPlayer1, mediaPlayer2);
}
if (player == null) {
player = new BasePlaybackController(listenerInformer, collectionModel, playerModel, currentPlaylistManager,
mediaPlayer1);
}
return player;
}
@Override
protected IPlaylistManager createPlaylistManager(IPlaybackInfoBroadcaster listenerInformer,
AbstractCollectionModelManager collectionModel, AbstractPlayerModelManager playerModel) {
return new PlaylistManager(collectionModel, playerModel, this, this);
}
}