/*
* 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;
import java.io.IOException;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Handler;
import android.os.Vibrator;
import android.widget.Toast;
import ch.ethz.dcg.jukefox.commons.AndroidConstants;
import ch.ethz.dcg.jukefox.commons.Constants;
import ch.ethz.dcg.jukefox.commons.MethodNotImplementedException;
import ch.ethz.dcg.jukefox.commons.utils.AndroidUtils;
import ch.ethz.dcg.jukefox.commons.utils.JoinableThread;
import ch.ethz.dcg.jukefox.commons.utils.Log;
import ch.ethz.dcg.jukefox.controller.player.AndroidPlayerController;
import ch.ethz.dcg.jukefox.controller.player.IOnPlayerStateChangeListener;
import ch.ethz.dcg.jukefox.data.cache.ImportStateListener;
import ch.ethz.dcg.jukefox.manager.AndroidSettingsManager;
import ch.ethz.dcg.jukefox.manager.libraryimport.ImportService;
import ch.ethz.dcg.jukefox.manager.libraryimport.LibraryImportManager;
import ch.ethz.dcg.jukefox.model.AndroidCollectionModelManager;
import ch.ethz.dcg.jukefox.model.AndroidPlayerModelManager;
import ch.ethz.dcg.jukefox.model.collection.BaseAlbum;
import ch.ethz.dcg.jukefox.model.collection.BaseArtist;
import ch.ethz.dcg.jukefox.model.collection.BaseSong;
import ch.ethz.dcg.jukefox.model.collection.ImportedPlaylist;
import ch.ethz.dcg.jukefox.model.collection.Playlist;
import ch.ethz.dcg.jukefox.model.collection.PlaylistSong;
import ch.ethz.dcg.jukefox.model.collection.PlaylistSong.SongSource;
import ch.ethz.dcg.jukefox.model.commons.EmptyPlaylistException;
import ch.ethz.dcg.jukefox.model.commons.NoNextSongException;
import ch.ethz.dcg.jukefox.model.commons.PlaylistPositionOutOfRangeException;
import ch.ethz.dcg.jukefox.model.player.PlayModeType;
import ch.ethz.dcg.jukefox.model.player.PlayerState;
import ch.ethz.dcg.pancho3.R;
import ch.ethz.dcg.pancho3.commons.settings.ISettingsEditor;
import ch.ethz.dcg.pancho3.commons.settings.ISettingsReader;
import ch.ethz.dcg.pancho3.controller.eventhandlers.AlbumDetailEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.AlbumListEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.AlbumListMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.ArtistListEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.ArtistListMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.BaseJukefoxEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.ContextShuffleConfigEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.DeleteSongMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.FeedbackDialogEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.GenreListEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.GenreListMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.ImportDialogEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.ImportPlaylistEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.ListSelectionEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.LoadPlaylistMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.LoadVideoPlaylistMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.MapEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.PlayModeSelectionEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.PlayerActivityEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.PlaylistContextMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.PlaylistMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.SavePlaylistMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.SearchEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.ShuffleModeMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.SimilarModeMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.SimilarSongsToFamousArtistEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.SleepMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.SongContextMenuEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.SongListEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.SpaceActivityEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.TabEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.TagCloudEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.TagPlaylistGenerationEventListener;
import ch.ethz.dcg.pancho3.controller.eventhandlers.TitleSearchMenuEventListener;
import ch.ethz.dcg.pancho3.model.IAndroidApplicationStateController;
import ch.ethz.dcg.pancho3.model.JukefoxApplication;
import ch.ethz.dcg.pancho3.model.PlaylistImporter.PlaylistInfo;
import ch.ethz.dcg.pancho3.model.collection.ParcelableAlbum;
import ch.ethz.dcg.pancho3.model.collection.ParcelableArtist;
import ch.ethz.dcg.pancho3.model.collection.ParcelableSong;
import ch.ethz.dcg.pancho3.view.commons.JukefoxActivity;
import ch.ethz.dcg.pancho3.view.dialogs.DirectorySelectionDialog;
import ch.ethz.dcg.pancho3.view.dialogs.DontShowAgainDialog;
import ch.ethz.dcg.pancho3.view.dialogs.FeedbackDialog;
import ch.ethz.dcg.pancho3.view.dialogs.FirstStartDialog;
import ch.ethz.dcg.pancho3.view.dialogs.ImportDialog;
import ch.ethz.dcg.pancho3.view.dialogs.SdCardProblemDialog;
import ch.ethz.dcg.pancho3.view.dialogs.StandardDialog;
import ch.ethz.dcg.pancho3.view.dialogs.TakeATourDialog;
import ch.ethz.dcg.pancho3.view.overlays.AlbumDetails;
import ch.ethz.dcg.pancho3.view.overlays.ContextShuffleConfig;
import ch.ethz.dcg.pancho3.view.overlays.DeleteSongMenu;
import ch.ethz.dcg.pancho3.view.overlays.LoadPlaylistMenu;
import ch.ethz.dcg.pancho3.view.overlays.LoadVideoPlaylistMenu;
import ch.ethz.dcg.pancho3.view.overlays.PlayModeMenu;
import ch.ethz.dcg.pancho3.view.overlays.PlaylistContextMenu;
import ch.ethz.dcg.pancho3.view.overlays.PlaylistMenu;
import ch.ethz.dcg.pancho3.view.overlays.SavePlaylistMenu;
import ch.ethz.dcg.pancho3.view.overlays.ShuffleModeMenu;
import ch.ethz.dcg.pancho3.view.overlays.SimilarModeMenu;
import ch.ethz.dcg.pancho3.view.overlays.SimilarSongsToFamousArtist;
import ch.ethz.dcg.pancho3.view.overlays.SleepMenu;
import ch.ethz.dcg.pancho3.view.overlays.SongContextMenu;
import ch.ethz.dcg.pancho3.view.overlays.SongMenu;
import ch.ethz.dcg.pancho3.view.overlays.TagPlaylistGenerationActivity;
import ch.ethz.dcg.pancho3.view.tabs.JukefoxTabActivity;
import ch.ethz.dcg.pancho3.view.tabs.JukefoxTabActivity.Tab;
import ch.ethz.dcg.pancho3.view.tabs.MapActivity;
import ch.ethz.dcg.pancho3.view.tabs.PlayerActivity;
import ch.ethz.dcg.pancho3.view.tabs.SearchActivity;
import ch.ethz.dcg.pancho3.view.tabs.SpaceActivity;
import ch.ethz.dcg.pancho3.view.tabs.lists.AlbumList;
import ch.ethz.dcg.pancho3.view.tabs.lists.AlbumListMenu;
import ch.ethz.dcg.pancho3.view.tabs.lists.ArtistList;
import ch.ethz.dcg.pancho3.view.tabs.lists.ArtistListMenu;
import ch.ethz.dcg.pancho3.view.tabs.lists.GenreList;
import ch.ethz.dcg.pancho3.view.tabs.lists.GenreListMenu;
import ch.ethz.dcg.pancho3.view.tabs.lists.ListSelectionActivity;
import ch.ethz.dcg.pancho3.view.tabs.lists.SongList;
import ch.ethz.dcg.pancho3.view.tabs.lists.TagCloud;
import ch.ethz.dcg.pancho3.view.webpublisher.IAudioScrobblerListener;
public class Controller implements IViewController, ImportStateListener, IOnPlayerStateChangeListener,
SharedPreferences.OnSharedPreferenceChangeListener, IAudioScrobblerListener {
public static final int BACK_BUTTON_THRESH = 3000;
public static final String INTENT_EXTRA_BASE_ARTIST = "artist";
public static final String INTENT_EXTRA_BASE_ALBUM = "album";
public static final String INTENT_EXTRA_BASE_SONG = "song";
public static final String INTENT_EXTRA_SONG_POSITION = "songPosition";
public static final String INTENT_EXTRA_BASE_GENRE = "genre";
public static final String INTENT_EXTRA_BASE_TAG = "tag";
public static final String INTENT_EXTRA_SONG_PLAYLIST_POSITION = "songPlaylistPosition";
public static final String INTENT_EXTRA_PATH = "path";
public static final String INTENT_EXTRA_FROM_TIMESTAMP = "fromTimestamp";
public static final String INTENT_EXTRA_TO_TIMESTAMP = "toTimestamp";
public static final String INTENT_EXTRA_TAG_NAME = "tagName";
public static final String INTENT_EXTRA_NUMBER_OF_ALBUMS_WITH_THIS_NAME = "numAlbumsWithThisName";
public static final String INTENT_EXTRA_EVENT_TIME = "eventTime";
public static final int DOUBLE_CLICK_THRESH = 500;
private final static String TAG = Controller.class.getSimpleName();
private final JukefoxApplication application;
private final IAndroidApplicationStateController appStateController;
private AndroidPlayerModelManager playerModel;
private final AndroidPlayerController playerController;
private LibraryImportManager libraryImportManager;
private final ISettingsEditor settingsEditor;
private final ISettingsReader settingsReader;
private final WidgetController widgetController;
private final Vibrator vibrator;
private boolean pausedDueToCall = false;
private boolean pausedDueToHeadphone = false;
private boolean isHeadsetPlugged = false;
private Timer sleepTimer;
private long lastPlayPauseButtonPressedTime;
private final AndroidCollectionModelManager collectionModel;
private int loadingIdCounter = 0;
private ProgressDialog loadingDialog;
private HashMap<Integer, String> loadingMessages;
private final StartupManager startupManager;
private JoinableThread startupThread;
private final Handler handler = new Handler();
// private final TwitterPublisher twitterPublisher;
private final PlaylistAutosaveController playlistAutosaveController;
private ProgressDialog progressDialog;
public Controller(JukefoxApplication appCtx, AndroidPlayerController playerController,
AndroidCollectionModelManager collectionModel, AndroidPlayerModelManager playerModel) {
this.application = appCtx;
this.collectionModel = collectionModel;
this.playerModel = playerModel;
this.appStateController = collectionModel.getApplicationStateManager().getApplicationStateController();
this.playerController = playerController;
this.settingsEditor = AndroidSettingsManager.getAndroidSettingsEditor();
this.settingsReader = AndroidSettingsManager.getAndroidSettingsReader();
settingsReader.addSettingsChangeListener(this);
vibrator = (Vibrator) appCtx.getSystemService(Context.VIBRATOR_SERVICE);
startupManager = new StartupManager(this, appStateController, appCtx);
widgetController = new WidgetController(this);
// twitterPublisher = new TwitterPublisher(this);
playlistAutosaveController = new PlaylistAutosaveController(this);
loadingMessages = new HashMap<Integer, String>();
playerController.addOnPlayerStateChangeListener(this);
libraryImportManager = collectionModel.getLibraryImportManager();
}
public void startStartupManager() {
startupThread = new JoinableThread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "starting startup manager thread...");
startupManager.start();
Log.d(TAG, "startup manager thread finished.");
}
});
startupThread.start();
}
public AndroidPlayerController getPlayerController() {
return playerController;
}
public PlayerActivityEventListener createPlayerViewEventListener(PlayerActivity activity) {
return new PlayerActivityEventListener(this, activity);
}
public void startPlayModeSelection(Activity activity) {
if (activity == null) {
Intent intent = new Intent(application, PlayModeMenu.class);
application.startActivity(intent);
} else {
Log.v(TAG, "start playModeActivity");
// activity.startActivity(new Intent(activity,
// PlayModeSelection.class));
startActivity(activity, PlayModeMenu.class);
doOverlayAnimation(activity);
}
}
private void doOverlayAnimation(Activity activity) {
// activity.overridePendingTransition(R.anim.overlay_entry_animation,
// R.anim.hold);
}
public void doHapticFeedback() {
if (settingsReader.isHapticFeedback()) {
vibrator.vibrate(AndroidConstants.VIBRATION_DURATION);
}
}
public void startActivity(Activity activity, Class<?> classToLoad) {
Intent intent = new Intent(activity, classToLoad);
activity.startActivity(intent);
}
public void startReplacingActivity(Activity activity, Class<?> classToLoad) {
activity.startActivity(new Intent(activity, classToLoad));
}
public boolean ignoreUserEvents() {
// TODO: decide if user events are ignored
return false;
}
@Override
public BaseJukefoxEventListener createBaseJukefoxEventListener(JukefoxActivity activity) {
return new BaseJukefoxEventListener(this, activity);
}
@Override
public TabEventListener createTabEventListener(JukefoxTabActivity activity, Tab currentTab) {
return new TabEventListener(this, activity, currentTab);
}
public void showFirstStartDialog() {
if (FirstStartDialog.isOpen()) {
return;
}
Log.v(TAG, "showFirstStartDialog()");
Intent intent = new Intent(application, FirstStartDialog.class);
intent.putExtra(StandardDialog.DIALOG_MSG, application.getString(R.string.welcome_text));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
application.startActivity(intent);
}
public void showDirectorySelectionDialog(Activity activity) {
DirectorySelectionDialog dsd = new DirectorySelectionDialog(activity);
dsd.show();
}
public void showPreloadedDataProblemDialog(Throwable e) {
String msg = application.getString(R.string.unknown_exception_while_loading_data);
msg += e.getMessage();
showStandardDialog(msg);
}
public void showLibraryImportProblemDialog(Throwable e) {
String msg;
msg = application.getString(R.string.unknown_exception_during_import_1);
msg += e.getMessage() + "\n";
msg += application.getString(R.string.unknown_exception_during_import_2);
showStandardDialog(msg);
}
public void showCouldNotCreateDirectoriesDialog() {
if (AndroidConstants.THROW_METHOD_STUB_EXCEPTIONS) {
throw new MethodNotImplementedException();
}
}
public void showCouldNotOpenDbDialog() {
if (AndroidConstants.THROW_METHOD_STUB_EXCEPTIONS) {
throw new MethodNotImplementedException();
}
}
@Override
public PlayModeSelectionEventListener createPlayModeSelectionEventListener(JukefoxActivity activity) {
return new PlayModeSelectionEventListener(this, activity);
}
public MapEventListener createMapEventListener(MapActivity activity) {
return new MapEventListener(this, activity, activity.getMapRenderer(), false);
}
public Context getApplicationContext() {
return application;
}
public PlaylistAutosaveController getPlaylistAutosaveController() {
return playlistAutosaveController;
}
public void showAlbumDetailInfo(JukefoxActivity activity, BaseAlbum album) {
Intent intent = new Intent(application, AlbumDetails.class);
intent.putExtra(INTENT_EXTRA_BASE_ALBUM, new ParcelableAlbum(album));
if (activity != null) {
activity.startActivity(intent);
} else {
application.startActivity(intent);
}
}
public void previousButtonPressed() {
Log.i(TAG, "MAGIC: PREV BUTTON PRESSED");
pausedDueToCall = false;
pausedDueToHeadphone = false;
if (playerController.getPlaybackPosition() > BACK_BUTTON_THRESH) {
playerController.seekTo(0);
} else {
try {
playerController.playPrevious();
} catch (EmptyPlaylistException e) {
Log.w(TAG, e);
} catch (NoNextSongException e) {
Log.w(TAG, e);
}
}
}
public void nextButtonPressed() {
try {
playNextSong();
} catch (Exception e) {
Log.w(TAG, e);
if (!AndroidUtils.isSdCardOk()) {
showSdCardProblemDialog();
}
}
}
private void playNextSong() throws NoNextSongException, EmptyPlaylistException {
pausedDueToCall = false;
pausedDueToHeadphone = false;
playerController.playNext(); // TODO: verify 'true'
}
public void headsetPlayPausePressed(long eventTime) {
if (JukefoxApplication.ignoreEventsUntil > System.currentTimeMillis()) {
return;
}
mediaButtonPlayPausePressed(eventTime);
}
public void mediaButtonPlayPausePressed(long eventTime) {
if (JukefoxApplication.ignoreEventsUntil > System.currentTimeMillis()) {
return;
}
Log.v(TAG, "mediaButton PLayPause EventTime:" + eventTime + " lastTime: " + lastPlayPauseButtonPressedTime);
if (eventTime - lastPlayPauseButtonPressedTime < DOUBLE_CLICK_THRESH) {
nextButtonPressed();
} else {
lastPlayPauseButtonPressedTime = eventTime;
playPauseButtonPressed();
}
}
public void playPauseButtonPressed() {
pausedDueToCall = false;
pausedDueToHeadphone = false;
if (playerController.getPlayerState() == PlayerState.PLAY) {
playerController.pause();
} else if (playerController.getPlayerState() == PlayerState.PAUSE) {
try {
playerController.play();
} catch (Exception e) {
if (!AndroidUtils.isSdCardOk()) {
showSdCardProblemDialog();
}
Log.w(TAG, e);
}
} else { // STOP or ERROR
try {
playerController.playSongAtPosition(playerController.getCurrentSongIndex());
} catch (PlaylistPositionOutOfRangeException e) {
Log.w(TAG, e);
playerController.stop();
} catch (EmptyPlaylistException e) {
try {
playNextSong();
} catch (Exception e2) {
if (!AndroidUtils.isSdCardOk()) {
showSdCardProblemDialog();
}
}
}
}
}
@Override
public AlbumDetailEventListener createAlbumDetailEventListener(AlbumDetails albumDetails) {
return new AlbumDetailEventListener(this, albumDetails);
}
@Override
public ListSelectionEventListener createListSelectionEventListener(ListSelectionActivity activity) {
return new ListSelectionEventListener(this, activity);
}
@Override
public SongListEventListener createSongListEventListener(SongList songList) {
return new SongListEventListener(this, songList);
}
public ISettingsEditor getSettingsEditor() {
return settingsEditor;
}
public ISettingsReader getSettingsReader() {
return settingsReader;
}
public void showSongContextMenu(PlayerActivity activity, BaseSong<BaseArtist, BaseAlbum> song,
int currentSongPosition) {
Intent intent = new Intent(activity, SongContextMenu.class);
intent.putExtra(Controller.INTENT_EXTRA_SONG_PLAYLIST_POSITION, currentSongPosition);
intent.putExtra(Controller.INTENT_EXTRA_BASE_SONG, new ParcelableSong(song));
activity.startActivity(intent);
}
@Override
public ShuffleModeMenuEventListener createShuffleModeMenuEventListener(ShuffleModeMenu shuffleModeMenu) {
return new ShuffleModeMenuEventListener(this, shuffleModeMenu);
}
@Override
public AlbumListEventListener createAlbumListEventListener(AlbumList albumList) {
return new AlbumListEventListener(this, albumList);
}
public void updateLargeWidget() {
widgetController.updateLargeWidget();
}
public void updateNormalWidget() {
widgetController.updateNormalWidget();
}
public void headsetPlugged() {
if (isHeadsetPlugged) {
// return, as we already know that headset is plugged
return;
}
isHeadsetPlugged = true;
resumeMusicDueToHeadphonesIfNeeded();
}
public void headsetUnplugged() {
if (!isHeadsetPlugged) {
// return, as we already know that headset is unplugged
return;
}
isHeadsetPlugged = false;
pausedDueToCall = false;
}
private void resumeMusicDueToHeadphonesIfNeeded() {
if (pausedDueToHeadphone && settingsReader.isAutomaticallyResumeOnHeadsetPlugged()) {
try {
playerController.play();
} catch (Exception e) {
Log.w(TAG, e);
}
}
}
public void callStarted() {
pausedDueToHeadphone = false;
if (playerController.getPlayerState() == PlayerState.PLAY) {
pausedDueToCall = true;
playerController.pause();
}
}
public void callEnded() {
if (pausedDueToCall) {
try {
playerController.play();
} catch (Exception e) {
Log.w(TAG, e);
}
}
}
public void audioBecameNoisy() {
JukefoxApplication.setIgnoreEventsTime(System.currentTimeMillis() + 2000);
headsetUnplugged();
if (playerController.getPlayerState() == PlayerState.PLAY) {
pauseMusicDueToHeadPhones();
}
}
private void pauseMusicDueToHeadPhones() {
playerController.pause();
pausedDueToHeadphone = true;
pausedDueToCall = false;
}
public void androidMediaScannerFinished() {
if (getSettingsReader().isAutomaticImports()) {
doImportAsync(false, true); // flags: don't clean db; do reduced
// scan
}
}
public void doImportAsync(final boolean clearDb, final boolean reduced) {
libraryImportManager.doImportAsync(clearDb, reduced);
}
public void abortImportAsync() {
collectionModel.getLibraryImportManager().abortImportAsync();
}
@Override
public PlaylistMenuEventListener createPlaylistMenuEventListener(PlaylistMenu playlistMenu) {
return new PlaylistMenuEventListener(this, playlistMenu);
}
@Override
public LoadPlaylistMenuEventListener createLoadPlaylistMenuEventListener(LoadPlaylistMenu loadPlaylistMenu) {
return new LoadPlaylistMenuEventListener(this, loadPlaylistMenu);
}
@Override
public LoadVideoPlaylistMenuEventListener createLoadVideoPlaylistMenuEventListener(
LoadVideoPlaylistMenu loadVideoPlaylistMenu) {
return new LoadVideoPlaylistMenuEventListener(this, loadVideoPlaylistMenu);
}
@Override
public SavePlaylistMenuEventListener createSavePlaylistMenuEventListener(SavePlaylistMenu savePlaylistMenu) {
return new SavePlaylistMenuEventListener(this, savePlaylistMenu);
}
@Override
public SleepMenuEventListener createSleepMenuEventListener(SleepMenu sleepMenu) {
return new SleepMenuEventListener(this, sleepMenu);
}
public void setSleepTimer(int minutes) {
if (sleepTimer != null) {
sleepTimer.cancel();
}
sleepTimer = new Timer();
sleepTimer.schedule(new TimerTask() {
@Override
public void run() {
playerController.pause();
}
}, minutes * 60000L);
Log.v(TAG, "sleep timer set");
}
public void cancelSleepTimer() {
if (sleepTimer != null) {
sleepTimer.cancel();
sleepTimer = null;
}
}
public void showAlbumList(JukefoxActivity activity, BaseArtist artist) {
Intent intent = new Intent(application, AlbumList.class);
intent.putExtra(INTENT_EXTRA_BASE_ARTIST, new ParcelableArtist(artist));
if (activity != null) {
activity.startActivity(intent);
} else {
application.startActivity(intent);
}
}
@Override
public ArtistListEventListener createArtistListEventListener(ArtistList artistList) {
return new ArtistListEventListener(this, artistList);
}
@Override
public GenreListEventListener createGenreListEventListener(GenreList genreList) {
return new GenreListEventListener(this, genreList);
}
@Override
public SimilarModeMenuEventListener createSimilarModeMenuEventListener(SimilarModeMenu similarModeMenu) {
return new SimilarModeMenuEventListener(this, similarModeMenu);
}
@Override
public GenreListMenuEventListener createGenreListMenuEventListener(GenreListMenu genreListMenu) {
return new GenreListMenuEventListener(this, genreListMenu);
}
@Override
public ArtistListMenuEventListener createArtistListMenuEventListener(ArtistListMenu artistListMenu) {
return new ArtistListMenuEventListener(this, artistListMenu);
}
@Override
public TagCloudEventListener createTagCloudEventListener(TagCloud tagCloud) {
return new TagCloudEventListener(this, tagCloud);
}
@Override
public SearchEventListener createSearchEventListener(SearchActivity searchActivity) {
return new SearchEventListener(this, searchActivity);
}
@Override
public void onBaseDataCommitted() {
}
@Override
public void onCoordinatesFetched() {
}
@Override
public void onAlbumCoversFetched() {
}
public int setLoading(final Context activityContext, final String msg) {
final int id = loadingIdCounter;
handler.post(new Runnable() {
@Override
public void run() {
if (loadingMessages.size() == 0) {
loadingDialog = ProgressDialog.show(activityContext, activityContext
.getString(R.string.please_wait), msg, true);
} else {
Log.v(TAG, "Loading msg size " + loadingMessages.size());
loadingDialog.setMessage(msg);
}
loadingIdCounter++;
loadingMessages.put(id, msg);
}
});
return id;
}
public void finishLoading(int id) {
loadingMessages.remove(id);
handler.post(new Runnable() {
@Override
public void run() {
if (loadingMessages.size() == 0) {
loadingDialog.dismiss();
} else {
loadingDialog.setMessage(loadingMessages.values().iterator().next());
}
}
});
}
@Override
public TitleSearchMenuEventListener createTitleSearchMenuEventListener(SongMenu titleSearchResultMenu) {
return new TitleSearchMenuEventListener(this, titleSearchResultMenu);
}
@Override
public SpaceActivityEventListener createSpaceEventListener(SpaceActivity spaceActivity) {
return new SpaceActivityEventListener(this, spaceActivity);
}
@Override
public SongContextMenuEventListener createSongContextMenuEventListener(SongContextMenu songContextMenu) {
return new SongContextMenuEventListener(this, songContextMenu);
}
@Override
public TagPlaylistGenerationEventListener createTagPlaylistGenerationEventListener(
TagPlaylistGenerationActivity tagPlaylistGeneration) {
return new TagPlaylistGenerationEventListener(this, tagPlaylistGeneration);
}
// public void showSdCardProblemDialog() {
// Intent intent = new Intent(appCtx, DialogDisplayer.class);
// intent.putExtra(DialogDisplayer.INTENT_EXTRA_DIALOG_TYPE,
// DialogDisplayer.DialogType.STANDARD);
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// appCtx.startActivity(intent);
// }
@Override
public SimilarSongsToFamousArtistEventListener createSimilarSongsToFamousArtistEventListener(
SimilarSongsToFamousArtist similarSongsToFamousArtist) {
return new SimilarSongsToFamousArtistEventListener(this, similarSongsToFamousArtist);
}
public void showStandardDialog(String msg) {
showStandardDialog(null, null, msg);
}
public void showStandardDialog(Activity activity, Integer requestCode, String msg) {
Intent intent = new Intent(activity == null ? application : activity, StandardDialog.class);
intent.putExtra(StandardDialog.DIALOG_MSG, msg);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (activity == null) {
application.startActivity(intent);
return;
}
activity.startActivityForResult(intent, requestCode);
}
public void showDontShowAgainDialog(String msg, String dontShowSharedPrefKey) {
if (settingsReader.isDontShowAgain(dontShowSharedPrefKey)) {
return;
}
Intent intent = new Intent(application, DontShowAgainDialog.class);
intent.putExtra(StandardDialog.DIALOG_MSG, msg);
intent.putExtra(DontShowAgainDialog.SHARED_PREF_KEY, dontShowSharedPrefKey);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
application.startActivity(intent);
}
@Override
public void onImportCompleted(boolean hadChanges) {
stopImportService();
if (hadChanges) {
// Notify user that import completed (if there were any changes)
handler.post(new Runnable() {
@Override
public void run() {
Toast toast = Toast.makeText(application, application.getString(R.string.import_completed),
Toast.LENGTH_LONG);
toast.show();
}
});
}
}
private void startImportService() {
Log.v(TAG, "startImportService()");
Intent intent = new Intent(JukefoxApplication.getAppContext(), ImportService.class);
JukefoxApplication.getAppContext().startService(intent);
}
private void stopImportService() {
Intent intent = new Intent(JukefoxApplication.getAppContext(), ImportService.class);
JukefoxApplication.getAppContext().stopService(intent);
Log.v(TAG, "stopService()");
}
@Override
public PlaylistContextMenuEventListener createPlaylistContextMenuEventListener(
PlaylistContextMenu playlistContextMenu) {
return new PlaylistContextMenuEventListener(this, playlistContextMenu);
}
public ImportDialogEventListener createImportDialogEventListener(ImportDialog importDialog) {
return new ImportDialogEventListener(this, importDialog);
}
public void showTakeATourDialog() {
Intent intent = new Intent(application, TakeATourDialog.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
application.startActivity(intent);
}
public void showAboutDialog() {
showStandardDialog("jukefox " + "v" + AndroidUtils.getVersionName() + "\n"
+ application.getString(R.string.about_info));
}
public void playDateRangeFromIntent(Intent intent) {
/*
* Playlist playlist; try { playlist =
* model.createDateRangePlaylist(intent); // TODO: this model here needs
* an interface for this method. //
* ((Model)data).getDbWrapper().printPlayLog(); // TODO: debug only... }
* catch (DataUnavailableException e1) { Log.w(TAG, e1); return; } if
* (playlist.size() < 1) { Log.w(TAG,
* "Failed to create playlist for date range"); return; }
* playlistController.clearPlaylist();
* playlistController.appendSongsAtEnd(playlist.getSongList()); try {
* playlistController.setPlayMode(PlayModeType.SIMILAR); int position =
* JukefoxApplication.getRandom().nextInt(playlist.size());
* playlistController.playSongAtPosition(position); } catch
* (PlaylistPositionOutOfRangeException e) { Log.w(TAG, e); }
*/
}
public void playTagFromIntent(Intent intent) {
String tagName = null;
try {
tagName = intent.getExtras().getString(INTENT_EXTRA_TAG_NAME);
BaseSong<BaseArtist, BaseAlbum> song = collectionModel.getSongProvider().getBaseSong(tagName);
Playlist playlist = new Playlist();
playlist.appendSongAtEnd(new PlaylistSong<BaseArtist, BaseAlbum>(song, SongSource.AUTOMATICALLY_SELECTED));
playerController.stop();
playerController.clearPlaylist();
playerController.appendSongAtEnd(new PlaylistSong<BaseArtist, BaseAlbum>(song, SongSource.TAG_BASED));
int artistAvoidance = AndroidSettingsManager.getAndroidSettingsReader().getSimilarArtistAvoidanceNumber();
playerController.setPlayMode(PlayModeType.SIMILAR, artistAvoidance, Constants.SAME_SONG_AVOIDANCE_NUM);
playerController.play();
} catch (Exception e) {
Log.w(TAG, e);
showStandardDialog(application.getString(R.string.could_not_play_tag_intent_playlist) + " " + tagName);
}
}
public void stopMusicFromIntent(Intent intent) {
stopButtonPressed();
}
public void showSdCardProblemDialog() {
if (SdCardProblemDialog.isOpen()) {
return;
}
String msg = application.getString(R.string.no_sd_card_available);
Intent intent = new Intent(application, SdCardProblemDialog.class);
intent.putExtra(SdCardProblemDialog.DIALOG_MSG, msg);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
application.startActivity(intent);
}
public void onFirstStartDialogClosed() {
startStartupManager();
showTakeATourDialog();
appStateController.setFirstStart(false);
}
// public void showFbSendActivity(String msg, String caption) {
// Intent intent = new Intent(appCtx, FbSendActivity.class);
// intent.putExtra(FbSendActivity.KEY_MSG, msg);
// intent.putExtra(FbSendActivity.KEY_COLLAGE_CAPTION, caption);
// intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// appCtx.startActivity(intent);
// }
public void stopButtonPressed() {
try {
pausedDueToCall = false;
pausedDueToHeadphone = false;
// playlistController.savePlaylist(playlistController.getCurrentPlaylist(),
// // TODO save playlist not possible anymore
// Constants.CURRENT_PLAYLIST_NAME);
playerController.stop();
} catch (Throwable e) {
Log.w(TAG, e);
}
}
public void showFeedbackDialog() {
Intent intent = new Intent(application, FeedbackDialog.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
application.startActivity(intent);
}
public void startMarketWithJukefox() {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=ch.ethz.dcg.pancho3"));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
application.startActivity(intent);
}
public void startEmailActivity() {
StringBuilder body = new StringBuilder();
try {
body.append("\n-----------------\n");
body.append("android-version: " + AndroidUtils.getAndroidVersionName() + "\n");
body.append("model: " + AndroidUtils.getModel() + "\n");
body.append("jukefox-version: " + AndroidUtils.getVersionName() + "\n");
body.append("-----------------\n");
} catch (Error e) {
Log.w(TAG, e);
}
String subject = "[jukefox]";
try {
subject = "[jukefox " + AndroidUtils.getVersionName() + "]";
} catch (Error e) {
Log.w(TAG, e);
}
// Intent intent = new Intent(Intent.ACTION_SENDTO,
// Uri.fromParts("mailto", Constants.MUSICEXPLORER_EMAIL, null));
Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts("mailto", Constants.MUSICEXPLORER_EMAIL, null));
// intent.putExtra(Intent.EXTRA_EMAIL, "kuhnmi@tik.ee.ethz.ch");
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, body.toString());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
application.startActivity(intent);
}
public void goToAlbum(Activity activity, BaseAlbum album) {
Intent intent = new Intent(activity, MapActivity.class);
intent.putExtra(Controller.INTENT_EXTRA_BASE_ALBUM, new ParcelableAlbum(album));
activity.startActivity(intent);
activity.finish();
}
@Override
public FeedbackDialogEventListener createFeedbackDialogEventListener(FeedbackDialog feedbackDialog) {
return new FeedbackDialogEventListener(this);
}
@Override
public AlbumListMenuEventListener createAlbumListMenuEventListener(AlbumListMenu albumListMenu) {
return new AlbumListMenuEventListener(this, albumListMenu);
}
public void groupAlbum(final String name) {
try {
collectionModel.getModelSettingsManager().addAlbumNameToGroup(name);
Log.v(TAG, "group albums done");
postToast(application.getString(R.string.grouping_album_finished_toast));
} catch (Throwable e) {
Log.w(TAG, e);
postToast(application.getString(R.string.grouping_album_failed_toast));
return;
}
Log.v(TAG, "performing library import after album grouping");
doImportAsync(false, false);
// String msg = appCtx.getString(R.string.grouping_album_toast);
// new JoinableThread(new Runnable() {
// @Override
// public void run() {
// try {
// data.groupAlbum(name);
// postToast(appCtx.getString(R.string.grouping_album_finished_toast));
// } catch (Throwable e) {
// Log.w(TAG, e);
// postToast(appCtx.getString(R.string.grouping_album_failed_toast));
// return;
// }
// doImportAsync(false, false);
// }
// }).start();
}
public void postToast(final String msg) {
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(application, msg, Toast.LENGTH_LONG).show();
}
});
}
public void ungroupAlbum(Activity activity, String name) {
try {
collectionModel.getModelSettingsManager().removeAlbumNameToGroup(name);
postToast(application.getString(R.string.ungrouping_album_finished_toast));
} catch (Throwable e) {
Log.w(TAG, e);
postToast(application.getString(R.string.ungrouping_album_failed_toast));
return;
}
doImportAsync(false, false);
activity.finish();
}
public void showToast(final String message) {
JukefoxApplication.getHandler().post(new Runnable() {
@Override
public void run() {
Toast t = Toast.makeText(application, message, Toast.LENGTH_LONG);
t.show();
}
});
}
public void scrobbleAuthenticationFailed() {
showToast(application.getString(R.string.could_not_connect_audioscrobbler));
}
@Override
public void onImportAborted(boolean hadChanges) {
stopImportService();
}
@Override
public void onImportStarted() {
startImportService();
}
public void performVersionChanges() {
// TODO: here, we should check whether this is a new installation. If
// not, we should check whether the app is up-to-date (i.e. current
// version is the same as the last known version (=> new shared pref),
// and if not, apply all changes recursively back to the last known
// version.
if (settingsReader.isScrobblingEnabled()) {
settingsEditor.updateScrobblingEnabledPref();
}
}
@Override
public DeleteSongMenuEventListener createDeleteSongMenuEventListener(DeleteSongMenu deleteSongMenu) {
return new DeleteSongMenuEventListener(this, deleteSongMenu);
}
public void ignoreSong(BaseSong<BaseArtist, BaseAlbum> song) {
collectionModel.getModifyProvider().ignoreSong(song);
}
public void deleteSong(BaseSong<BaseArtist, BaseAlbum> song) {
collectionModel.getModifyProvider().deleteSong(song);
}
@Override
public void onPlayerStateChanged(PlayerState playerState) {
application.updateJukefoxIntentReceiver();
}
/**
* stops the playerservice if the music is not playing
*
* @return returns true if the service was stopped, false otherwise
*/
public boolean stopServiceIfNotNeeded() {
if (playerController.getPlayerState() != PlayerState.PLAY) {
playerController.stopPlayerService();
return true;
}
return false;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(application.getString(R.string.KEY_LOCK_SCREEN_CONTROLS))) {
application.updateJukefoxIntentReceiver();
}
}
@Override
public ContextShuffleConfigEventListener createContextShuffleConfigEventListener(
ContextShuffleConfig smartShuffleConfig) {
return new ContextShuffleConfigEventListener(this, smartShuffleConfig);
}
public void showProgressDialog(final JukefoxActivity activity, final String msg) {
if (progressDialog != null) {
return;
}
handler.post(new Runnable() {
@Override
public void run() {
Log.v(TAG, "showing progress dialog.");
progressDialog = new ProgressDialog(activity);
progressDialog.setMessage(msg);
progressDialog.show();
}
});
}
public void removeProgressDialog() {
if (progressDialog == null) {
return;
}
handler.post(new Runnable() {
@Override
public void run() {
Log.v(TAG, "removing progress dialog.");
progressDialog.dismiss();
progressDialog = null;
}
});
}
@Override
public ImportPlaylistEventListener createImportPlaylistEventListener() {
return new ImportPlaylistEventListener(this);
}
public ImportedPlaylist importPlaylist(PlaylistInfo info) throws IOException {
ImportedPlaylist playlist = collectionModel.getPlaylistImporter().parse(info);
playerController.setPlaylist(playlist);
if (!playlist.isPlaylistEmpty()) {
try {
playerController.loadSongAtPosition(0); // playSongAtPosition(0);
} catch (PlaylistPositionOutOfRangeException e) {
// should never happen!
Log.w(TAG, e);
}
}
return playlist;
}
public void onTerminate() {
try {
getPlaylistAutosaveController().saveCurrentPlaylist();
getPlaylistAutosaveController().cancelTimers();
} catch (Exception e) {
Log.w(TAG, e);
}
}
@Override
public void onAuthenticationFailed() {
// TODO Auto-generated method stub
if (AndroidConstants.THROW_METHOD_STUB_EXCEPTIONS) {
throw new MethodNotImplementedException();
}
}
@Override
public void onSongCompleted(PlaylistSong<BaseArtist, BaseAlbum> song) {
}
@Override
public void onSongSkipped(PlaylistSong<BaseArtist, BaseAlbum> song, int position) {
}
@Override
public void onSongStarted(PlaylistSong<BaseArtist, BaseAlbum> song) {
}
@Override
public void onImportProblem(Throwable e) {
showLibraryImportProblemDialog(e);
}
}