From cfd014d38cba03ba05f571597b361ab253bff578 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Sat, 25 Apr 2015 17:03:02 -0700 Subject: Update to gradle --- .../dsub/activity/DownloadActivity.java | 62 - .../dsub/activity/EditPlayActionActivity.java | 246 -- .../dsub/activity/QueryReceiverActivity.java | 85 - .../dsub/activity/SettingsActivity.java | 91 - .../dsub/activity/SubsonicActivity.java | 860 ------- .../dsub/activity/SubsonicFragmentActivity.java | 686 ------ .../dsub/activity/VoiceQueryReceiverActivity.java | 61 - .../daneren2005/dsub/adapter/AlbumGridAdapter.java | 73 - .../daneren2005/dsub/adapter/AlbumListAdapter.java | 154 -- .../daneren2005/dsub/adapter/ArtistAdapter.java | 97 - .../daneren2005/dsub/adapter/BookmarkAdapter.java | 64 - .../daneren2005/dsub/adapter/ChatAdapter.java | 109 - .../dsub/adapter/DownloadFileAdapter.java | 49 - .../daneren2005/dsub/adapter/DrawerAdapter.java | 126 - .../daneren2005/dsub/adapter/EntryAdapter.java | 82 - .../daneren2005/dsub/adapter/GenreAdapter.java | 60 - .../daneren2005/dsub/adapter/MergeAdapter.java | 290 --- .../daneren2005/dsub/adapter/PlaylistAdapter.java | 70 - .../dsub/adapter/PodcastChannelAdapter.java | 60 - .../dsub/adapter/SackOfViewsAdapter.java | 181 -- .../daneren2005/dsub/adapter/SettingsAdapter.java | 59 - .../daneren2005/dsub/adapter/ShareAdapter.java | 56 - .../daneren2005/dsub/adapter/UserAdapter.java | 52 - .../dsub/audiofx/AudioEffectsController.java | 69 - .../dsub/audiofx/EqualizerController.java | 198 -- .../dsub/audiofx/LoudnessEnhancerController.java | 77 - src/github/daneren2005/dsub/domain/Artist.java | 145 -- src/github/daneren2005/dsub/domain/ArtistInfo.java | 76 - src/github/daneren2005/dsub/domain/Bookmark.java | 105 - .../daneren2005/dsub/domain/ChatMessage.java | 51 - src/github/daneren2005/dsub/domain/DLNADevice.java | 78 - src/github/daneren2005/dsub/domain/Genre.java | 69 - src/github/daneren2005/dsub/domain/Indexes.java | 94 - src/github/daneren2005/dsub/domain/Lyrics.java | 57 - .../daneren2005/dsub/domain/MusicDirectory.java | 559 ----- .../daneren2005/dsub/domain/MusicFolder.java | 49 - .../daneren2005/dsub/domain/PlayerQueue.java | 30 - .../daneren2005/dsub/domain/PlayerState.java | 47 - src/github/daneren2005/dsub/domain/Playlist.java | 128 -- .../daneren2005/dsub/domain/PodcastChannel.java | 145 -- .../daneren2005/dsub/domain/PodcastEpisode.java | 54 - .../dsub/domain/RemoteControlState.java | 38 - .../daneren2005/dsub/domain/RemoteStatus.java | 63 - src/github/daneren2005/dsub/domain/RepeatMode.java | 28 - .../daneren2005/dsub/domain/SearchCritera.java | 55 - .../daneren2005/dsub/domain/SearchResult.java | 52 - src/github/daneren2005/dsub/domain/ServerInfo.java | 213 -- src/github/daneren2005/dsub/domain/Share.java | 165 -- src/github/daneren2005/dsub/domain/User.java | 117 - src/github/daneren2005/dsub/domain/Version.java | 181 -- .../daneren2005/dsub/fragments/AdminFragment.java | 147 -- .../daneren2005/dsub/fragments/ChatFragment.java | 250 -- .../dsub/fragments/DownloadFragment.java | 189 -- .../dsub/fragments/EqualizerFragment.java | 441 ---- .../daneren2005/dsub/fragments/LyricsFragment.java | 107 - .../daneren2005/dsub/fragments/MainFragment.java | 586 ----- .../dsub/fragments/NowPlayingFragment.java | 1568 ------------- .../dsub/fragments/PreferenceCompatFragment.java | 313 --- .../daneren2005/dsub/fragments/SearchFragment.java | 368 --- .../dsub/fragments/SelectArtistFragment.java | 333 --- .../dsub/fragments/SelectBookmarkFragment.java | 131 -- .../dsub/fragments/SelectDirectoryFragment.java | 1597 ------------- .../dsub/fragments/SelectGenreFragment.java | 71 - .../dsub/fragments/SelectListFragment.java | 163 -- .../dsub/fragments/SelectPlaylistFragment.java | 303 --- .../dsub/fragments/SelectPodcastsFragment.java | 308 --- .../dsub/fragments/SelectShareFragment.java | 216 -- .../dsub/fragments/SelectVideoFragment.java | 82 - .../dsub/fragments/SelectYearFragment.java | 78 - .../dsub/fragments/SettingsFragment.java | 724 ------ .../dsub/fragments/SimilarArtistFragment.java | 169 -- .../dsub/fragments/SubsonicFragment.java | 1817 --------------- .../daneren2005/dsub/fragments/UserFragment.java | 125 - .../dsub/provider/DLNARouteProvider.java | 425 ---- .../dsub/provider/DSubSearchProvider.java | 191 -- .../daneren2005/dsub/provider/DSubWidget4x1.java | 28 - .../daneren2005/dsub/provider/DSubWidget4x2.java | 28 - .../daneren2005/dsub/provider/DSubWidget4x3.java | 28 - .../daneren2005/dsub/provider/DSubWidget4x4.java | 28 - .../dsub/provider/DSubWidgetProvider.java | 304 --- .../dsub/provider/JukeboxRouteProvider.java | 131 -- .../dsub/provider/MostRecentStubProvider.java | 61 - .../dsub/provider/PlaylistStubProvider.java | 61 - .../dsub/provider/PodcastStubProvider.java | 61 - .../dsub/provider/StarredStubProvider.java | 61 - .../dsub/receiver/A2dpIntentReceiver.java | 47 - .../dsub/receiver/AudioNoisyReceiver.java | 51 - .../daneren2005/dsub/receiver/BootReceiver.java | 34 - .../dsub/receiver/HeadphonePlugReceiver.java | 42 - .../dsub/receiver/MediaButtonIntentReceiver.java | 57 - .../dsub/receiver/PlayActionReceiver.java | 46 - .../dsub/service/CachedMusicService.java | 1424 ------------ .../dsub/service/ChromeCastController.java | 522 ----- .../daneren2005/dsub/service/DLNAController.java | 687 ------ .../daneren2005/dsub/service/DownloadFile.java | 607 ----- .../daneren2005/dsub/service/DownloadService.java | 2410 -------------------- .../service/DownloadServiceLifecycleSupport.java | 445 ---- .../dsub/service/HeadphoneListenerService.java | 66 - .../dsub/service/JukeboxController.java | 307 --- .../dsub/service/MediaStoreService.java | 187 -- .../daneren2005/dsub/service/MusicService.java | 197 -- .../dsub/service/MusicServiceFactory.java | 36 - .../daneren2005/dsub/service/OfflineException.java | 32 - .../dsub/service/OfflineMusicService.java | 836 ------- .../daneren2005/dsub/service/RESTMusicService.java | 1991 ---------------- .../daneren2005/dsub/service/RemoteController.java | 116 - src/github/daneren2005/dsub/service/Scrobbler.java | 85 - .../dsub/service/ServerTooOldException.java | 60 - .../dsub/service/parser/AbstractParser.java | 150 -- .../dsub/service/parser/AlbumListParser.java | 61 - .../dsub/service/parser/ArtistInfoParser.java | 82 - .../dsub/service/parser/BookmarkParser.java | 100 - .../dsub/service/parser/ChatMessageParser.java | 65 - .../dsub/service/parser/ErrorParser.java | 49 - .../dsub/service/parser/GenreParser.java | 122 - .../dsub/service/parser/IndexesParser.java | 134 -- .../dsub/service/parser/JukeboxStatusParser.java | 62 - .../dsub/service/parser/LicenseParser.java | 62 - .../dsub/service/parser/LyricsParser.java | 64 - .../service/parser/MusicDirectoryEntryParser.java | 94 - .../dsub/service/parser/MusicDirectoryParser.java | 108 - .../dsub/service/parser/MusicFoldersParser.java | 65 - .../dsub/service/parser/PlayQueueParser.java | 85 - .../dsub/service/parser/PlaylistParser.java | 63 - .../dsub/service/parser/PlaylistsParser.java | 70 - .../dsub/service/parser/PodcastChannelParser.java | 66 - .../dsub/service/parser/PodcastEntryParser.java | 112 - .../dsub/service/parser/RandomSongsParser.java | 60 - .../dsub/service/parser/ScanStatusParser.java | 56 - .../dsub/service/parser/SearchResult2Parser.java | 75 - .../dsub/service/parser/SearchResultParser.java | 65 - .../dsub/service/parser/ShareParser.java | 126 - .../dsub/service/parser/StarredListParser.java | 69 - .../dsub/service/parser/SubsonicRESTException.java | 19 - .../dsub/service/parser/UserParser.java | 73 - .../dsub/service/parser/VideosParser.java | 53 - .../dsub/service/ssl/SSLSocketFactory.java | 549 ----- .../dsub/service/ssl/TrustManagerDecorator.java | 65 - .../dsub/service/ssl/TrustSelfSignedStrategy.java | 44 - .../dsub/service/ssl/TrustStrategy.java | 57 - .../dsub/service/sync/AuthenticatorService.java | 90 - .../dsub/service/sync/MostRecentSyncAdapter.java | 105 - .../dsub/service/sync/MostRecentSyncService.java | 48 - .../dsub/service/sync/PlaylistSyncAdapter.java | 153 -- .../dsub/service/sync/PlaylistSyncService.java | 48 - .../dsub/service/sync/PodcastSyncAdapter.java | 113 - .../dsub/service/sync/PodcastSyncService.java | 48 - .../dsub/service/sync/StarredSyncAdapter.java | 80 - .../dsub/service/sync/StarredSyncService.java | 48 - .../dsub/service/sync/SubsonicSyncAdapter.java | 174 -- src/github/daneren2005/dsub/updates/Updater.java | 98 - .../daneren2005/dsub/updates/Updater403.java | 58 - .../daneren2005/dsub/util/ArtistRadioBuffer.java | 148 -- .../daneren2005/dsub/util/BackgroundTask.java | 307 --- src/github/daneren2005/dsub/util/CacheCleaner.java | 292 --- src/github/daneren2005/dsub/util/Constants.java | 206 -- src/github/daneren2005/dsub/util/FileUtil.java | 860 ------- src/github/daneren2005/dsub/util/ImageLoader.java | 600 ----- src/github/daneren2005/dsub/util/LoadingTask.java | 73 - .../daneren2005/dsub/util/MediaRouteManager.java | 181 -- .../daneren2005/dsub/util/Notifications.java | 348 --- src/github/daneren2005/dsub/util/Pair.java | 54 - .../daneren2005/dsub/util/ProgressListener.java | 27 - .../daneren2005/dsub/util/SettingsBackupAgent.java | 31 - .../daneren2005/dsub/util/ShufflePlayBuffer.java | 212 -- .../dsub/util/SilentBackgroundTask.java | 48 - .../daneren2005/dsub/util/SimpleServiceBinder.java | 37 - src/github/daneren2005/dsub/util/SyncUtil.java | 222 -- .../daneren2005/dsub/util/TabBackgroundTask.java | 51 - .../daneren2005/dsub/util/TimeLimitedCache.java | 55 - src/github/daneren2005/dsub/util/UserUtil.java | 452 ---- src/github/daneren2005/dsub/util/Util.java | 1339 ----------- .../daneren2005/dsub/util/compat/CastCompat.java | 57 - .../dsub/util/compat/RemoteControlClientBase.java | 43 - .../util/compat/RemoteControlClientHelper.java | 32 - .../dsub/util/compat/RemoteControlClientICS.java | 104 - .../dsub/util/compat/RemoteControlClientJB.java | 58 - src/github/daneren2005/dsub/util/tags/Bastp.java | 85 - .../daneren2005/dsub/util/tags/BastpUtil.java | 73 - src/github/daneren2005/dsub/util/tags/Common.java | 111 - .../daneren2005/dsub/util/tags/FlacFile.java | 85 - .../daneren2005/dsub/util/tags/ID3v2File.java | 176 -- .../daneren2005/dsub/util/tags/LameHeader.java | 70 - src/github/daneren2005/dsub/util/tags/OggFile.java | 114 - src/github/daneren2005/dsub/view/AlbumCell.java | 108 - src/github/daneren2005/dsub/view/AlbumView.java | 107 - .../daneren2005/dsub/view/ArtistEntryView.java | 79 - src/github/daneren2005/dsub/view/ArtistView.java | 78 - .../daneren2005/dsub/view/AutoRepeatButton.java | 86 - src/github/daneren2005/dsub/view/ChangeLog.java | 546 ----- src/github/daneren2005/dsub/view/ErrorDialog.java | 75 - .../daneren2005/dsub/view/FadeOutAnimation.java | 77 - src/github/daneren2005/dsub/view/GenreView.java | 58 - .../daneren2005/dsub/view/HeaderGridView.java | 836 ------- .../dsub/view/MyLeadingMarginSpan2.java | 34 - .../daneren2005/dsub/view/MyViewFlipper.java | 53 - .../daneren2005/dsub/view/PlaylistSongView.java | 102 - src/github/daneren2005/dsub/view/PlaylistView.java | 69 - .../daneren2005/dsub/view/PodcastChannelView.java | 87 - .../daneren2005/dsub/view/RecyclingImageView.java | 91 - .../daneren2005/dsub/view/SeekBarPreference.java | 156 -- src/github/daneren2005/dsub/view/SettingView.java | 102 - src/github/daneren2005/dsub/view/ShareView.java | 65 - src/github/daneren2005/dsub/view/SongView.java | 318 --- .../daneren2005/dsub/view/SquareImageView.java | 32 - .../dsub/view/UnscrollableGridView.java | 128 -- src/github/daneren2005/dsub/view/UpdateView.java | 286 --- src/github/daneren2005/dsub/view/UserView.java | 54 - 208 files changed, 42560 deletions(-) delete mode 100644 src/github/daneren2005/dsub/activity/DownloadActivity.java delete mode 100644 src/github/daneren2005/dsub/activity/EditPlayActionActivity.java delete mode 100644 src/github/daneren2005/dsub/activity/QueryReceiverActivity.java delete mode 100644 src/github/daneren2005/dsub/activity/SettingsActivity.java delete mode 100644 src/github/daneren2005/dsub/activity/SubsonicActivity.java delete mode 100644 src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java delete mode 100644 src/github/daneren2005/dsub/activity/VoiceQueryReceiverActivity.java delete mode 100644 src/github/daneren2005/dsub/adapter/AlbumGridAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/AlbumListAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/ArtistAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/BookmarkAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/ChatAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/DownloadFileAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/DrawerAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/EntryAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/GenreAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/MergeAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/PlaylistAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/SackOfViewsAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/SettingsAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/ShareAdapter.java delete mode 100644 src/github/daneren2005/dsub/adapter/UserAdapter.java delete mode 100644 src/github/daneren2005/dsub/audiofx/AudioEffectsController.java delete mode 100644 src/github/daneren2005/dsub/audiofx/EqualizerController.java delete mode 100644 src/github/daneren2005/dsub/audiofx/LoudnessEnhancerController.java delete mode 100644 src/github/daneren2005/dsub/domain/Artist.java delete mode 100644 src/github/daneren2005/dsub/domain/ArtistInfo.java delete mode 100644 src/github/daneren2005/dsub/domain/Bookmark.java delete mode 100644 src/github/daneren2005/dsub/domain/ChatMessage.java delete mode 100644 src/github/daneren2005/dsub/domain/DLNADevice.java delete mode 100644 src/github/daneren2005/dsub/domain/Genre.java delete mode 100644 src/github/daneren2005/dsub/domain/Indexes.java delete mode 100644 src/github/daneren2005/dsub/domain/Lyrics.java delete mode 100644 src/github/daneren2005/dsub/domain/MusicDirectory.java delete mode 100644 src/github/daneren2005/dsub/domain/MusicFolder.java delete mode 100644 src/github/daneren2005/dsub/domain/PlayerQueue.java delete mode 100644 src/github/daneren2005/dsub/domain/PlayerState.java delete mode 100644 src/github/daneren2005/dsub/domain/Playlist.java delete mode 100644 src/github/daneren2005/dsub/domain/PodcastChannel.java delete mode 100644 src/github/daneren2005/dsub/domain/PodcastEpisode.java delete mode 100644 src/github/daneren2005/dsub/domain/RemoteControlState.java delete mode 100644 src/github/daneren2005/dsub/domain/RemoteStatus.java delete mode 100644 src/github/daneren2005/dsub/domain/RepeatMode.java delete mode 100644 src/github/daneren2005/dsub/domain/SearchCritera.java delete mode 100644 src/github/daneren2005/dsub/domain/SearchResult.java delete mode 100644 src/github/daneren2005/dsub/domain/ServerInfo.java delete mode 100644 src/github/daneren2005/dsub/domain/Share.java delete mode 100644 src/github/daneren2005/dsub/domain/User.java delete mode 100644 src/github/daneren2005/dsub/domain/Version.java delete mode 100644 src/github/daneren2005/dsub/fragments/AdminFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/ChatFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/DownloadFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/EqualizerFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/LyricsFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/MainFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/NowPlayingFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/PreferenceCompatFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SearchFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SelectArtistFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SelectGenreFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SelectListFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SelectShareFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SelectVideoFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SelectYearFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SettingsFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SimilarArtistFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/SubsonicFragment.java delete mode 100644 src/github/daneren2005/dsub/fragments/UserFragment.java delete mode 100644 src/github/daneren2005/dsub/provider/DLNARouteProvider.java delete mode 100644 src/github/daneren2005/dsub/provider/DSubSearchProvider.java delete mode 100644 src/github/daneren2005/dsub/provider/DSubWidget4x1.java delete mode 100644 src/github/daneren2005/dsub/provider/DSubWidget4x2.java delete mode 100644 src/github/daneren2005/dsub/provider/DSubWidget4x3.java delete mode 100644 src/github/daneren2005/dsub/provider/DSubWidget4x4.java delete mode 100644 src/github/daneren2005/dsub/provider/DSubWidgetProvider.java delete mode 100644 src/github/daneren2005/dsub/provider/JukeboxRouteProvider.java delete mode 100644 src/github/daneren2005/dsub/provider/MostRecentStubProvider.java delete mode 100644 src/github/daneren2005/dsub/provider/PlaylistStubProvider.java delete mode 100644 src/github/daneren2005/dsub/provider/PodcastStubProvider.java delete mode 100644 src/github/daneren2005/dsub/provider/StarredStubProvider.java delete mode 100644 src/github/daneren2005/dsub/receiver/A2dpIntentReceiver.java delete mode 100644 src/github/daneren2005/dsub/receiver/AudioNoisyReceiver.java delete mode 100644 src/github/daneren2005/dsub/receiver/BootReceiver.java delete mode 100644 src/github/daneren2005/dsub/receiver/HeadphonePlugReceiver.java delete mode 100644 src/github/daneren2005/dsub/receiver/MediaButtonIntentReceiver.java delete mode 100644 src/github/daneren2005/dsub/receiver/PlayActionReceiver.java delete mode 100644 src/github/daneren2005/dsub/service/CachedMusicService.java delete mode 100644 src/github/daneren2005/dsub/service/ChromeCastController.java delete mode 100644 src/github/daneren2005/dsub/service/DLNAController.java delete mode 100644 src/github/daneren2005/dsub/service/DownloadFile.java delete mode 100644 src/github/daneren2005/dsub/service/DownloadService.java delete mode 100644 src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java delete mode 100644 src/github/daneren2005/dsub/service/HeadphoneListenerService.java delete mode 100644 src/github/daneren2005/dsub/service/JukeboxController.java delete mode 100644 src/github/daneren2005/dsub/service/MediaStoreService.java delete mode 100644 src/github/daneren2005/dsub/service/MusicService.java delete mode 100644 src/github/daneren2005/dsub/service/MusicServiceFactory.java delete mode 100644 src/github/daneren2005/dsub/service/OfflineException.java delete mode 100644 src/github/daneren2005/dsub/service/OfflineMusicService.java delete mode 100644 src/github/daneren2005/dsub/service/RESTMusicService.java delete mode 100644 src/github/daneren2005/dsub/service/RemoteController.java delete mode 100644 src/github/daneren2005/dsub/service/Scrobbler.java delete mode 100644 src/github/daneren2005/dsub/service/ServerTooOldException.java delete mode 100644 src/github/daneren2005/dsub/service/parser/AbstractParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/AlbumListParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/ArtistInfoParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/BookmarkParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/ChatMessageParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/ErrorParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/GenreParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/IndexesParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/JukeboxStatusParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/LicenseParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/LyricsParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/MusicFoldersParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/PlayQueueParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/PlaylistParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/PlaylistsParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/RandomSongsParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/ScanStatusParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/SearchResult2Parser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/SearchResultParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/ShareParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/StarredListParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/SubsonicRESTException.java delete mode 100644 src/github/daneren2005/dsub/service/parser/UserParser.java delete mode 100644 src/github/daneren2005/dsub/service/parser/VideosParser.java delete mode 100644 src/github/daneren2005/dsub/service/ssl/SSLSocketFactory.java delete mode 100644 src/github/daneren2005/dsub/service/ssl/TrustManagerDecorator.java delete mode 100644 src/github/daneren2005/dsub/service/ssl/TrustSelfSignedStrategy.java delete mode 100644 src/github/daneren2005/dsub/service/ssl/TrustStrategy.java delete mode 100644 src/github/daneren2005/dsub/service/sync/AuthenticatorService.java delete mode 100644 src/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java delete mode 100644 src/github/daneren2005/dsub/service/sync/MostRecentSyncService.java delete mode 100644 src/github/daneren2005/dsub/service/sync/PlaylistSyncAdapter.java delete mode 100644 src/github/daneren2005/dsub/service/sync/PlaylistSyncService.java delete mode 100644 src/github/daneren2005/dsub/service/sync/PodcastSyncAdapter.java delete mode 100644 src/github/daneren2005/dsub/service/sync/PodcastSyncService.java delete mode 100644 src/github/daneren2005/dsub/service/sync/StarredSyncAdapter.java delete mode 100644 src/github/daneren2005/dsub/service/sync/StarredSyncService.java delete mode 100644 src/github/daneren2005/dsub/service/sync/SubsonicSyncAdapter.java delete mode 100644 src/github/daneren2005/dsub/updates/Updater.java delete mode 100644 src/github/daneren2005/dsub/updates/Updater403.java delete mode 100644 src/github/daneren2005/dsub/util/ArtistRadioBuffer.java delete mode 100644 src/github/daneren2005/dsub/util/BackgroundTask.java delete mode 100644 src/github/daneren2005/dsub/util/CacheCleaner.java delete mode 100644 src/github/daneren2005/dsub/util/Constants.java delete mode 100644 src/github/daneren2005/dsub/util/FileUtil.java delete mode 100644 src/github/daneren2005/dsub/util/ImageLoader.java delete mode 100644 src/github/daneren2005/dsub/util/LoadingTask.java delete mode 100644 src/github/daneren2005/dsub/util/MediaRouteManager.java delete mode 100644 src/github/daneren2005/dsub/util/Notifications.java delete mode 100644 src/github/daneren2005/dsub/util/Pair.java delete mode 100644 src/github/daneren2005/dsub/util/ProgressListener.java delete mode 100644 src/github/daneren2005/dsub/util/SettingsBackupAgent.java delete mode 100644 src/github/daneren2005/dsub/util/ShufflePlayBuffer.java delete mode 100644 src/github/daneren2005/dsub/util/SilentBackgroundTask.java delete mode 100644 src/github/daneren2005/dsub/util/SimpleServiceBinder.java delete mode 100644 src/github/daneren2005/dsub/util/SyncUtil.java delete mode 100644 src/github/daneren2005/dsub/util/TabBackgroundTask.java delete mode 100644 src/github/daneren2005/dsub/util/TimeLimitedCache.java delete mode 100644 src/github/daneren2005/dsub/util/UserUtil.java delete mode 100644 src/github/daneren2005/dsub/util/Util.java delete mode 100644 src/github/daneren2005/dsub/util/compat/CastCompat.java delete mode 100644 src/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java delete mode 100644 src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java delete mode 100644 src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java delete mode 100644 src/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java delete mode 100644 src/github/daneren2005/dsub/util/tags/Bastp.java delete mode 100644 src/github/daneren2005/dsub/util/tags/BastpUtil.java delete mode 100644 src/github/daneren2005/dsub/util/tags/Common.java delete mode 100644 src/github/daneren2005/dsub/util/tags/FlacFile.java delete mode 100644 src/github/daneren2005/dsub/util/tags/ID3v2File.java delete mode 100644 src/github/daneren2005/dsub/util/tags/LameHeader.java delete mode 100644 src/github/daneren2005/dsub/util/tags/OggFile.java delete mode 100644 src/github/daneren2005/dsub/view/AlbumCell.java delete mode 100644 src/github/daneren2005/dsub/view/AlbumView.java delete mode 100644 src/github/daneren2005/dsub/view/ArtistEntryView.java delete mode 100644 src/github/daneren2005/dsub/view/ArtistView.java delete mode 100644 src/github/daneren2005/dsub/view/AutoRepeatButton.java delete mode 100644 src/github/daneren2005/dsub/view/ChangeLog.java delete mode 100644 src/github/daneren2005/dsub/view/ErrorDialog.java delete mode 100644 src/github/daneren2005/dsub/view/FadeOutAnimation.java delete mode 100644 src/github/daneren2005/dsub/view/GenreView.java delete mode 100644 src/github/daneren2005/dsub/view/HeaderGridView.java delete mode 100644 src/github/daneren2005/dsub/view/MyLeadingMarginSpan2.java delete mode 100644 src/github/daneren2005/dsub/view/MyViewFlipper.java delete mode 100644 src/github/daneren2005/dsub/view/PlaylistSongView.java delete mode 100644 src/github/daneren2005/dsub/view/PlaylistView.java delete mode 100644 src/github/daneren2005/dsub/view/PodcastChannelView.java delete mode 100644 src/github/daneren2005/dsub/view/RecyclingImageView.java delete mode 100644 src/github/daneren2005/dsub/view/SeekBarPreference.java delete mode 100644 src/github/daneren2005/dsub/view/SettingView.java delete mode 100644 src/github/daneren2005/dsub/view/ShareView.java delete mode 100644 src/github/daneren2005/dsub/view/SongView.java delete mode 100644 src/github/daneren2005/dsub/view/SquareImageView.java delete mode 100644 src/github/daneren2005/dsub/view/UnscrollableGridView.java delete mode 100644 src/github/daneren2005/dsub/view/UpdateView.java delete mode 100644 src/github/daneren2005/dsub/view/UserView.java (limited to 'src') diff --git a/src/github/daneren2005/dsub/activity/DownloadActivity.java b/src/github/daneren2005/dsub/activity/DownloadActivity.java deleted file mode 100644 index e13a8b8c..00000000 --- a/src/github/daneren2005/dsub/activity/DownloadActivity.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.activity; - -import github.daneren2005.dsub.R; -import android.os.Bundle; -import android.view.MotionEvent; -import github.daneren2005.dsub.fragments.NowPlayingFragment; - -import android.widget.EditText; - -import github.daneren2005.dsub.util.Constants; - -public class DownloadActivity extends SubsonicActivity { - private static final String TAG = DownloadActivity.class.getSimpleName(); - private EditText playlistNameView; - - /** - * Called when the activity is first created. - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.download_activity); - - if (findViewById(R.id.fragment_container) != null && savedInstanceState == null) { - currentFragment = new NowPlayingFragment(); - if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) { - Bundle args = new Bundle(); - args.putBoolean(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW, true); - currentFragment.setArguments(args); - } - currentFragment.setPrimaryFragment(true); - getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "").commit(); - } - } - - @Override - public boolean onTouchEvent(MotionEvent me) { - if(currentFragment != null && currentFragment.getGestureDetector() != null) { - return currentFragment.getGestureDetector().onTouchEvent(me); - } else { - return false; - } - } -} diff --git a/src/github/daneren2005/dsub/activity/EditPlayActionActivity.java b/src/github/daneren2005/dsub/activity/EditPlayActionActivity.java deleted file mode 100644 index e1f2cad3..00000000 --- a/src/github/daneren2005/dsub/activity/EditPlayActionActivity.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.activity; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.widget.DrawerLayout; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.EditText; -import android.widget.Spinner; - -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.service.OfflineException; -import github.daneren2005.dsub.service.ServerTooOldException; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.LoadingTask; -import github.daneren2005.dsub.util.Util; - -public class EditPlayActionActivity extends SubsonicActivity { - private CheckBox shuffleCheckbox; - private CheckBox startYearCheckbox; - private EditText startYearBox; - private CheckBox endYearCheckbox; - private EditText endYearBox; - private Button genreButton; - private Spinner offlineSpinner; - - private String doNothing; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setTitle(R.string.tasker_start_playing_title); - setContentView(R.layout.edit_play_action); - final Activity context = this; - doNothing = context.getResources().getString(R.string.tasker_edit_do_nothing); - - shuffleCheckbox = (CheckBox) findViewById(R.id.edit_shuffle_checkbox); - shuffleCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton view, boolean isChecked) { - startYearCheckbox.setEnabled(isChecked); - endYearCheckbox.setEnabled(isChecked); - genreButton.setEnabled(isChecked); - } - }); - - startYearCheckbox = (CheckBox) findViewById(R.id.edit_start_year_checkbox); - startYearBox = (EditText) findViewById(R.id.edit_start_year); - // Disable/enable number box if checked - startYearCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton view, boolean isChecked) { - startYearBox.setEnabled(isChecked); - } - }); - - endYearCheckbox = (CheckBox) findViewById(R.id.edit_end_year_checkbox); - endYearBox = (EditText) findViewById(R.id.edit_end_year); - endYearCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton view, boolean isChecked) { - endYearBox.setEnabled(isChecked); - } - }); - - genreButton = (Button) findViewById(R.id.edit_genre_spinner); - genreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - new LoadingTask>(context, true) { - @Override - protected List doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - return musicService.getGenres(false, context, this); - } - - @Override - protected void done(final List genres) { - List names = new ArrayList(); - String blank = context.getResources().getString(R.string.select_genre_blank); - names.add(doNothing); - names.add(blank); - for(Genre genre: genres) { - names.add(genre.getName()); - } - final List finalNames = names; - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.shuffle_pick_genre) - .setItems(names.toArray(new CharSequence[names.size()]), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if(which == 1) { - genreButton.setText(""); - } else { - genreButton.setText(finalNames.get(which)); - } - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - }); - genreButton.setText(doNothing); - - offlineSpinner = (Spinner) findViewById(R.id.edit_offline_spinner); - ArrayAdapter offlineAdapter = ArrayAdapter.createFromResource(this, R.array.editServerOptions, android.R.layout.simple_spinner_item); - offlineAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - offlineSpinner.setAdapter(offlineAdapter); - - // Setup default for everything - Bundle extras = getIntent().getBundleExtra(Constants.TASKER_EXTRA_BUNDLE); - if(extras != null) { - if(extras.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE)) { - shuffleCheckbox.setChecked(true); - } - - String startYear = extras.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, null); - if(startYear != null) { - startYearCheckbox.setEnabled(true); - startYearBox.setText(startYear); - } - String endYear = extras.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, null); - if(endYear != null) { - endYearCheckbox.setEnabled(true); - endYearBox.setText(endYear); - } - - String genre = extras.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, doNothing); - if(genre != null) { - genreButton.setText(genre); - } - - int offline = extras.getInt(Constants.PREFERENCES_KEY_OFFLINE, 0); - if(offline != 0) { - offlineSpinner.setSelection(offline); - } - } - - drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater menuInflater = getMenuInflater(); - menuInflater.inflate(R.menu.tasker_configuration, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(item.getItemId() == android.R.id.home) { - cancel(); - return true; - } else if(item.getItemId() == R.id.menu_accept) { - accept(); - return true; - } else if(item.getItemId() == R.id.menu_cancel) { - cancel(); - return true; - } - - return false; - } - - private void accept() { - Intent intent = new Intent(); - - String blurb = getResources().getString(shuffleCheckbox.isChecked() ? R.string.tasker_start_playing_shuffled : R.string.tasker_start_playing); - intent.putExtra("com.twofortyfouram.locale.intent.extra.BLURB", blurb); - - // Get settings user specified - Bundle data = new Bundle(); - boolean shuffle = shuffleCheckbox.isChecked(); - data.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, shuffle); - if(shuffle) { - if(startYearCheckbox.isChecked()) { - data.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYearBox.getText().toString()); - } - if(endYearCheckbox.isChecked()) { - data.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYearBox.getText().toString()); - } - String genre = genreButton.getText().toString(); - if(!genre.equals(doNothing)) { - data.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre); - } - } - - int offline = offlineSpinner.getSelectedItemPosition(); - if(offline != 0) { - data.putInt(Constants.PREFERENCES_KEY_OFFLINE, offline); - } - - intent.putExtra(Constants.TASKER_EXTRA_BUNDLE, data); - - setResult(Activity.RESULT_OK, intent); - finish(); - } - private void cancel() { - setResult(Activity.RESULT_CANCELED); - finish(); - } -} diff --git a/src/github/daneren2005/dsub/activity/QueryReceiverActivity.java b/src/github/daneren2005/dsub/activity/QueryReceiverActivity.java deleted file mode 100644 index eefb9c56..00000000 --- a/src/github/daneren2005/dsub/activity/QueryReceiverActivity.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.activity; - -import android.app.Activity; -import android.app.SearchManager; -import android.content.Intent; -import android.os.Bundle; -import android.provider.SearchRecentSuggestions; -import android.util.Log; - -import github.daneren2005.dsub.fragments.SubsonicFragment; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.provider.DSubSearchProvider; - -/** - * Receives search queries and forwards to the SearchFragment. - * - * @author Sindre Mehus - */ -public class QueryReceiverActivity extends Activity { - - private static final String TAG = QueryReceiverActivity.class.getSimpleName(); - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Intent intent = getIntent(); - if (Intent.ACTION_SEARCH.equals(intent.getAction())) { - doSearch(); - } else if(Intent.ACTION_VIEW.equals(intent.getAction())) { - showResult(intent.getDataString(), intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); - } - finish(); - Util.disablePendingTransition(this); - } - - private void doSearch() { - String query = getIntent().getStringExtra(SearchManager.QUERY); - if (query != null) { - Intent intent = new Intent(QueryReceiverActivity.this, SubsonicFragmentActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query); - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); - Util.startActivityWithoutTransition(QueryReceiverActivity.this, intent); - } - } - private void showResult(String albumId, String name) { - if (albumId != null) { - Intent intent = new Intent(this, SubsonicFragmentActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.putExtra(Constants.INTENT_EXTRA_VIEW_ALBUM, true); - if(albumId.indexOf("ar-") == 0) { - intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, true); - albumId = albumId.replace("ar-", ""); - } else if(albumId.indexOf("so-") == 0) { - intent.putExtra(Constants.INTENT_EXTRA_SEARCH_SONG, name); - albumId = albumId.replace("so-", ""); - } - intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, albumId); - if (name != null) { - intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, name); - } - Util.startActivityWithoutTransition(this, intent); - } - } -} diff --git a/src/github/daneren2005/dsub/activity/SettingsActivity.java b/src/github/daneren2005/dsub/activity/SettingsActivity.java deleted file mode 100644 index d5ac60d3..00000000 --- a/src/github/daneren2005/dsub/activity/SettingsActivity.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.activity; - -import android.annotation.TargetApi; -import android.accounts.Account; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.EditTextPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceCategory; -import android.preference.PreferenceScreen; -import android.support.v7.app.ActionBarActivity; -import android.text.InputType; -import android.util.Log; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.EditText; -import android.widget.FrameLayout; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.fragments.PreferenceCompatFragment; -import github.daneren2005.dsub.fragments.SettingsFragment; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.LoadingTask; -import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.view.ErrorDialog; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Util; - -import java.io.File; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.net.URL; -import java.text.DecimalFormat; -import java.util.LinkedHashMap; -import java.util.Map; - -public class SettingsActivity extends SubsonicActivity { - private static final String TAG = SettingsActivity.class.getSimpleName(); - private PreferenceCompatFragment fragment; - - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.download_activity); - - if (savedInstanceState == null) { - fragment = new SettingsFragment(); - Bundle args = new Bundle(); - args.putInt(Constants.INTENT_EXTRA_FRAGMENT_TYPE, R.xml.settings); - - fragment.setArguments(args); - fragment.setRetainInstance(true); - - currentFragment = fragment; - currentFragment.setPrimaryFragment(true); - getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "").commit(); - } - } -} diff --git a/src/github/daneren2005/dsub/activity/SubsonicActivity.java b/src/github/daneren2005/dsub/activity/SubsonicActivity.java deleted file mode 100644 index 97b86e19..00000000 --- a/src/github/daneren2005/dsub/activity/SubsonicActivity.java +++ /dev/null @@ -1,860 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.activity; - -import android.app.UiModeManager; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.content.res.TypedArray; -import android.media.AudioManager; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; -import android.support.v7.app.ActionBarDrawerToggle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBarActivity; -import android.util.Log; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.view.animation.AnimationUtils; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemSelectedListener; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.Spinner; -import android.widget.TextView; - -import java.io.File; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.fragments.SubsonicFragment; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.HeadphoneListenerService; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.DrawerAdapter; -import github.daneren2005.dsub.view.UpdateView; -import github.daneren2005.dsub.util.UserUtil; - -public class SubsonicActivity extends ActionBarActivity implements OnItemSelectedListener { - private static final String TAG = SubsonicActivity.class.getSimpleName(); - private static ImageLoader IMAGE_LOADER; - protected static String theme; - protected static boolean fullScreen; - private String[] drawerItemsDescriptions; - private String[] drawerItems; - private boolean drawerIdle = true; - private boolean[] enabledItems = {true, true, true, true, true}; - private boolean destroyed = false; - private boolean finished = false; - protected List backStack = new ArrayList(); - protected SubsonicFragment currentFragment; - protected View primaryContainer; - protected View secondaryContainer; - protected boolean tv = false; - protected boolean touchscreen = true; - Spinner actionBarSpinner; - ArrayAdapter spinnerAdapter; - ViewGroup rootView; - DrawerLayout drawer; - ActionBarDrawerToggle drawerToggle; - DrawerAdapter drawerAdapter; - ListView drawerList; - TextView lastSelectedView = null; - int lastSelectedPosition = 0; - boolean drawerOpen = false; - - @Override - protected void onCreate(Bundle bundle) { - UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE); - if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) { - // tv = true; - } - PackageManager pm = getPackageManager(); - if(!pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) { - touchscreen = false; - } - - setUncaughtExceptionHandler(); - applyTheme(); - applyFullscreen(); - super.onCreate(bundle); - startService(new Intent(this, DownloadService.class)); - setVolumeControlStream(AudioManager.STREAM_MUSIC); - - View actionbar = getLayoutInflater().inflate(R.layout.actionbar_spinner, null); - actionBarSpinner = (Spinner)actionbar.findViewById(R.id.spinner); - spinnerAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item); - spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - actionBarSpinner.setOnItemSelectedListener(this); - actionBarSpinner.setAdapter(spinnerAdapter); - - getSupportActionBar().setCustomView(actionbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); - - if(getIntent().hasExtra(Constants.FRAGMENT_POSITION)) { - lastSelectedPosition = getIntent().getIntExtra(Constants.FRAGMENT_POSITION, 0); - } - } - - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - // Sync the toggle state after onRestoreInstanceState has occurred. - if(drawerToggle != null) { - drawerToggle.syncState(); - } - - if(Util.shouldStartOnHeadphones(this)) { - Intent serviceIntent = new Intent(); - serviceIntent.setClassName(this.getPackageName(), HeadphoneListenerService.class.getName()); - this.startService(serviceIntent); - } - } - - @Override - protected void onResume() { - super.onResume(); - Util.registerMediaButtonEventReceiver(this); - - // Make sure to update theme - if (theme != null && !theme.equals(Util.getTheme(this)) || fullScreen != Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_FULL_SCREEN, false)) { - restart(); - overridePendingTransition(R.anim.fade_in, R.anim.fade_out); - } - - populateDrawer(); - UpdateView.addActiveActivity(); - } - - @Override - protected void onPause() { - super.onPause(); - - UpdateView.removeActiveActivity(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - destroyed = true; - } - - @Override - public void finish() { - super.finish(); - Util.disablePendingTransition(this); - } - - @Override - public void startActivity(Intent intent) { - if(intent.getComponent() != null) { - String name = intent.getComponent().getClassName(); - if(name != null && name.indexOf("DownloadActivity") != -1) { - intent.putExtra(Constants.FRAGMENT_POSITION, lastSelectedPosition); - } else if(name != null && name.indexOf("SettingsActivity") != -1) { - intent.putExtra(Constants.FRAGMENT_POSITION, drawerItems.length - 1); - } - } - super.startActivity(intent); - } - - @Override - public void setContentView(int viewId) { - if(isTv()) { - super.setContentView(R.layout.static_drawer_activity); - } else { - super.setContentView(R.layout.abstract_activity); - } - rootView = (ViewGroup) findViewById(R.id.content_frame); - - if(viewId != 0) { - LayoutInflater layoutInflater = getLayoutInflater(); - layoutInflater.inflate(viewId, rootView); - } - - drawerList = (ListView) findViewById(R.id.left_drawer); - drawerList.setOnItemClickListener(new ListView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, final View view, final int position, long id) { - final int actualPosition = drawerAdapter.getActualPosition(position); - if("Settings".equals(drawerItemsDescriptions[actualPosition])) { - startActivity(new Intent(SubsonicActivity.this, SettingsActivity.class)); - drawer.closeDrawers(); - } else if("Admin".equals(drawerItemsDescriptions[actualPosition]) && UserUtil.isCurrentAdmin()) { - UserUtil.confirmCredentials(SubsonicActivity.this, new Runnable() { - @Override - public void run() { - drawerItemSelected(actualPosition, view); - } - }); - } else { - drawerItemSelected(actualPosition, view); - } - } - }); - - - - if(!isTv()) { - drawer = (DrawerLayout) findViewById(R.id.drawer_layout); - - drawerToggle = new ActionBarDrawerToggle(this, drawer, R.string.common_appname, R.string.common_appname) { - @Override - public void onDrawerClosed(View view) { - setTitle(currentFragment.getTitle()); - - drawerIdle = true; - drawerOpen = false; - - supportInvalidateOptionsMenu(); - } - - @Override - public void onDrawerOpened(View view) { - DownloadService downloadService = getDownloadService(); - if (downloadService == null || downloadService.getBackgroundDownloads().isEmpty()) { - drawerAdapter.setDownloadVisible(false); - } else { - drawerAdapter.setDownloadVisible(true); - } - - if (lastSelectedView == null && drawerList.getCount() > lastSelectedPosition) { - lastSelectedView = (TextView) drawerList.getChildAt(lastSelectedPosition).findViewById(R.id.drawer_name); - if (lastSelectedView != null) { - lastSelectedView.setTextAppearance(SubsonicActivity.this, R.style.DSub_TextViewStyle_Bold); - } - } - - getSupportActionBar().setTitle(R.string.common_appname); - getSupportActionBar().setDisplayShowCustomEnabled(false); - - drawerIdle = true; - drawerOpen = true; - - supportInvalidateOptionsMenu(); - } - - @Override - public void onDrawerSlide(View drawerView, float slideOffset) { - super.onDrawerSlide(drawerView, slideOffset); - drawerIdle = false; - } - }; - drawer.setDrawerListener(drawerToggle); - drawerToggle.setDrawerIndicatorEnabled(false); - - drawer.setOnTouchListener(new View.OnTouchListener() { - public boolean onTouch(View v, MotionEvent event) { - if (drawerIdle && currentFragment != null && currentFragment.getGestureDetector() != null) { - return currentFragment.getGestureDetector().onTouchEvent(event); - } else { - return false; - } - } - }); - } - - // Check whether this is a tablet or not - secondaryContainer = findViewById(R.id.fragment_second_container); - if(secondaryContainer != null) { - primaryContainer = findViewById(R.id.fragment_container); - } - } - - @Override - public void onSaveInstanceState(Bundle savedInstanceState) { - super.onSaveInstanceState(savedInstanceState); - String[] ids = new String[backStack.size() + 1]; - ids[0] = currentFragment.getTag(); - int i = 1; - for(SubsonicFragment frag: backStack) { - ids[i] = frag.getTag(); - i++; - } - savedInstanceState.putStringArray(Constants.MAIN_BACK_STACK, ids); - savedInstanceState.putInt(Constants.MAIN_BACK_STACK_SIZE, backStack.size() + 1); - savedInstanceState.putInt(Constants.FRAGMENT_POSITION, lastSelectedPosition); - } - @Override - public void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - int size = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_SIZE); - String[] ids = savedInstanceState.getStringArray(Constants.MAIN_BACK_STACK); - FragmentManager fm = getSupportFragmentManager(); - currentFragment = (SubsonicFragment)fm.findFragmentByTag(ids[0]); - currentFragment.setPrimaryFragment(true); - currentFragment.setSupportTag(ids[0]); - supportInvalidateOptionsMenu(); - FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); - for(int i = 1; i < size; i++) { - SubsonicFragment frag = (SubsonicFragment)fm.findFragmentByTag(ids[i]); - frag.setSupportTag(ids[i]); - if(secondaryContainer != null) { - frag.setPrimaryFragment(false, true); - } - trans.hide(frag); - backStack.add(frag); - } - trans.commit(); - - // Current fragment is hidden in secondaryContainer - if(secondaryContainer == null && !currentFragment.isVisible()) { - trans = getSupportFragmentManager().beginTransaction(); - trans.remove(currentFragment); - trans.commit(); - getSupportFragmentManager().executePendingTransactions(); - - trans = getSupportFragmentManager().beginTransaction(); - trans.add(R.id.fragment_container, currentFragment, ids[0]); - trans.commit(); - } - // Current fragment needs to be moved over to secondaryContainer - else if(secondaryContainer != null && secondaryContainer.findViewById(currentFragment.getRootId()) == null && backStack.size() > 0) { - trans = getSupportFragmentManager().beginTransaction(); - trans.remove(currentFragment); - trans.show(backStack.get(backStack.size() - 1)); - trans.commit(); - getSupportFragmentManager().executePendingTransactions(); - - trans = getSupportFragmentManager().beginTransaction(); - trans.add(R.id.fragment_second_container, currentFragment, ids[0]); - trans.commit(); - - secondaryContainer.setVisibility(View.VISIBLE); - } - - lastSelectedPosition = savedInstanceState.getInt(Constants.FRAGMENT_POSITION); - recreateSpinner(); - } - - @Override - public void onNewIntent(Intent intent) { - super.onNewIntent(intent); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater menuInflater = getMenuInflater(); - if(drawerOpen) { - menuInflater.inflate(R.menu.drawer_menu, menu); - } else if(currentFragment != null) { - try { - currentFragment.setContext(this); - currentFragment.onCreateOptionsMenu(menu, menuInflater); - - if(isTouchscreen()) { - menu.setGroupVisible(R.id.not_touchscreen, false); - } - } catch(Exception e) { - Log.w(TAG, "Error on creating options menu", e); - } - } - return true; - } - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(drawerToggle != null && drawerToggle.onOptionsItemSelected(item)) { - return true; - } else if(item.getItemId() == android.R.id.home) { - onBackPressed(); - return true; - } - - return currentFragment.onOptionsItemSelected(item); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - boolean isVolumeDown = keyCode == KeyEvent.KEYCODE_VOLUME_DOWN; - boolean isVolumeUp = keyCode == KeyEvent.KEYCODE_VOLUME_UP; - boolean isVolumeAdjust = isVolumeDown || isVolumeUp; - boolean isJukebox = getDownloadService() != null && getDownloadService().isRemoteEnabled(); - - if (isVolumeAdjust && isJukebox) { - getDownloadService().updateRemoteVolume(isVolumeUp); - return true; - } - return super.onKeyDown(keyCode, event); - } - - @Override - public void setTitle(CharSequence title) { - if(title != null && !title.equals(getSupportActionBar().getTitle())) { - getSupportActionBar().setTitle(title); - recreateSpinner(); - } - } - public void setSubtitle(CharSequence title) { - getSupportActionBar().setSubtitle(title); - } - - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - int top = spinnerAdapter.getCount() - 1; - if(position < top) { - for(int i = top; i > position; i--) { - removeCurrent(); - } - } - } - - @Override - public void onNothingSelected(AdapterView parent) { - - } - - private void populateDrawer() { - SharedPreferences prefs = Util.getPreferences(this); - boolean podcastsEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_PODCASTS_ENABLED, true); - boolean bookmarksEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_BOOKMARKS_ENABLED, true) && !Util.isOffline(this) && ServerInfo.canBookmark(this); - boolean sharedEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_SHARED_ENABLED, true) && !Util.isOffline(this); - boolean chatEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_CHAT_ENABLED, true) && !Util.isOffline(this); - boolean adminEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_ADMIN_ENABLED, true) && !Util.isOffline(this); - - if(drawerItems == null || !enabledItems[0] == podcastsEnabled || !enabledItems[1] == bookmarksEnabled || !enabledItems[2] == sharedEnabled || !enabledItems[3] == chatEnabled || !enabledItems[4] == adminEnabled) { - drawerItems = getResources().getStringArray(R.array.drawerItems); - drawerItemsDescriptions = getResources().getStringArray(R.array.drawerItemsDescriptions); - - List drawerItemsList = new ArrayList(Arrays.asList(drawerItems)); - List drawerItemsIconsList = new ArrayList(); - List drawerItemsVisibleList = new ArrayList(); - - int[] arrayAttr = {R.attr.drawerItemsIcons}; - TypedArray arrayType = obtainStyledAttributes(arrayAttr); - int arrayId = arrayType.getResourceId(0, 0); - TypedArray iconType = getResources().obtainTypedArray(arrayId); - for(int i = 0; i < drawerItemsList.size(); i++) { - drawerItemsIconsList.add(iconType.getResourceId(i, 0)); - drawerItemsVisibleList.add(true); - } - iconType.recycle(); - arrayType.recycle(); - - // Hide listings user doesn't want to see - if(!podcastsEnabled) { - drawerItemsVisibleList.set(3, false); - } - if(!bookmarksEnabled) { - drawerItemsVisibleList.set(4, false); - } - if(!sharedEnabled) { - drawerItemsVisibleList.set(5, false); - } - if(!chatEnabled) { - drawerItemsVisibleList.set(6, false); - } - if(!adminEnabled) { - drawerItemsVisibleList.set(7, false); - } - if(!getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) { - drawerItemsVisibleList.set(8, false); - } - - drawerList.setAdapter(drawerAdapter = new DrawerAdapter(this, drawerItemsList, drawerItemsIconsList, drawerItemsVisibleList)); - enabledItems[0] = podcastsEnabled; - enabledItems[1] = bookmarksEnabled; - enabledItems[2] = sharedEnabled; - enabledItems[3] = chatEnabled; - enabledItems[4] = adminEnabled; - - String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE); - if(fragmentType != null && lastSelectedPosition == 0) { - for(int i = 0; i < drawerItemsDescriptions.length; i++) { - if(fragmentType.equals(drawerItemsDescriptions[i])) { - lastSelectedPosition = drawerAdapter.getAdapterPosition(i); - break; - } - } - } - - if(drawerList.getChildAt(lastSelectedPosition) == null) { - lastSelectedView = null; - drawerAdapter.setSelectedPosition(lastSelectedPosition); - } else { - lastSelectedView = (TextView) drawerList.getChildAt(lastSelectedPosition).findViewById(R.id.drawer_name); - if(lastSelectedView != null) { - lastSelectedView.setTextAppearance(SubsonicActivity.this, R.style.DSub_TextViewStyle_Bold); - } - } - } - } - - private void drawerItemSelected(int position, View view) { - startFragmentActivity(drawerItemsDescriptions[position]); - - if(lastSelectedView != view) { - if(lastSelectedView != null) { - lastSelectedView.setTextAppearance(this, R.style.DSub_TextViewStyle); - } - - lastSelectedView = (TextView) view.findViewById(R.id.drawer_name); - lastSelectedView.setTextAppearance(this, R.style.DSub_TextViewStyle_Bold); - lastSelectedPosition = position; - } - } - - public void startFragmentActivity(String fragmentType) { - Intent intent = new Intent(); - intent.setClass(SubsonicActivity.this, SubsonicFragmentActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - if(!"".equals(fragmentType)) { - intent.putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, fragmentType); - } - startActivity(intent); - finish(); - } - - protected void exit() { - if(((Object) this).getClass() != SubsonicFragmentActivity.class) { - Intent intent = new Intent(this, SubsonicFragmentActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true); - Util.startActivityWithoutTransition(this, intent); - } else { - finished = true; - this.stopService(new Intent(this, DownloadService.class)); - this.finish(); - } - } - - public boolean onBackPressedSupport() { - if(drawerOpen) { - drawer.closeDrawers(); - return false; - } else if(backStack.size() > 0) { - removeCurrent(); - return false; - } else { - return true; - } - } - - @Override - public void onBackPressed() { - if(onBackPressedSupport()) { - super.onBackPressed(); - } - } - - public void replaceFragment(SubsonicFragment fragment, int tag) { - replaceFragment(fragment, tag, false); - } - public void replaceFragment(SubsonicFragment fragment, int tag, boolean replaceCurrent) { - SubsonicFragment oldFragment = currentFragment; - if(currentFragment != null) { - currentFragment.setPrimaryFragment(false, secondaryContainer != null); - } - backStack.add(currentFragment); - - currentFragment = fragment; - currentFragment.setPrimaryFragment(true); - supportInvalidateOptionsMenu(); - - if(secondaryContainer == null) { - FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); - trans.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right); - trans.hide(oldFragment); - trans.add(R.id.fragment_container, fragment, tag + ""); - trans.commit(); - } else { - // Make sure secondary container is visible now - secondaryContainer.setVisibility(View.VISIBLE); - - FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); - - // Check to see if you need to put on top of old left or not - if(backStack.size() > 1) { - // Move old right to left if there is a backstack already - SubsonicFragment newLeftFragment = backStack.get(backStack.size() - 1); - if(replaceCurrent) { - // trans.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right); - } - trans.remove(newLeftFragment); - - // Only move right to left if replaceCurrent is false - if(!replaceCurrent) { - SubsonicFragment oldLeftFragment = backStack.get(backStack.size() - 2); - oldLeftFragment.setSecondaryFragment(false); - // trans.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right); - trans.hide(oldLeftFragment); - - // Make sure remove is finished before adding - trans.commit(); - getSupportFragmentManager().executePendingTransactions(); - - trans = getSupportFragmentManager().beginTransaction(); - // trans.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right); - trans.add(R.id.fragment_container, newLeftFragment, newLeftFragment.getSupportTag() + ""); - } else { - backStack.remove(backStack.size() - 1); - } - } - - // Add fragment to the right container - trans.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right); - trans.add(R.id.fragment_second_container, fragment, tag + ""); - - // Commit it all - trans.commit(); - } - recreateSpinner(); - } - public void removeCurrent() { - if(currentFragment != null) { - currentFragment.setPrimaryFragment(false); - } - Fragment oldFrag = currentFragment; - - currentFragment = backStack.remove(backStack.size() - 1); - currentFragment.setPrimaryFragment(true, false); - supportInvalidateOptionsMenu(); - - if(secondaryContainer == null) { - FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); - trans.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left); - trans.remove(oldFrag); - trans.show(currentFragment); - trans.commit(); - } else { - FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); - - // Remove old right fragment - trans.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left); - trans.remove(oldFrag); - - // Only switch places if there is a backstack, otherwise primary container is correct - if(backStack.size() > 0) { - trans.setCustomAnimations(0, 0, 0, 0); - // Add current left fragment to right side - trans.remove(currentFragment); - - // Make sure remove is finished before adding - trans.commit(); - getSupportFragmentManager().executePendingTransactions(); - - trans = getSupportFragmentManager().beginTransaction(); - // trans.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left); - trans.add(R.id.fragment_second_container, currentFragment, currentFragment.getSupportTag() + ""); - - SubsonicFragment newLeftFragment = backStack.get(backStack.size() - 1); - newLeftFragment.setSecondaryFragment(true); - trans.show(newLeftFragment); - } else { - secondaryContainer.startAnimation(AnimationUtils.loadAnimation(this, R.anim.exit_to_right)); - secondaryContainer.setVisibility(View.GONE); - } - - trans.commit(); - } - recreateSpinner(); - } - - public void invalidate() { - if(currentFragment != null) { - while(backStack.size() > 0) { - removeCurrent(); - } - - currentFragment.invalidate(); - populateDrawer(); - } - - supportInvalidateOptionsMenu(); - } - - protected void recreateSpinner() { - if(currentFragment == null || currentFragment.getTitle() == null) { - return; - } - - if(backStack.size() > 0) { - spinnerAdapter.clear(); - for(int i = 0; i < backStack.size(); i++) { - CharSequence title = backStack.get(i).getTitle(); - if(title != null) { - spinnerAdapter.add(title); - } else { - spinnerAdapter.add("null"); - } - } - if(currentFragment.getTitle() != null) { - spinnerAdapter.add(currentFragment.getTitle()); - } else { - spinnerAdapter.add("null"); - } - spinnerAdapter.notifyDataSetChanged(); - actionBarSpinner.setSelection(spinnerAdapter.getCount() - 1); - if(!isTv()) { - getSupportActionBar().setDisplayShowCustomEnabled(true); - } - } else if(!isTv()) { - getSupportActionBar().setDisplayShowCustomEnabled(false); - } - } - - protected void restart() { - Intent intent = new Intent(this, ((Object) this).getClass()); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.putExtras(getIntent()); - Util.startActivityWithoutTransition(this, intent); - } - - private void applyTheme() { - theme = Util.getTheme(this); - - if(theme != null && theme.indexOf("fullscreen") != -1) { - theme = theme.substring(0, theme.indexOf("_fullscreen")); - Util.setTheme(this, theme); - } - - Util.applyTheme(this, theme); - } - private void applyFullscreen() { - fullScreen = Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_FULL_SCREEN, false); - if(fullScreen || isTv()) { - // Hide additional elements on higher Android versions - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_FULLSCREEN | - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - - getWindow().getDecorView().setSystemUiVisibility(flags); - } else if(Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - getWindow().requestFeature(Window.FEATURE_NO_TITLE); - } - getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - } - - public boolean isDestroyedCompat() { - return destroyed; - } - - public synchronized ImageLoader getImageLoader() { - if (IMAGE_LOADER == null) { - IMAGE_LOADER = new ImageLoader(this); - } - return IMAGE_LOADER; - } - public synchronized static ImageLoader getStaticImageLoader(Context context) { - if (IMAGE_LOADER == null) { - IMAGE_LOADER = new ImageLoader(context); - } - return IMAGE_LOADER; - } - - public DownloadService getDownloadService() { - if(finished) { - return null; - } - - // If service is not available, request it to start and wait for it. - for (int i = 0; i < 5; i++) { - DownloadService downloadService = DownloadService.getInstance(); - if (downloadService != null) { - return downloadService; - } - Log.w(TAG, "DownloadService not running. Attempting to start it."); - startService(new Intent(this, DownloadService.class)); - Util.sleepQuietly(50L); - } - return DownloadService.getInstance(); - } - - public static String getThemeName() { - return theme; - } - - public boolean isTv() { - return tv; - } - public boolean isTouchscreen() { - return touchscreen; - } - - private void setUncaughtExceptionHandler() { - Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler(); - if (!(handler instanceof SubsonicActivity.SubsonicUncaughtExceptionHandler)) { - Thread.setDefaultUncaughtExceptionHandler(new SubsonicActivity.SubsonicUncaughtExceptionHandler(this)); - } - } - - /** - * Logs the stack trace of uncaught exceptions to a file on the SD card. - */ - private static class SubsonicUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { - - private final Thread.UncaughtExceptionHandler defaultHandler; - private final Context context; - - private SubsonicUncaughtExceptionHandler(Context context) { - this.context = context; - defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); - } - - @Override - public void uncaughtException(Thread thread, Throwable throwable) { - File file = null; - PrintWriter printWriter = null; - try { - - PackageInfo packageInfo = context.getPackageManager().getPackageInfo("github.daneren2005.dsub", 0); - file = new File(Environment.getExternalStorageDirectory(), "dsub-stacktrace.txt"); - printWriter = new PrintWriter(file); - printWriter.println("Android API level: " + Build.VERSION.SDK); - printWriter.println("Subsonic version name: " + packageInfo.versionName); - printWriter.println("Subsonic version code: " + packageInfo.versionCode); - printWriter.println(); - throwable.printStackTrace(printWriter); - Log.i(TAG, "Stack trace written to " + file); - } catch (Throwable x) { - Log.e(TAG, "Failed to write stack trace to " + file, x); - } finally { - Util.close(printWriter); - if (defaultHandler != null) { - defaultHandler.uncaughtException(thread, throwable); - } - - } - } - } -} diff --git a/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java b/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java deleted file mode 100644 index ca0ac2f6..00000000 --- a/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java +++ /dev/null @@ -1,686 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.activity; - -import android.accounts.Account; -import android.accounts.AccountManager; -import android.app.Dialog; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.TypedArray; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.support.v4.app.FragmentTransaction; -import android.util.Log; -import android.view.MenuItem; -import android.view.View; -import android.widget.ImageButton; -import android.widget.TextView; - -import java.io.File; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerQueue; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.fragments.AdminFragment; -import github.daneren2005.dsub.fragments.ChatFragment; -import github.daneren2005.dsub.fragments.DownloadFragment; -import github.daneren2005.dsub.fragments.MainFragment; -import github.daneren2005.dsub.fragments.SearchFragment; -import github.daneren2005.dsub.fragments.SelectArtistFragment; -import github.daneren2005.dsub.fragments.SelectBookmarkFragment; -import github.daneren2005.dsub.fragments.SelectDirectoryFragment; -import github.daneren2005.dsub.fragments.SelectPlaylistFragment; -import github.daneren2005.dsub.fragments.SelectPodcastsFragment; -import github.daneren2005.dsub.fragments.SelectShareFragment; -import github.daneren2005.dsub.fragments.SubsonicFragment; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.updates.Updater; -import github.daneren2005.dsub.util.BackgroundTask; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.UserUtil; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.view.ChangeLog; - -/** - * Created by Scott on 10/14/13. - */ -public class SubsonicFragmentActivity extends SubsonicActivity { - private static String TAG = SubsonicFragmentActivity.class.getSimpleName(); - private static boolean infoDialogDisplayed; - private static boolean sessionInitialized = false; - private static long ALLOWED_SKEW = 30000L; - - private ScheduledExecutorService executorService; - private View bottomBar; - private View coverArtView; - private TextView trackView; - private TextView artistView; - private ImageButton startButton; - private long lastBackPressTime = 0; - private DownloadFile currentPlaying; - private PlayerState currentState; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) { - stopService(new Intent(this, DownloadService.class)); - finish(); - getImageLoader().clearCache(); - } else if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) { - getIntent().putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, "Download"); - if(drawerAdapter != null) { - drawerAdapter.setDownloadVisible(true); - } - } else if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD)) { - DownloadService service = getDownloadService(); - if((service != null && service.getCurrentPlaying() != null)) { - getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD); - Intent intent = new Intent(); - intent.setClass(this, DownloadActivity.class); - startActivity(intent); - } - } - setContentView(R.layout.abstract_fragment_activity); - - UserUtil.seedCurrentUser(this); - if (findViewById(R.id.fragment_container) != null && savedInstanceState == null) { - String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE); - boolean firstRun = false; - if(fragmentType == null) { - fragmentType = Util.openToTab(this); - if(fragmentType != null) { - getIntent().putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, fragmentType); - firstRun = true; - } - } - currentFragment = getNewFragment(fragmentType); - - if("".equals(fragmentType) || fragmentType == null || firstRun) { - // Initial startup stuff - if(!sessionInitialized) { - loadSession(); - } - } - - currentFragment.setPrimaryFragment(true); - getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "").commit(); - - if(getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY) != null) { - SearchFragment fragment = new SearchFragment(); - replaceFragment(fragment, fragment.getSupportTag()); - } - - // If a album type is set, switch to that album type view - String albumType = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE); - if(albumType != null) { - SubsonicFragment fragment = new SelectDirectoryFragment(); - - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, albumType); - args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); - args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); - - fragment.setArguments(args); - replaceFragment(fragment, fragment.getSupportTag()); - } - } - - bottomBar = findViewById(R.id.bottom_bar); - bottomBar.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - Intent intent = new Intent(); - intent.setClass(v.getContext(), DownloadActivity.class); - startActivity(intent); - } - }); - coverArtView = bottomBar.findViewById(R.id.album_art); - trackView = (TextView) bottomBar.findViewById(R.id.track_name); - artistView = (TextView) bottomBar.findViewById(R.id.artist_name); - - ImageButton previousButton = (ImageButton) findViewById(R.id.download_previous); - previousButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new SilentBackgroundTask(SubsonicFragmentActivity.this) { - @Override - protected Void doInBackground() throws Throwable { - if(getDownloadService() == null) { - return null; - } - - getDownloadService().previous(); - return null; - } - - @Override - protected void done(Void result) { - update(); - } - }.execute(); - } - }); - - startButton = (ImageButton) findViewById(R.id.download_start); - startButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new SilentBackgroundTask(SubsonicFragmentActivity.this) { - @Override - protected Void doInBackground() throws Throwable { - PlayerState state = getDownloadService().getPlayerState(); - if(state == PlayerState.STARTED) { - getDownloadService().pause(); - } else { - getDownloadService().start(); - } - - return null; - } - - @Override - protected void done(Void result) { - update(); - } - }.execute(); - } - }); - - ImageButton nextButton = (ImageButton) findViewById(R.id.download_next); - nextButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new SilentBackgroundTask(SubsonicFragmentActivity.this) { - @Override - protected Void doInBackground() throws Throwable { - if(getDownloadService() == null) { - return null; - } - - getDownloadService().next(); - return null; - } - - @Override - protected void done(Void result) { - update(); - } - }.execute(); - } - }); - } - - @Override - protected void onPostCreate(Bundle bundle) { - super.onPostCreate(bundle); - - showInfoDialog(); - checkUpdates(); - - ChangeLog changeLog = new ChangeLog(this, Util.getPreferences(this)); - if(changeLog.isFirstRun()) { - if(changeLog.isFirstRunEver()) { - changeLog.updateVersionInPreferences(); - } else { - Dialog log = changeLog.getLogDialog(); - if (log != null) { - log.show(); - } - } - } - } - - @Override - public void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - if(currentFragment != null && intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY) != null) { - if(currentFragment instanceof SearchFragment) { - String query = intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY); - boolean autoplay = intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false); - boolean requestsearch = intent.getBooleanExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, false); - - if (query != null) { - ((SearchFragment)currentFragment).search(query, autoplay); - } else { - ((SearchFragment)currentFragment).populateList(); - if (requestsearch) { - onSearchRequested(); - } - } - getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_QUERY); - } else { - setIntent(intent); - - SearchFragment fragment = new SearchFragment(); - replaceFragment(fragment, fragment.getSupportTag()); - } - } else { - setIntent(intent); - } - if(drawer != null) { - drawer.closeDrawers(); - } - } - - @Override - public void onResume() { - super.onResume(); - - final Handler handler = new Handler(); - Runnable runnable = new Runnable() { - @Override - public void run() { - handler.post(new Runnable() { - @Override - public void run() { - update(); - } - }); - } - }; - - if(getIntent().hasExtra(Constants.INTENT_EXTRA_VIEW_ALBUM)) { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID)); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_NAME)); - args.putString(Constants.INTENT_EXTRA_SEARCH_SONG, getIntent().getStringExtra(Constants.INTENT_EXTRA_SEARCH_SONG)); - if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_ARTIST)) { - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - } - if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_CHILD_ID)) { - args.putString(Constants.INTENT_EXTRA_NAME_CHILD_ID, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_CHILD_ID)); - } - fragment.setArguments(args); - - replaceFragment(fragment, fragment.getSupportTag()); - getIntent().removeExtra(Constants.INTENT_EXTRA_VIEW_ALBUM); - if("Artist".equals(getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE))) { - lastSelectedPosition = 1; - } - } - - createAccount(); - - executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS); - } - - @Override - public void onPause() { - super.onPause(); - executorService.shutdown(); - } - - @Override - public void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - if(drawerToggle != null && backStack.size() > 0) { - drawerToggle.setDrawerIndicatorEnabled(false); - } - } - - @Override - public void setContentView(int viewId) { - super.setContentView(viewId); - if(drawerToggle != null){ - drawerToggle.setDrawerIndicatorEnabled(true); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - return super.onOptionsItemSelected(item); - } - - @Override - public void onBackPressed() { - if(onBackPressedSupport()) { - if(!Util.disableExitPrompt(this) && lastBackPressTime < (System.currentTimeMillis() - 4000)) { - lastBackPressTime = System.currentTimeMillis(); - Util.toast(this, R.string.main_back_confirm); - } else { - finish(); - } - } - } - - @Override - public void replaceFragment(SubsonicFragment fragment, int tag, boolean replaceCurrent) { - super.replaceFragment(fragment, tag, replaceCurrent); - if(drawerToggle != null) { - drawerToggle.setDrawerIndicatorEnabled(false); - } - } - @Override - public void removeCurrent() { - super.removeCurrent(); - if(drawerToggle != null && backStack.isEmpty()) { - drawerToggle.setDrawerIndicatorEnabled(true); - } - } - - @Override - public void startFragmentActivity(String fragmentType) { - // Create a transaction that does all of this - FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); - - // Clear existing stack - for(int i = backStack.size() - 1; i >= 0; i--) { - trans.remove(backStack.get(i)); - } - trans.remove(currentFragment); - backStack.clear(); - - // Create new stack - currentFragment = getNewFragment(fragmentType); - currentFragment.setPrimaryFragment(true); - trans.add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + ""); - - // Done, cleanup - trans.commit(); - supportInvalidateOptionsMenu(); - recreateSpinner(); - if(drawer != null) { - drawer.closeDrawers(); - } - - if(secondaryContainer != null) { - secondaryContainer.setVisibility(View.GONE); - } - if(drawerToggle != null) { - drawerToggle.setDrawerIndicatorEnabled(true); - } - } - - private SubsonicFragment getNewFragment(String fragmentType) { - if("Artist".equals(fragmentType)) { - return new SelectArtistFragment(); - } else if("Playlist".equals(fragmentType)) { - return new SelectPlaylistFragment(); - } else if("Chat".equals(fragmentType)) { - return new ChatFragment(); - } else if("Podcast".equals(fragmentType)) { - return new SelectPodcastsFragment(); - } else if("Bookmark".equals(fragmentType)) { - return new SelectBookmarkFragment(); - } else if("Share".equals(fragmentType)) { - return new SelectShareFragment(); - } else if("Admin".equals(fragmentType)) { - return new AdminFragment(); - } else if("Download".equals(fragmentType)) { - return new DownloadFragment(); - } else { - return new MainFragment(); - } - } - - private void update() { - DownloadService downloadService = getDownloadService(); - if (downloadService == null) { - return; - } - - DownloadFile current = downloadService.getCurrentPlaying(); - PlayerState state = downloadService.getPlayerState(); - if(current == currentPlaying && state == currentState) { - return; - } else { - currentPlaying = current; - currentState = state; - } - - MusicDirectory.Entry song = null; - if(current != null) { - song = current.getSong(); - trackView.setText(song.getTitle()); - artistView.setText(song.getArtist()); - } else { - trackView.setText("Title"); - artistView.setText("Artist"); - } - - getImageLoader().loadImage(coverArtView, song, false, false); - int[] attrs = new int[] {(state == PlayerState.STARTED) ? R.attr.media_button_pause : R.attr.media_button_start}; - TypedArray typedArray = this.obtainStyledAttributes(attrs); - startButton.setImageResource(typedArray.getResourceId(0, 0)); - typedArray.recycle(); - } - - public void checkUpdates() { - try { - String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; - int ver = Integer.parseInt(version.replace(".", "")); - Updater updater = new Updater(ver); - updater.checkUpdates(this); - } - catch(Exception e) { - - } - } - - private void loadSession() { - loadSettings(); - if(!Util.isOffline(this) && ServerInfo.canBookmark(this)) { - loadBookmarks(); - } - // If we are on Subsonic 5.2+, save play queue - if(ServerInfo.canSavePlayQueue(this) && !Util.isOffline(this)) { - loadRemotePlayQueue(); - } - - sessionInitialized = true; - } - private void loadSettings() { - PreferenceManager.setDefaultValues(this, R.xml.settings, false); - SharedPreferences prefs = Util.getPreferences(this); - if (!prefs.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION) || prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null) == null) { - resetCacheLocation(prefs); - } else { - String path = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - File cacheLocation = new File(path); - if(!FileUtil.verifyCanWrite(cacheLocation)) { - // Only warn user if there is a difference saved - if(resetCacheLocation(prefs)) { - Util.info(this, R.string.common_warning, R.string.settings_cache_location_reset); - } - } - } - - if (!prefs.contains(Constants.PREFERENCES_KEY_OFFLINE)) { - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(Constants.PREFERENCES_KEY_OFFLINE, false); - - editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + 1, "Demo Server"); - editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + 1, "http://demo.subsonic.org"); - editor.putString(Constants.PREFERENCES_KEY_USERNAME + 1, "android-guest"); - editor.putString(Constants.PREFERENCES_KEY_PASSWORD + 1, "guest"); - editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); - editor.commit(); - } - if(!prefs.contains(Constants.PREFERENCES_KEY_SERVER_COUNT)) { - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 1); - editor.commit(); - } - } - - private boolean resetCacheLocation(SharedPreferences prefs) { - String newDirectory = FileUtil.getDefaultMusicDirectory(this).getPath(); - String oldDirectory = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - if(newDirectory == null || (oldDirectory != null && newDirectory.equals(oldDirectory))) { - return false; - } else { - SharedPreferences.Editor editor = prefs.edit(); - editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, newDirectory); - editor.commit(); - return true; - } - } - - private void loadBookmarks() { - final Context context = this; - new SilentBackgroundTask(context) { - @Override - public Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.getBookmarks(true, context, null); - - return null; - } - - @Override - public void error(Throwable error) { - Log.e(TAG, "Failed to get bookmarks", error); - } - }.execute(); - } - private void loadRemotePlayQueue() { - final SubsonicActivity context = this; - new SilentBackgroundTask(this) { - private PlayerQueue playerQueue; - - @Override - protected Void doInBackground() throws Throwable { - try { - MusicService musicService = MusicServiceFactory.getMusicService(context); - PlayerQueue remoteState = musicService.getPlayQueue(context, null); - - // Make sure we wait until download service is ready - DownloadService downloadService = getDownloadService(); - while(downloadService == null || !downloadService.isInitialized()) { - Util.sleepQuietly(100L); - downloadService = getDownloadService(); - } - - // If we had a remote state and it's changed is more recent than our existing state - if(remoteState != null && remoteState.changed != null) { - // Check if changed + 30 seconds since some servers have slight skew - Date remoteChange = new Date(remoteState.changed.getTime() - ALLOWED_SKEW); - Date localChange = downloadService.getLastStateChanged(); - if(localChange == null || localChange.before(remoteChange)) { - playerQueue = remoteState; - } - } - } catch (Exception e) { - Log.e(TAG, "Failed to get playing queue to server", e); - } - - return null; - } - - @Override - protected void done(Void arg) { - if(!context.isDestroyedCompat() && playerQueue != null) { - promptRestoreFromRemoteQueue(playerQueue); - } - } - }.execute(); - } - private void promptRestoreFromRemoteQueue(final PlayerQueue remoteState) { - Util.confirmDialog(this, R.string.download_restore_play_queue, Util.formatDate(remoteState.changed), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new SilentBackgroundTask(SubsonicFragmentActivity.this) { - @Override - protected Void doInBackground() throws Throwable { - DownloadService downloadService = getDownloadService(); - downloadService.clear(); - downloadService.download(remoteState.songs, false, false, false, false, remoteState.currentPlayingIndex, remoteState.currentPlayingPosition); - return null; - } - }.execute(); - } - }, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new SilentBackgroundTask(SubsonicFragmentActivity.this) { - @Override - protected Void doInBackground() throws Throwable { - DownloadService downloadService = getDownloadService(); - downloadService.serializeQueue(false); - return null; - } - }.execute(); - } - }); - } - - private void createAccount() { - final Context context = this; - - new SilentBackgroundTask(this) { - @Override - protected Void doInBackground() throws Throwable { - AccountManager accountManager = (AccountManager) context.getSystemService(ACCOUNT_SERVICE); - Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE); - accountManager.addAccountExplicitly(account, null, null); - - SharedPreferences prefs = Util.getPreferences(context); - boolean syncEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_SYNC_ENABLED, true); - int syncInterval = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_SYNC_INTERVAL, "60")); - - // Add enabled/frequency to playlist/podcasts syncing - ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, syncEnabled); - ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, new Bundle(), 60L * syncInterval); - ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PODCAST_AUTHORITY, syncEnabled); - ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PODCAST_AUTHORITY, new Bundle(), 60L * syncInterval); - - // Add for starred/recently added - ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_STARRED_AUTHORITY, (syncEnabled && prefs.getBoolean(Constants.PREFERENCES_KEY_SYNC_STARRED, false))); - ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_STARRED_AUTHORITY, new Bundle(), 60L * syncInterval); - ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_MOST_RECENT_AUTHORITY, (syncEnabled && prefs.getBoolean(Constants.PREFERENCES_KEY_SYNC_MOST_RECENT, false))); - ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_MOST_RECENT_AUTHORITY, new Bundle(), 60L * syncInterval); - return null; - } - - @Override - protected void done(Void result) { - - } - }.execute(); - } - - private void showInfoDialog() { - if (!infoDialogDisplayed) { - infoDialogDisplayed = true; - if (Util.getRestUrl(this, null).contains("demo.subsonic.org")) { - Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text); - } - } - } -} diff --git a/src/github/daneren2005/dsub/activity/VoiceQueryReceiverActivity.java b/src/github/daneren2005/dsub/activity/VoiceQueryReceiverActivity.java deleted file mode 100644 index 7ae0ba77..00000000 --- a/src/github/daneren2005/dsub/activity/VoiceQueryReceiverActivity.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.activity; - -import android.app.Activity; -import android.app.SearchManager; -import android.content.Intent; -import android.os.Bundle; -import android.provider.SearchRecentSuggestions; - -import github.daneren2005.dsub.fragments.SubsonicFragment; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.provider.DSubSearchProvider; - -/** - * Receives voice search queries and forwards to the SearchFragment. - * - * http://android-developers.blogspot.com/2010/09/supporting-new-music-voice-action.html - * - * @author Sindre Mehus - */ -public class VoiceQueryReceiverActivity extends Activity { - private static String GMS_SEARCH_ACTION = "com.google.android.gms.actions.SEARCH_ACTION"; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - String query = getIntent().getStringExtra(SearchManager.QUERY); - - if (query != null) { - Intent intent = new Intent(VoiceQueryReceiverActivity.this, SubsonicFragmentActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query); - if(!GMS_SEARCH_ACTION.equals(getIntent().getAction())) { - intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); - } - intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); - Util.startActivityWithoutTransition(VoiceQueryReceiverActivity.this, intent); - } - finish(); - Util.disablePendingTransition(this); - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/adapter/AlbumGridAdapter.java b/src/github/daneren2005/dsub/adapter/AlbumGridAdapter.java deleted file mode 100644 index eb187569..00000000 --- a/src/github/daneren2005/dsub/adapter/AlbumGridAdapter.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; - -import java.util.List; - -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.view.AlbumCell; - -public class AlbumGridAdapter extends ArrayAdapter { - private final static String TAG = AlbumGridAdapter.class.getSimpleName(); - private final Context activity; - private final ImageLoader imageLoader; - private List entries; - private boolean showArtist; - - public AlbumGridAdapter(Context activity, ImageLoader imageLoader, List entries, boolean showArtist) { - super(activity, android.R.layout.simple_list_item_1, entries); - this.entries = entries; - this.activity = activity; - this.imageLoader = imageLoader; - - // Always show artist if they aren't all the same - if(!showArtist) { - String artist = null; - for(MusicDirectory.Entry entry: entries) { - if(artist == null) { - artist = entry.getArtist(); - } - - if(artist != null && !artist.equals(entry.getArtist())) { - showArtist = true; - } - } - } - this.showArtist = showArtist; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - MusicDirectory.Entry entry = getItem(position); - - AlbumCell view; - if(convertView instanceof AlbumCell) { - view = (AlbumCell) convertView; - } else { - view = new AlbumCell(activity); - } - - view.setShowArtist(showArtist); - view.setObject(entry, imageLoader); - return view; - } -} diff --git a/src/github/daneren2005/dsub/adapter/AlbumListAdapter.java b/src/github/daneren2005/dsub/adapter/AlbumListAdapter.java deleted file mode 100644 index b2fcded3..00000000 --- a/src/github/daneren2005/dsub/adapter/AlbumListAdapter.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.SectionIndexer; - -import com.commonsware.cwac.endless.EndlessAdapter; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -public class AlbumListAdapter extends EndlessAdapter implements SectionIndexer { - Context context; - ArrayAdapter adapter; - String type; - String extra; - int size; - int offset; - List entries; - - private boolean shouldIndex = false; - private Object[] sections; - private Integer[] positions; - - public AlbumListAdapter(Context context, ArrayAdapter adapter, String type, String extra, int size) { - super(adapter); - this.context = context; - this.adapter = adapter; - this.type = type; - this.extra = extra; - this.size = size; - this.offset = size; - - if("alphabeticalByName".equals(this.type)) { - shouldIndex = true; - recreateIndexes(); - } - } - - @Override - protected boolean cacheInBackground() throws Exception { - MusicService service = MusicServiceFactory.getMusicService(context); - MusicDirectory result; - if(("genres".equals(type) && ServerInfo.checkServerVersion(context, "1.10.0")) || "years".equals(type)) { - result = service.getAlbumList(type, extra, size, offset, context, null); - } else if("genres".equals(type) || "genres-songs".equals(type)) { - result = service.getSongsByGenre(extra, size, offset, context, null); - } else { - result = service.getAlbumList(type, size, offset, context, null); - } - entries = result.getChildren(); - return entries.size() > 0; - } - - @Override - protected void appendCachedData() { - for(MusicDirectory.Entry entry: entries) { - adapter.add(entry); - } - offset += entries.size(); - recreateIndexes(); - } - - @Override - protected View getPendingView(ViewGroup parent) { - View progress = LayoutInflater.from(context).inflate(R.layout.tab_progress, null); - progress.setVisibility(View.VISIBLE); - return progress; - } - - private void recreateIndexes() { - if(!shouldIndex) { - return; - } - - Set sectionSet = new LinkedHashSet(30); - List positionList = new ArrayList(30); - for (int i = 0; i < adapter.getCount(); i++) { - MusicDirectory.Entry entry = adapter.getItem(i); - String index = entry.getAlbum().substring(0, 1); - if(!Character.isLetter(index.charAt(0))) { - index = "#"; - } - - if (!sectionSet.contains(index)) { - sectionSet.add(index); - positionList.add(i); - } - } - sections = sectionSet.toArray(new Object[sectionSet.size()]); - positions = positionList.toArray(new Integer[positionList.size()]); - } - - @Override - public Object[] getSections() { - if(sections != null) { - return sections; - } else { - return new Object[0]; - } - } - - @Override - public int getPositionForSection(int section) { - if(sections != null) { - section = Math.min(section, positions.length - 1); - return positions[section]; - } else { - return 0; - } - } - - @Override - public int getSectionForPosition(int pos) { - if(sections != null) { - for (int i = 0; i < sections.length - 1; i++) { - if (pos < positions[i + 1]) { - return i; - } - } - return sections.length - 1; - } else { - return 0; - } - } -} diff --git a/src/github/daneren2005/dsub/adapter/ArtistAdapter.java b/src/github/daneren2005/dsub/adapter/ArtistAdapter.java deleted file mode 100644 index 4d469faf..00000000 --- a/src/github/daneren2005/dsub/adapter/ArtistAdapter.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import github.daneren2005.dsub.R; -import java.util.List; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.SectionIndexer; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.view.ArtistView; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.Set; - -/** - * @author Sindre Mehus - */ -public class ArtistAdapter extends ArrayAdapter implements SectionIndexer { - - private final Context activity; - - // Both arrays are indexed by section ID. - private final Object[] sections; - private final Integer[] positions; - - public ArtistAdapter(Context activity, List artists) { - super(activity, R.layout.basic_list_item, artists); - this.activity = activity; - - Set sectionSet = new LinkedHashSet(30); - List positionList = new ArrayList(30); - for (int i = 0; i < artists.size(); i++) { - Artist artist = artists.get(i); - String index = artist.getIndex(); - if (!sectionSet.contains(index)) { - sectionSet.add(index); - positionList.add(i); - } - } - sections = sectionSet.toArray(new Object[sectionSet.size()]); - positions = positionList.toArray(new Integer[positionList.size()]); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Artist entry = getItem(position); - ArtistView view; - if (convertView != null && convertView instanceof ArtistView) { - view = (ArtistView) convertView; - } else { - view = new ArtistView(activity); - } - view.setObject(entry); - return view; - } - - @Override - public Object[] getSections() { - return sections; - } - - @Override - public int getPositionForSection(int section) { - section = Math.min(section, positions.length - 1); - return positions[section]; - } - - @Override - public int getSectionForPosition(int pos) { - for (int i = 0; i < sections.length - 1; i++) { - if (pos < positions[i + 1]) { - return i; - } - } - return sections.length - 1; - } -} diff --git a/src/github/daneren2005/dsub/adapter/BookmarkAdapter.java b/src/github/daneren2005/dsub/adapter/BookmarkAdapter.java deleted file mode 100644 index 26d3e16a..00000000 --- a/src/github/daneren2005/dsub/adapter/BookmarkAdapter.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus -*/ - -package github.daneren2005.dsub.adapter; - -import android.content.Context; - -import java.util.List; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.TextView; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Bookmark; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.view.SongView; - -public class BookmarkAdapter extends ArrayAdapter { - private final static String TAG = BookmarkAdapter.class.getSimpleName(); - private Context activity; - - public BookmarkAdapter(Context activity, List bookmarks) { - super(activity, android.R.layout.simple_list_item_1, bookmarks); - this.activity = activity; - } - - public View getView(int position, View convertView, ViewGroup parent) { - MusicDirectory.Entry entry = getItem(position); - Bookmark bookmark = entry.getBookmark(); - - SongView view; - if (convertView != null) { - view = (SongView) convertView; - } else { - view = new SongView(activity); - } - view.setObject(entry, false); - - // Add current position to duration - TextView durationTextView = (TextView) view.findViewById(R.id.song_duration); - String duration = durationTextView.getText().toString(); - durationTextView.setText(Util.formatDuration(bookmark.getPosition() / 1000) + " / " + duration); - - return view; - } -} diff --git a/src/github/daneren2005/dsub/adapter/ChatAdapter.java b/src/github/daneren2005/dsub/adapter/ChatAdapter.java deleted file mode 100644 index 0c116d39..00000000 --- a/src/github/daneren2005/dsub/adapter/ChatAdapter.java +++ /dev/null @@ -1,109 +0,0 @@ -package github.daneren2005.dsub.adapter; - -import android.text.method.LinkMovementMethod; -import android.text.util.Linkify; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ImageView; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.SubsonicActivity; -import github.daneren2005.dsub.domain.ChatMessage; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.util.UserUtil; -import github.daneren2005.dsub.util.Util; - -import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.regex.Pattern; - -public class ChatAdapter extends ArrayAdapter { - - private final SubsonicActivity activity; - private ArrayList messages; - private final ImageLoader imageLoader; - - private static final String phoneRegex = "1?\\W*([2-9][0-8][0-9])\\W*([2-9][0-9]{2})\\W*([0-9]{4})"; //you can just place your support phone here - private static final Pattern phoneMatcher = Pattern.compile(phoneRegex); - - public ChatAdapter(SubsonicActivity activity, ArrayList messages, ImageLoader imageLoader) { - super(activity, R.layout.chat_item, messages); - this.activity = activity; - this.messages = messages; - this.imageLoader = imageLoader; - } - - @Override - public int getCount() { - return messages.size(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - ChatMessage message = this.getItem(position); - - ViewHolder holder; - int layout; - - String messageUser = message.getUsername(); - Date messageTime = new java.util.Date(message.getTime()); - String messageText = message.getMessage(); - - String me = UserUtil.getCurrentUsername(activity); - - if (messageUser.equals(me)) { - layout = R.layout.chat_item_reverse; - } else { - layout = R.layout.chat_item; - } - - if (convertView == null) - { - holder = new ViewHolder(); - - convertView = LayoutInflater.from(activity).inflate(layout, parent, false); - - TextView usernameView = (TextView) convertView.findViewById(R.id.chat_username); - TextView timeView = (TextView) convertView.findViewById(R.id.chat_time); - TextView messageView = (TextView) convertView.findViewById(R.id.chat_message); - - messageView.setMovementMethod(LinkMovementMethod.getInstance()); - Linkify.addLinks(messageView, Linkify.EMAIL_ADDRESSES); - Linkify.addLinks(messageView, Linkify.WEB_URLS); - Linkify.addLinks(messageView, phoneMatcher, "tel:"); - - holder.message = messageView; - holder.username = usernameView; - holder.time = timeView; - holder.avatar = (ImageView) convertView.findViewById(R.id.chat_avatar); - - convertView.setTag(holder); - } - else - { - holder = (ViewHolder) convertView.getTag(); - } - - DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(activity); - String messageTimeFormatted = String.format("[%s]", timeFormat.format(messageTime)); - - holder.username.setText(messageUser); - holder.message.setText(messageText); - holder.time.setText(messageTimeFormatted); - - imageLoader.loadAvatar(activity, holder.avatar, messageUser); - - return convertView; - } - - private static class ViewHolder - { - TextView message; - TextView username; - TextView time; - ImageView avatar; - } -} diff --git a/src/github/daneren2005/dsub/adapter/DownloadFileAdapter.java b/src/github/daneren2005/dsub/adapter/DownloadFileAdapter.java deleted file mode 100644 index be9b4cb9..00000000 --- a/src/github/daneren2005/dsub/adapter/DownloadFileAdapter.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; - -import java.util.List; - -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.view.SongView; - -public class DownloadFileAdapter extends ArrayAdapter { - Context context; - - public DownloadFileAdapter(Context context, List entries) { - super(context, android.R.layout.simple_list_item_1, entries); - this.context = context; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - SongView view; - if (convertView != null && convertView instanceof SongView) { - view = (SongView) convertView; - } else { - view = new SongView(context); - } - DownloadFile downloadFile = getItem(position); - view.setObject(downloadFile.getSong(), false); - view.setDownloadFile(downloadFile); - return view; - } -} diff --git a/src/github/daneren2005/dsub/adapter/DrawerAdapter.java b/src/github/daneren2005/dsub/adapter/DrawerAdapter.java deleted file mode 100644 index b0a4a33d..00000000 --- a/src/github/daneren2005/dsub/adapter/DrawerAdapter.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus -*/ -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ImageView; -import android.widget.TextView; - -import java.util.List; - -import github.daneren2005.dsub.R; - -/** - * Created by Scott on 11/8/13. - */ -public class DrawerAdapter extends ArrayAdapter { - private static String TAG = DrawerAdapter.class.getSimpleName(); - private Context context; - private List items; - private List icons; - private List visible; - private int selectedPosition = -1; - - public DrawerAdapter(Context context, List items, List icons, List visible) { - super(context, R.layout.drawer_list_item, items); - - this.context = context; - this.items = items; - this.icons = icons; - this.visible = visible; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - position = getActualPosition(position); - String item = items.get(position); - Integer icon = icons.get(position); - - if(convertView == null) { - convertView = LayoutInflater.from(context).inflate(R.layout.drawer_list_item, null); - } - - TextView textView = (TextView) convertView.findViewById(R.id.drawer_name); - textView.setText(item); - - if(selectedPosition == position) { - textView.setTextAppearance(context, R.style.DSub_TextViewStyle_Bold); - selectedPosition = -1; - } - - ImageView iconView = (ImageView) convertView.findViewById(R.id.drawer_icon); - iconView.setImageResource(icon); - - return convertView; - } - - @Override - public int getCount() { - int count = 0; - for(int i = 0; i < visible.size(); i++) { - if(visible.get(i)) { - count++; - } - } - - return count; - } - - public int getActualPosition(int position) { - for(int i = 0; i <= position; i++) { - if(!visible.get(i)) { - position++; - } - } - - return position; - } - public int getAdapterPosition(int position) { - if(!visible.get(position)) { - visible.set(position, true); - notifyDataSetChanged(); - } - - for(int i = position; i >= 0; i--) { - if(!visible.get(i)) { - position--; - } - } - - return position; - } - - public void setItemVisible(int position, boolean visible) { - if(this.visible.get(position) != visible) { - this.visible.set(position, visible); - notifyDataSetInvalidated(); - } - } - public void setDownloadVisible(boolean visible) { - setItemVisible(items.size() - 2, visible); - } - - public void setSelectedPosition(int position) { - selectedPosition = position; - } -} diff --git a/src/github/daneren2005/dsub/adapter/EntryAdapter.java b/src/github/daneren2005/dsub/adapter/EntryAdapter.java deleted file mode 100644 index 9e506e5a..00000000 --- a/src/github/daneren2005/dsub/adapter/EntryAdapter.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.adapter; - -import android.content.Context; - -import java.util.List; - -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.view.AlbumView; -import github.daneren2005.dsub.view.ArtistEntryView; -import github.daneren2005.dsub.view.SongView; - -/** - * @author Sindre Mehus - */ -public class EntryAdapter extends ArrayAdapter { - private final static String TAG = EntryAdapter.class.getSimpleName(); - private final Context activity; - private final ImageLoader imageLoader; - private final boolean checkable; - private List entries; - - public EntryAdapter(Context activity, ImageLoader imageLoader, List entries, boolean checkable) { - super(activity, android.R.layout.simple_list_item_1, entries); - this.entries = entries; - this.activity = activity; - this.imageLoader = imageLoader; - this.checkable = checkable; - } - - public void removeAt(int position) { - entries.remove(position); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - MusicDirectory.Entry entry = getItem(position); - - if (entry.isDirectory()) { - if(entry.isAlbum()) { - AlbumView view; - view = new AlbumView(activity); - view.setObject(entry, imageLoader); - return view; - } else { - ArtistEntryView view = new ArtistEntryView(activity); - view.setObject(entry); - return view; - } - } else { - SongView view; - if (convertView != null && convertView instanceof SongView) { - view = (SongView) convertView; - } else { - view = new SongView(activity); - } - view.setObject(entry, checkable); - return view; - } - } -} diff --git a/src/github/daneren2005/dsub/adapter/GenreAdapter.java b/src/github/daneren2005/dsub/adapter/GenreAdapter.java deleted file mode 100644 index abb208c9..00000000 --- a/src/github/daneren2005/dsub/adapter/GenreAdapter.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.adapter; - -import android.widget.ArrayAdapter; -import android.widget.SectionIndexer; -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.view.GenreView; - -import java.util.List; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; - -/** - * @author Sindre Mehus -*/ -public class GenreAdapter extends ArrayAdapter{ - private Context activity; - private List genres; - - public GenreAdapter(Context context, List genres) { - super(context, android.R.layout.simple_list_item_1, genres); - this.activity = context; - this.genres = genres; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Genre genre = genres.get(position); - GenreView view; - if (convertView != null && convertView instanceof GenreView) { - view = (GenreView) convertView; - } else { - view = new GenreView(activity); - } - view.setObject(genre); - return view; - } -} diff --git a/src/github/daneren2005/dsub/adapter/MergeAdapter.java b/src/github/daneren2005/dsub/adapter/MergeAdapter.java deleted file mode 100644 index a2db4cf0..00000000 --- a/src/github/daneren2005/dsub/adapter/MergeAdapter.java +++ /dev/null @@ -1,290 +0,0 @@ -/*** - Copyright (c) 2008-2009 CommonsWare, LLC - Portions (c) 2009 Google, Inc. - - 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. - */ - -package github.daneren2005.dsub.adapter; - -import android.database.DataSetObserver; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ListAdapter; - -import java.util.ArrayList; -import java.util.List; -import java.util.Arrays; - -/** - * Adapter that merges multiple child adapters and views - * into a single contiguous whole. - *

- * Adapters used as pieces within MergeAdapter must - * have view type IDs monotonically increasing from 0. Ideally, - * adapters also have distinct ranges for their row ids, as - * returned by getItemId(). - */ -public class MergeAdapter extends BaseAdapter { - - private final CascadeDataSetObserver observer = new CascadeDataSetObserver(); - private final ArrayList pieces = new ArrayList(); - - /** - * Stock constructor, simply chaining to the superclass. - */ - public MergeAdapter() { - super(); - } - - /** - * Adds a new adapter to the roster of things to appear - * in the aggregate list. - * - * @param adapter Source for row views for this section - */ - public void addAdapter(ListAdapter adapter) { - pieces.add(adapter); - adapter.registerDataSetObserver(observer); - } - - public void removeAdapter(ListAdapter adapter) { - adapter.unregisterDataSetObserver(observer); - pieces.remove(adapter); - } - - /** - * Adds a new View to the roster of things to appear - * in the aggregate list. - * - * @param view Single view to add - */ - public ListAdapter addView(View view) { - return addView(view, false); - } - - /** - * Adds a new View to the roster of things to appear - * in the aggregate list. - * - * @param view Single view to add - * @param enabled false if views are disabled, true if enabled - */ - public ListAdapter addView(View view, boolean enabled) { - return addViews(Arrays.asList(view), enabled); - } - - /** - * Adds a list of views to the roster of things to appear - * in the aggregate list. - * - * @param views List of views to add - */ - public ListAdapter addViews(List views) { - return addViews(views, false); - } - - /** - * Adds a list of views to the roster of things to appear - * in the aggregate list. - * - * @param views List of views to add - * @param enabled false if views are disabled, true if enabled - */ - public ListAdapter addViews(List views, boolean enabled) { - ListAdapter adapter = enabled ? new EnabledSackAdapter(views) : new SackOfViewsAdapter(views); - addAdapter(adapter); - return adapter; - } - - /** - * Get the data item associated with the specified - * position in the data set. - * - * @param position Position of the item whose data we want - */ - @Override - public Object getItem(int position) { - for (ListAdapter piece : pieces) { - int size = piece.getCount(); - - if (position < size) { - return (piece.getItem(position)); - } - - position -= size; - } - - return (null); - } - - /** - * How many items are in the data set represented by this - * Adapter. - */ - @Override - public int getCount() { - int total = 0; - - for (ListAdapter piece : pieces) { - total += piece.getCount(); - } - - return (total); - } - - /** - * Returns the number of types of Views that will be - * created by getView(). - */ - @Override - public int getViewTypeCount() { - int total = 0; - - for (ListAdapter piece : pieces) { - total += piece.getViewTypeCount(); - } - - return (Math.max(total, 1)); // needed for setListAdapter() before content add' - } - - /** - * Get the type of View that will be created by getView() - * for the specified item. - * - * @param position Position of the item whose data we want - */ - @Override - public int getItemViewType(int position) { - int typeOffset = 0; - int result = -1; - - for (ListAdapter piece : pieces) { - int size = piece.getCount(); - - if (position < size) { - result = typeOffset + piece.getItemViewType(position); - break; - } - - position -= size; - typeOffset += piece.getViewTypeCount(); - } - - return (result); - } - - /** - * Are all items in this ListAdapter enabled? If yes it - * means all items are selectable and clickable. - */ - @Override - public boolean areAllItemsEnabled() { - return (false); - } - - /** - * Returns true if the item at the specified position is - * not a separator. - * - * @param position Position of the item whose data we want - */ - @Override - public boolean isEnabled(int position) { - for (ListAdapter piece : pieces) { - int size = piece.getCount(); - - if (position < size) { - return (piece.isEnabled(position)); - } - - position -= size; - } - - return (false); - } - - /** - * Get a View that displays the data at the specified - * position in the data set. - * - * @param position Position of the item whose data we want - * @param convertView View to recycle, if not null - * @param parent ViewGroup containing the returned View - */ - @Override - public View getView(int position, View convertView, - ViewGroup parent) { - for (ListAdapter piece : pieces) { - int size = piece.getCount(); - - if (position < size) { - - return (piece.getView(position, convertView, parent)); - } - - position -= size; - } - - return (null); - } - - /** - * Get the row id associated with the specified position - * in the list. - * - * @param position Position of the item whose data we want - */ - @Override - public long getItemId(int position) { - for (ListAdapter piece : pieces) { - int size = piece.getCount(); - - if (position < size) { - return (piece.getItemId(position)); - } - - position -= size; - } - - return (-1); - } - - private static class EnabledSackAdapter extends SackOfViewsAdapter { - public EnabledSackAdapter(List views) { - super(views); - } - - @Override - public boolean areAllItemsEnabled() { - return (true); - } - - @Override - public boolean isEnabled(int position) { - return (true); - } - } - - private class CascadeDataSetObserver extends DataSetObserver { - @Override - public void onChanged() { - notifyDataSetChanged(); - } - - @Override - public void onInvalidated() { - notifyDataSetInvalidated(); - } - } -} - diff --git a/src/github/daneren2005/dsub/adapter/PlaylistAdapter.java b/src/github/daneren2005/dsub/adapter/PlaylistAdapter.java deleted file mode 100644 index d56a6b97..00000000 --- a/src/github/daneren2005/dsub/adapter/PlaylistAdapter.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import github.daneren2005.dsub.R; -import java.util.List; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.view.PlaylistView; - -import java.util.Collections; -import java.util.Comparator; - -/** - * @author Sindre Mehus - */ -public class PlaylistAdapter extends ArrayAdapter { - - private final Context activity; - - public PlaylistAdapter(Context activity, List Playlists) { - super(activity, R.layout.basic_list_item, Playlists); - this.activity = activity; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Playlist entry = getItem(position); - PlaylistView view; - if (convertView != null && convertView instanceof PlaylistView) { - view = (PlaylistView) convertView; - } else { - view = new PlaylistView(activity); - } - view.setObject(entry); - return view; - } - - public static class PlaylistComparator implements Comparator { - @Override - public int compare(Playlist playlist1, Playlist playlist2) { - return playlist1.getName().compareToIgnoreCase(playlist2.getName()); - } - - public static List sort(List playlists) { - Collections.sort(playlists, new PlaylistComparator()); - return playlists; - } - - } -} diff --git a/src/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java b/src/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java deleted file mode 100644 index 8ee39a10..00000000 --- a/src/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.adapter; - -import android.widget.ArrayAdapter; -import android.widget.SectionIndexer; -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.view.PodcastChannelView; - -import java.util.List; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; - -/** - * @author Sindre Mehus -*/ -public class PodcastChannelAdapter extends ArrayAdapter{ - private Context activity; - private List podcasts; - - public PodcastChannelAdapter(Context context, List podcasts) { - super(context, android.R.layout.simple_list_item_1, podcasts); - this.activity = context; - this.podcasts = podcasts; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - PodcastChannel podcast = podcasts.get(position); - PodcastChannelView view; - if (convertView != null && convertView instanceof PodcastChannelView) { - view = (PodcastChannelView) convertView; - } else { - view = new PodcastChannelView(activity); - } - view.setObject(podcast); - return view; - } -} diff --git a/src/github/daneren2005/dsub/adapter/SackOfViewsAdapter.java b/src/github/daneren2005/dsub/adapter/SackOfViewsAdapter.java deleted file mode 100644 index e4744cc5..00000000 --- a/src/github/daneren2005/dsub/adapter/SackOfViewsAdapter.java +++ /dev/null @@ -1,181 +0,0 @@ -/*** - Copyright (c) 2008-2009 CommonsWare, LLC - Portions (c) 2009 Google, Inc. - - 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. - */ -package github.daneren2005.dsub.adapter; - -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ListView; - -import java.util.ArrayList; -import java.util.List; - -/** - * Adapter that simply returns row views from a list. - *

- * If you supply a size, you must implement newView(), to - * create a required view. The adapter will then cache these - * views. - *

- * If you supply a list of views in the constructor, that - * list will be used directly. If any elements in the list - * are null, then newView() will be called just for those - * slots. - *

- * Subclasses may also wish to override areAllItemsEnabled() - * (default: false) and isEnabled() (default: false), if some - * of their rows should be selectable. - *

- * It is assumed each view is unique, and therefore will not - * get recycled. - *

- * Note that this adapter is not designed for long lists. It - * is more for screens that should behave like a list. This - * is particularly useful if you combine this with other - * adapters (e.g., SectionedAdapter) that might have an - * arbitrary number of rows, so it all appears seamless. - */ -public class SackOfViewsAdapter extends BaseAdapter { - private List views = null; - - /** - * Constructor creating an empty list of views, but with - * a specified count. Subclasses must override newView(). - */ - public SackOfViewsAdapter(int count) { - super(); - - views = new ArrayList(count); - - for (int i = 0; i < count; i++) { - views.add(null); - } - } - - /** - * Constructor wrapping a supplied list of views. - * Subclasses must override newView() if any of the elements - * in the list are null. - */ - public SackOfViewsAdapter(List views) { - for (View view : views) { - view.setLayoutParams(new ListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - } - this.views = views; - } - - /** - * Get the data item associated with the specified - * position in the data set. - * - * @param position Position of the item whose data we want - */ - @Override - public Object getItem(int position) { - return (views.get(position)); - } - - /** - * How many items are in the data set represented by this - * Adapter. - */ - @Override - public int getCount() { - return (views.size()); - } - - /** - * Returns the number of types of Views that will be - * created by getView(). - */ - @Override - public int getViewTypeCount() { - return (getCount()); - } - - /** - * Get the type of View that will be created by getView() - * for the specified item. - * - * @param position Position of the item whose data we want - */ - @Override - public int getItemViewType(int position) { - return (position); - } - - /** - * Are all items in this ListAdapter enabled? If yes it - * means all items are selectable and clickable. - */ - @Override - public boolean areAllItemsEnabled() { - return (false); - } - - /** - * Returns true if the item at the specified position is - * not a separator. - * - * @param position Position of the item whose data we want - */ - @Override - public boolean isEnabled(int position) { - return (false); - } - - /** - * Get a View that displays the data at the specified - * position in the data set. - * - * @param position Position of the item whose data we want - * @param convertView View to recycle, if not null - * @param parent ViewGroup containing the returned View - */ - @Override - public View getView(int position, View convertView, - ViewGroup parent) { - View result = views.get(position); - - if (result == null) { - result = newView(position, parent); - views.set(position, result); - } - - return (result); - } - - /** - * Get the row id associated with the specified position - * in the list. - * - * @param position Position of the item whose data we want - */ - @Override - public long getItemId(int position) { - return (position); - } - - /** - * Create a new View to go into the list at the specified - * position. - * - * @param position Position of the item whose data we want - * @param parent ViewGroup containing the returned View - */ - protected View newView(int position, ViewGroup parent) { - throw new RuntimeException("You must override newView()!"); - } -} diff --git a/src/github/daneren2005/dsub/adapter/SettingsAdapter.java b/src/github/daneren2005/dsub/adapter/SettingsAdapter.java deleted file mode 100644 index 45c3ead1..00000000 --- a/src/github/daneren2005/dsub/adapter/SettingsAdapter.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; - -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.User; -import github.daneren2005.dsub.view.SettingView; - -import static github.daneren2005.dsub.domain.User.Setting; - -public class SettingsAdapter extends ArrayAdapter { - private final Context context; - private final boolean editable; - - public SettingsAdapter(Context context, User user, boolean editable) { - super(context, R.layout.basic_list_item, user.getSettings()); - this.context = context; - this.editable = editable; - } - - public SettingsAdapter(Context context, List settings, boolean editable) { - super(context, R.layout.basic_list_item, settings); - this.context = context; - this.editable = editable; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Setting entry = getItem(position); - SettingView view; - if (convertView != null && convertView instanceof SettingView) { - view = (SettingView) convertView; - } else { - view = new SettingView(context); - } - view.setObject(entry, editable); - return view; - } -} diff --git a/src/github/daneren2005/dsub/adapter/ShareAdapter.java b/src/github/daneren2005/dsub/adapter/ShareAdapter.java deleted file mode 100644 index 4121a85a..00000000 --- a/src/github/daneren2005/dsub/adapter/ShareAdapter.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; - -import java.util.List; - -import github.daneren2005.dsub.domain.Share; -import github.daneren2005.dsub.view.ShareView; - -/** - * @author Sindre Mehus -*/ -public class ShareAdapter extends ArrayAdapter{ - private Context activity; - private List shares; - - public ShareAdapter(Context context, List shares) { - super(context, android.R.layout.simple_list_item_1, shares); - this.activity = context; - this.shares = shares; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Share share = shares.get(position); - ShareView view; - if (convertView != null && convertView instanceof ShareView) { - view = (ShareView) convertView; - } else { - view = new ShareView(activity); - } - view.setObject(share); - return view; - } -} diff --git a/src/github/daneren2005/dsub/adapter/UserAdapter.java b/src/github/daneren2005/dsub/adapter/UserAdapter.java deleted file mode 100644 index f0f78d97..00000000 --- a/src/github/daneren2005/dsub/adapter/UserAdapter.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; - -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.User; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.view.UserView; - -public class UserAdapter extends ArrayAdapter { - private final Context activity; - private final ImageLoader imageLoader; - - public UserAdapter(Context activity, List users, ImageLoader imageLoader) { - super(activity, R.layout.basic_list_item, users); - this.activity = activity; - this.imageLoader = imageLoader; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - User entry = getItem(position); - UserView view; - if (convertView != null && convertView instanceof UserView) { - view = (UserView) convertView; - } else { - view = new UserView(activity); - } - view.setObject(entry, imageLoader); - return view; - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/audiofx/AudioEffectsController.java b/src/github/daneren2005/dsub/audiofx/AudioEffectsController.java deleted file mode 100644 index 1933bd64..00000000 --- a/src/github/daneren2005/dsub/audiofx/AudioEffectsController.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2014 (C) Scott Jackson -*/ -package github.daneren2005.dsub.audiofx; - -import android.content.Context; -import android.media.MediaPlayer; -import android.media.audiofx.AudioEffect; -import android.media.audiofx.LoudnessEnhancer; -import android.os.Build; -import android.util.Log; - -public class AudioEffectsController { - private static final String TAG = AudioEffectsController.class.getSimpleName(); - - private final Context context; - private int audioSessionId = 0; - - private boolean available = false; - - private EqualizerController equalizerController; - - public AudioEffectsController(Context context, int audioSessionId) { - this.context = context; - this.audioSessionId = audioSessionId; - - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { - available = true; - } - } - - public boolean isAvailable() { - return available; - } - - public void release() { - if(equalizerController != null) { - equalizerController.release(); - } - } - - public EqualizerController getEqualizerController() { - if (available && equalizerController == null) { - equalizerController = new EqualizerController(context, audioSessionId); - if (!equalizerController.isAvailable()) { - equalizerController = null; - } else { - equalizerController.loadSettings(); - } - } - return equalizerController; - } -} - diff --git a/src/github/daneren2005/dsub/audiofx/EqualizerController.java b/src/github/daneren2005/dsub/audiofx/EqualizerController.java deleted file mode 100644 index f170af0b..00000000 --- a/src/github/daneren2005/dsub/audiofx/EqualizerController.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2011 (C) Sindre Mehus - */ -package github.daneren2005.dsub.audiofx; - -import java.io.Serializable; - -import android.content.Context; -import android.media.audiofx.BassBoost; -import android.media.audiofx.Equalizer; -import android.os.Build; -import android.util.Log; -import github.daneren2005.dsub.util.FileUtil; - -/** - * Backward-compatible wrapper for {@link Equalizer}, which is API Level 9. - * - * @author Sindre Mehus - * @version $Id$ - */ -public class EqualizerController { - - private static final String TAG = EqualizerController.class.getSimpleName(); - - private final Context context; - private Equalizer equalizer; - private BassBoost bass; - private boolean loudnessAvailable = false; - private LoudnessEnhancerController loudnessEnhancerController; - private boolean released = false; - private int audioSessionId = 0; - - public EqualizerController(Context context, int audioSessionId) { - this.context = context; - this.audioSessionId = audioSessionId; - init(); - } - - private void init() { - equalizer = new Equalizer(0, audioSessionId); - bass = new BassBoost(0, audioSessionId); - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - loudnessAvailable = true; - loudnessEnhancerController = new LoudnessEnhancerController(context, audioSessionId); - } - } - - public void saveSettings() { - try { - if (isAvailable()) { - FileUtil.serialize(context, new EqualizerSettings(equalizer, bass, loudnessEnhancerController), "equalizer.dat"); - } - } catch (Throwable x) { - Log.w(TAG, "Failed to save equalizer settings.", x); - } - } - - public void loadSettings() { - try { - if (isAvailable()) { - EqualizerSettings settings = FileUtil.deserialize(context, "equalizer.dat", EqualizerSettings.class); - if (settings != null) { - settings.apply(equalizer, bass, loudnessEnhancerController); - } - } - } catch (Throwable x) { - Log.w(TAG, "Failed to load equalizer settings.", x); - } - } - - public boolean isAvailable() { - return equalizer != null && bass != null; - } - - public boolean isEnabled() { - try { - return isAvailable() && equalizer.getEnabled(); - } catch(Exception e) { - return false; - } - } - - public void release() { - if (isAvailable()) { - released = true; - equalizer.release(); - bass.release(); - if(loudnessEnhancerController != null && loudnessEnhancerController.isAvailable()) { - loudnessEnhancerController.release(); - } - } - } - - public Equalizer getEqualizer() { - if(released) { - released = false; - try { - init(); - } catch (Throwable x) { - equalizer = null; - released = true; - Log.w(TAG, "Failed to create equalizer.", x); - } - } - return equalizer; - } - public BassBoost getBassBoost() { - if(released) { - released = false; - try { - init(); - } catch (Throwable x) { - bass = null; - Log.w(TAG, "Failed to create bass booster.", x); - } - } - return bass; - } - public LoudnessEnhancerController getLoudnessEnhancerController() { - if(loudnessAvailable && released) { - released = false; - try { - init(); - } catch (Throwable x) { - loudnessEnhancerController = null; - Log.w(TAG, "Failed to create loudness enhancer.", x); - } - } - return loudnessEnhancerController; - } - - private static class EqualizerSettings implements Serializable { - - private short[] bandLevels; - private short preset; - private boolean enabled; - private short bass; - private int loudness; - - public EqualizerSettings() { - - } - public EqualizerSettings(Equalizer equalizer, BassBoost boost, LoudnessEnhancerController loudnessEnhancerController) { - enabled = equalizer.getEnabled(); - bandLevels = new short[equalizer.getNumberOfBands()]; - for (short i = 0; i < equalizer.getNumberOfBands(); i++) { - bandLevels[i] = equalizer.getBandLevel(i); - } - try { - preset = equalizer.getCurrentPreset(); - } catch (Exception x) { - preset = -1; - } - try { - bass = boost.getRoundedStrength(); - } catch(Exception e) { - bass = 0; - } - - try { - loudness = (int) loudnessEnhancerController.getGain(); - } catch(Exception e) { - loudness = 0; - } - } - - public void apply(Equalizer equalizer, BassBoost boost, LoudnessEnhancerController loudnessController) { - for (short i = 0; i < bandLevels.length; i++) { - equalizer.setBandLevel(i, bandLevels[i]); - } - equalizer.setEnabled(enabled); - if(bass != 0) { - boost.setEnabled(true); - boost.setStrength(bass); - } - if(loudness != 0) { - loudnessController.enable(); - loudnessController.setGain(loudness); - } - } - } -} - diff --git a/src/github/daneren2005/dsub/audiofx/LoudnessEnhancerController.java b/src/github/daneren2005/dsub/audiofx/LoudnessEnhancerController.java deleted file mode 100644 index df6fdb1c..00000000 --- a/src/github/daneren2005/dsub/audiofx/LoudnessEnhancerController.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2014 (C) Scott Jackson -*/ -package github.daneren2005.dsub.audiofx; - -import android.content.Context; -import android.media.audiofx.LoudnessEnhancer; -import android.util.Log; - -public class LoudnessEnhancerController { - private static final String TAG = LoudnessEnhancerController.class.getSimpleName(); - - private final Context context; - private LoudnessEnhancer enhancer; - private boolean released = false; - private int audioSessionId = 0; - - public LoudnessEnhancerController(Context context, int audioSessionId) { - this.context = context; - try { - this.audioSessionId = audioSessionId; - enhancer = new LoudnessEnhancer(audioSessionId); - } catch (Throwable x) { - Log.w(TAG, "Failed to create enhancer", x); - } - } - - public boolean isAvailable() { - return enhancer != null; - } - - public boolean isEnabled() { - try { - return isAvailable() && enhancer.getEnabled(); - } catch(Exception e) { - return false; - } - } - - public void enable() { - enhancer.setEnabled(true); - } - public void disable() { - enhancer.setEnabled(false); - } - - public float getGain() { - return enhancer.getTargetGain(); - } - public void setGain(int gain) { - enhancer.setTargetGain(gain); - } - - public void release() { - if (isAvailable()) { - enhancer.release(); - released = true; - } - } - -} - diff --git a/src/github/daneren2005/dsub/domain/Artist.java b/src/github/daneren2005/dsub/domain/Artist.java deleted file mode 100644 index f30147e6..00000000 --- a/src/github/daneren2005/dsub/domain/Artist.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import android.util.Log; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -/** - * @author Sindre Mehus - */ -public class Artist implements Serializable { - private static final String TAG = Artist.class.getSimpleName(); - - private String id; - private String name; - private String index; - private boolean starred; - private int closeness; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getIndex() { - return index; - } - - public void setIndex(String index) { - this.index = index; - } - - public boolean isStarred() { - return starred; - } - - public void setStarred(boolean starred) { - this.starred = starred; - } - - public int getCloseness() { - return closeness; - } - - public void setCloseness(int closeness) { - this.closeness = closeness; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Artist entry = (Artist) o; - return id.equals(entry.id); - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public String toString() { - return name; - } - - public static class ArtistComparator implements Comparator { - private String[] ignoredArticles; - - public ArtistComparator(String[] ignoredArticles) { - this.ignoredArticles = ignoredArticles; - } - - public int compare(Artist lhsArtist, Artist rhsArtist) { - String lhs = lhsArtist.getName().toLowerCase(); - String rhs = rhsArtist.getName().toLowerCase(); - - char lhs1 = lhs.charAt(0); - char rhs1 = rhs.charAt(0); - - if (Character.isDigit(lhs1) && !Character.isDigit(rhs1)) { - return 1; - } else if (Character.isDigit(rhs1) && !Character.isDigit(lhs1)) { - return -1; - } - - for (String article : ignoredArticles) { - int index = lhs.indexOf(article.toLowerCase() + " "); - if (index == 0) { - lhs = lhs.substring(article.length() + 1); - } - index = rhs.indexOf(article.toLowerCase() + " "); - if (index == 0) { - rhs = rhs.substring(article.length() + 1); - } - } - - return lhs.compareTo(rhs); - } - } - - public static void sort(List artists, String[] ignoredArticles) { - try { - Collections.sort(artists, new ArtistComparator(ignoredArticles)); - } catch (Exception e) { - Log.w(TAG, "Failed to sort artists", e); - } - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/domain/ArtistInfo.java b/src/github/daneren2005/dsub/domain/ArtistInfo.java deleted file mode 100644 index 2205d561..00000000 --- a/src/github/daneren2005/dsub/domain/ArtistInfo.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.domain; - -import java.io.Serializable; -import java.util.List; - -public class ArtistInfo implements Serializable { - private String biography; - private String musicBrainzId; - private String lastFMUrl; - private String imageUrl; - private List similarArtists; - private List missingArtists; - - public String getBiography() { - return biography; - } - - public void setBiography(String biography) { - this.biography = biography; - } - - public String getMusicBrainzId() { - return musicBrainzId; - } - - public void setMusicBrainzId(String musicBrainzId) { - this.musicBrainzId = musicBrainzId; - } - - public String getLastFMUrl() { - return lastFMUrl; - } - - public void setLastFMUrl(String lastFMUrl) { - this.lastFMUrl = lastFMUrl; - } - - public String getImageUrl() { - return imageUrl; - } - - public void setImageUrl(String imageUrl) { - this.imageUrl = imageUrl; - } - - public List getSimilarArtists() { - return similarArtists; - } - - public void setSimilarArtists(List similarArtists) { - this.similarArtists = similarArtists; - } - - public List getMissingArtists() { - return missingArtists; - } - - public void setMissingArtists(List missingArtists) { - this.missingArtists = missingArtists; - } -} diff --git a/src/github/daneren2005/dsub/domain/Bookmark.java b/src/github/daneren2005/dsub/domain/Bookmark.java deleted file mode 100644 index df3535d0..00000000 --- a/src/github/daneren2005/dsub/domain/Bookmark.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2013 (C) Scott Jackson - */ -package github.daneren2005.dsub.domain; - -import java.io.Serializable; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -/** - * Created by Scott on 11/4/13. - */ -public class Bookmark implements Serializable { - private int position; - private String username; - private String comment; - private Date created; - private Date changed; - - public Bookmark() { - - } - public Bookmark(int position) { - this.position = position; - } - - public int getPosition() { - return position; - } - - public void setPosition(int position) { - this.position = position; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getComment() { - return comment; - } - - public void setComment(String comment) { - this.comment = comment; - } - - public Date getCreated() { - return created; - } - - public void setCreated(String created) { - if (created != null) { - try { - this.created = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(created); - } catch (ParseException e) { - this.created = null; - } - } else { - this.created = null; - } - } - public void setCreated(Date created) { - this.created = created; - } - - public Date getChanged() { - return changed; - } - - public void setChanged(String changed) { - if (changed != null) { - try { - this.changed = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(changed); - } catch (ParseException e) { - this.changed = null; - } - } else { - this.changed = null; - } - } - public void setChanged(Date changed) { - this.changed = changed; - } -} diff --git a/src/github/daneren2005/dsub/domain/ChatMessage.java b/src/github/daneren2005/dsub/domain/ChatMessage.java deleted file mode 100644 index 471594e9..00000000 --- a/src/github/daneren2005/dsub/domain/ChatMessage.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import java.io.Serializable; - -public class ChatMessage implements Serializable { - private String username; - private Long time; - private String message; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public Long getTime() { - return time; - } - - public void setTime(Long time) { - this.time = time; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/src/github/daneren2005/dsub/domain/DLNADevice.java b/src/github/daneren2005/dsub/domain/DLNADevice.java deleted file mode 100644 index 2de84013..00000000 --- a/src/github/daneren2005/dsub/domain/DLNADevice.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.domain; - -import android.os.Parcel; -import android.os.Parcelable; - -import org.fourthline.cling.model.meta.Device; - -/** - * Created by Scott on 11/1/2014. - */ -public class DLNADevice implements Parcelable { - public Device renderer; - public String id; - public String name; - public String description; - public int volume; - public int volumeMax; - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public DLNADevice createFromParcel(Parcel in) { - return new DLNADevice(in); - } - - public DLNADevice[] newArray(int size) { - return new DLNADevice[size]; - } - }; - - private DLNADevice(Parcel in) { - id = in.readString(); - name = in.readString(); - description = in.readString(); - volume = in.readInt(); - volumeMax = in.readInt(); - } - - public DLNADevice(Device renderer, String id, String name, String description, int volume, int volumeMax) { - this.renderer = renderer; - this.id = id; - this.name = name; - this.description = description; - this.volume = volume; - this.volumeMax = volumeMax; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(id); - dest.writeString(name); - dest.writeString(description); - dest.writeInt(volume); - dest.writeInt(volumeMax); - } -} diff --git a/src/github/daneren2005/dsub/domain/Genre.java b/src/github/daneren2005/dsub/domain/Genre.java deleted file mode 100644 index 4ca4c387..00000000 --- a/src/github/daneren2005/dsub/domain/Genre.java +++ /dev/null @@ -1,69 +0,0 @@ -package github.daneren2005.dsub.domain; - -import android.content.Context; -import android.content.SharedPreferences; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; - -public class Genre implements Serializable { - private String name; - private String index; - private Integer albumCount; - private Integer songCount; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getIndex() { - return index; - } - - public void setIndex(String index) { - this.index = index; - } - - @Override - public String toString() { - return name; - } - - public Integer getAlbumCount() { - return albumCount; - } - - public void setAlbumCount(Integer albumCount) { - this.albumCount = albumCount; - } - - public Integer getSongCount() { - return songCount; - } - - public void setSongCount(Integer songCount) { - this.songCount = songCount; - } - - public static class GenreComparator implements Comparator { - @Override - public int compare(Genre genre1, Genre genre2) { - return genre1.getName().compareToIgnoreCase(genre2.getName()); - } - - public static List sort(List genres) { - Collections.sort(genres, new GenreComparator()); - return genres; - } - - } -} diff --git a/src/github/daneren2005/dsub/domain/Indexes.java b/src/github/daneren2005/dsub/domain/Indexes.java deleted file mode 100644 index e15ccf9f..00000000 --- a/src/github/daneren2005/dsub/domain/Indexes.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import android.content.Context; -import android.content.SharedPreferences; - -import java.util.ArrayList; -import java.util.List; -import java.io.Serializable; - -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; - -/** - * @author Sindre Mehus - */ -public class Indexes implements Serializable { - - private long lastModified; - private List shortcuts; - private List artists; - private List entries; - - public Indexes() { - - } - public Indexes(long lastModified, List shortcuts, List artists) { - this.lastModified = lastModified; - this.shortcuts = shortcuts; - this.artists = artists; - this.entries = new ArrayList(); - } - public Indexes(long lastModified, List shortcuts, List artists, List entries) { - this.lastModified = lastModified; - this.shortcuts = shortcuts; - this.artists = artists; - this.entries = entries; - if(!entries.isEmpty()) { - Artist root = new Artist(); - root.setId("root"); - root.setName("Root"); - root.setIndex("#"); - artists.add(root); - } - } - - public long getLastModified() { - return lastModified; - } - - public List getShortcuts() { - return shortcuts; - } - - public List getArtists() { - return artists; - } - - public void setArtists(List artists) { - this.shortcuts = new ArrayList(); - this.artists.clear(); - this.artists.addAll(artists); - } - - public List getEntries() { - return entries; - } - - public void sortChildren(Context context) { - SharedPreferences prefs = Util.getPreferences(context); - String ignoredArticlesString = prefs.getString(Constants.CACHE_KEY_IGNORE, "The El La Los Las Le Les"); - final String[] ignoredArticles = ignoredArticlesString.split(" "); - - Artist.sort(shortcuts, ignoredArticles); - Artist.sort(artists, ignoredArticles); - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/domain/Lyrics.java b/src/github/daneren2005/dsub/domain/Lyrics.java deleted file mode 100644 index 5272920d..00000000 --- a/src/github/daneren2005/dsub/domain/Lyrics.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import java.io.Serializable; - -/** - * Song lyrics. - * - * @author Sindre Mehus - */ -public class Lyrics implements Serializable { - - private String artist; - private String title; - private String text; - - public String getArtist() { - return artist; - } - - public void setArtist(String artist) { - this.artist = artist; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getText() { - return text; - } - - public void setText(String text) { - this.text = text; - } -} diff --git a/src/github/daneren2005/dsub/domain/MusicDirectory.java b/src/github/daneren2005/dsub/domain/MusicDirectory.java deleted file mode 100644 index ad819763..00000000 --- a/src/github/daneren2005/dsub/domain/MusicDirectory.java +++ /dev/null @@ -1,559 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import android.content.Context; -import android.media.MediaMetadataRetriever; -import android.util.Log; -import java.util.ArrayList; -import java.util.List; -import java.io.File; -import java.io.Serializable; -import java.util.Collections; -import java.util.Comparator; - -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; - -/** - * @author Sindre Mehus - */ -public class MusicDirectory implements Serializable { - private static final String TAG = MusicDirectory.class.getSimpleName(); - - private String name; - private String id; - private String parent; - private List children; - - public MusicDirectory() { - children = new ArrayList(); - } - public MusicDirectory(List children) { - this.children = children; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getParent() { - return parent; - } - - public void setParent(String parent) { - this.parent = parent; - } - - public void addChild(Entry child) { - if(child != null) { - children.add(child); - } - } - public void addChildren(List children) { - this.children.addAll(children); - } - - public void replaceChildren(List children) { - this.children = children; - } - - public List getChildren() { - return getChildren(true, true); - } - - public List getChildren(boolean includeDirs, boolean includeFiles) { - if (includeDirs && includeFiles) { - return children; - } - - List result = new ArrayList(children.size()); - for (Entry child : children) { - if (child != null && child.isDirectory() && includeDirs || !child.isDirectory() && includeFiles) { - result.add(child); - } - } - return result; - } - - public int getChildrenSize() { - return children.size(); - } - - public void shuffleChildren() { - Collections.shuffle(this.children); - } - - public void sortChildren(Context context, int instance) { - if(ServerInfo.checkServerVersion(context, "1.8", instance)) { - sortChildren(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_CUSTOM_SORT_ENABLED, true)); - } - } - public void sortChildren(boolean byYear) { - EntryComparator.sort(children, byYear); - } - - public static class Entry implements Serializable { - public static final int TYPE_SONG = 0; - public static final int TYPE_PODCAST = 1; - public static final int TYPE_AUDIO_BOOK = 2; - - private String id; - private String parent; - private String grandParent; - private String albumId; - private String artistId; - private boolean directory; - private String title; - private String album; - private String artist; - private Integer track; - private Integer year; - private String genre; - private String contentType; - private String suffix; - private String transcodedContentType; - private String transcodedSuffix; - private String coverArt; - private Long size; - private Integer duration; - private Integer bitRate; - private String path; - private boolean video; - private Integer discNumber; - private boolean starred; - private Integer rating; - private Bookmark bookmark; - private int type = 0; - private int closeness; - - public Entry() { - - } - public Entry(String id) { - this.id = id; - } - public Entry(Artist artist) { - this.id = artist.getId(); - this.title = artist.getName(); - this.directory = true; - } - - public void loadMetadata(File file) { - try { - MediaMetadataRetriever metadata = new MediaMetadataRetriever(); - metadata.setDataSource(file.getAbsolutePath()); - String discNumber = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER); - if(discNumber == null) { - discNumber = "1/1"; - } - int slashIndex = discNumber.indexOf("/"); - if(slashIndex > 0) { - discNumber = discNumber.substring(0, slashIndex); - } - try { - setDiscNumber(Integer.parseInt(discNumber)); - } catch(Exception e) { - Log.w(TAG, "Non numbers in disc field!"); - } - String bitrate = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE); - setBitRate(Integer.parseInt((bitrate != null) ? bitrate : "0") / 1000); - String length = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); - setDuration(Integer.parseInt(length) / 1000); - String artist = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST); - if(artist != null) { - setArtist(artist); - } - String album = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM); - if(album != null) { - setAlbum(album); - } - metadata.release(); - } catch(Exception e) { - Log.i(TAG, "Device doesn't properly support MediaMetadataRetreiver", e); - } - } - public void rebaseTitleOffPath() { - try { - String filename = getPath(); - int index = filename.lastIndexOf('/'); - if (index != -1) { - filename = filename.substring(index + 1); - if (getTrack() != null) { - filename = filename.replace(String.format("%02d ", getTrack()), ""); - } - - index = filename.lastIndexOf('.'); - if(index != -1) { - filename = filename.substring(0, index); - } - - setTitle(filename); - } - } catch(Exception e) { - Log.w(TAG, "Failed to update title based off of path", e); - } - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getParent() { - return parent; - } - - public void setParent(String parent) { - this.parent = parent; - } - - public String getGrandParent() { - return grandParent; - } - - public void setGrandParent(String grandParent) { - this.grandParent = grandParent; - } - - public String getAlbumId() { - return albumId; - } - - public void setAlbumId(String albumId) { - this.albumId = albumId; - } - - public String getArtistId() { - return artistId; - } - - public void setArtistId(String artistId) { - this.artistId = artistId; - } - - public boolean isDirectory() { - return directory; - } - - public void setDirectory(boolean directory) { - this.directory = directory; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getAlbum() { - return album; - } - - public boolean isAlbum() { - return getParent() != null || getArtist() != null; - } - - public String getAlbumDisplay() { - if(album != null && title.startsWith("Disc ")) { - return album; - } else { - return title; - } - } - - public void setAlbum(String album) { - this.album = album; - } - - public String getArtist() { - return artist; - } - - public void setArtist(String artist) { - this.artist = artist; - } - - public Integer getTrack() { - return track; - } - - public void setTrack(Integer track) { - this.track = track; - } - - public Integer getYear() { - return year; - } - - public void setYear(Integer year) { - this.year = year; - } - - public String getGenre() { - return genre; - } - - public void setGenre(String genre) { - this.genre = genre; - } - - public String getContentType() { - return contentType; - } - - public void setContentType(String contentType) { - this.contentType = contentType; - } - - public String getSuffix() { - return suffix; - } - - public void setSuffix(String suffix) { - this.suffix = suffix; - } - - public String getTranscodedContentType() { - return transcodedContentType; - } - - public void setTranscodedContentType(String transcodedContentType) { - this.transcodedContentType = transcodedContentType; - } - - public String getTranscodedSuffix() { - return transcodedSuffix; - } - - public void setTranscodedSuffix(String transcodedSuffix) { - this.transcodedSuffix = transcodedSuffix; - } - - public Long getSize() { - return size; - } - - public void setSize(Long size) { - this.size = size; - } - - public Integer getDuration() { - return duration; - } - - public void setDuration(Integer duration) { - this.duration = duration; - } - - public Integer getBitRate() { - return bitRate; - } - - public void setBitRate(Integer bitRate) { - this.bitRate = bitRate; - } - - public String getCoverArt() { - return coverArt; - } - - public void setCoverArt(String coverArt) { - this.coverArt = coverArt; - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } - - public boolean isVideo() { - return video; - } - - public void setVideo(boolean video) { - this.video = video; - } - - public Integer getDiscNumber() { - return discNumber; - } - - public void setDiscNumber(Integer discNumber) { - this.discNumber = discNumber; - } - - public boolean isStarred() { - return starred; - } - - public void setStarred(boolean starred) { - this.starred = starred; - } - - public int getRating() { - return rating == null ? 0 : rating; - } - public void setRating(Integer rating) { - if(rating == null || rating == 0) { - this.rating = null; - } else { - this.rating = rating; - } - } - - public Bookmark getBookmark() { - return bookmark; - } - public void setBookmark(Bookmark bookmark) { - this.bookmark = bookmark; - } - - public int getType() { - return type; - } - public void setType(int type) { - this.type = type; - } - public boolean isSong() { - return type == TYPE_SONG; - } - public boolean isPodcast() { - return this instanceof PodcastEpisode || type == TYPE_PODCAST; - } - public boolean isAudioBook() { - return type == TYPE_AUDIO_BOOK; - } - - public int getCloseness() { - return closeness; - } - - public void setCloseness(int closeness) { - this.closeness = closeness; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Entry entry = (Entry) o; - return id.equals(entry.id); - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public String toString() { - return title; - } - } - - public static class EntryComparator implements Comparator { - private boolean byYear; - - public EntryComparator(boolean byYear) { - this.byYear = byYear; - } - - public int compare(Entry lhs, Entry rhs) { - if(lhs.isDirectory() && !rhs.isDirectory()) { - return -1; - } else if(!lhs.isDirectory() && rhs.isDirectory()) { - return 1; - } else if(lhs.isDirectory() && rhs.isDirectory()) { - if(byYear) { - Integer lhsYear = lhs.getYear(); - Integer rhsYear = rhs.getYear(); - if(lhsYear != null && rhsYear != null) { - return lhsYear.compareTo(rhsYear); - } else if(lhsYear != null) { - return -1; - } else if(rhsYear != null) { - return 1; - } - } - - return lhs.getTitle().compareToIgnoreCase(rhs.getTitle()); - } - - Integer lhsDisc = lhs.getDiscNumber(); - Integer rhsDisc = rhs.getDiscNumber(); - - if(lhsDisc != null && rhsDisc != null) { - if(lhsDisc < rhsDisc) { - return -1; - } else if(lhsDisc > rhsDisc) { - return 1; - } - } - - Integer lhsTrack = lhs.getTrack(); - Integer rhsTrack = rhs.getTrack(); - if(lhsTrack != null && rhsTrack != null) { - return lhsTrack.compareTo(rhsTrack); - } else if(lhsTrack != null) { - return -1; - } else if(rhsTrack != null) { - return 1; - } - - return lhs.getTitle().compareToIgnoreCase(rhs.getTitle()); - } - - public static void sort(List entries) { - sort(entries, true); - } - public static void sort(List entries, boolean byYear) { - try { - Collections.sort(entries, new EntryComparator(byYear)); - } catch (Exception e) { - Log.w(TAG, "Failed to sort MusicDirectory"); - } - } - } -} diff --git a/src/github/daneren2005/dsub/domain/MusicFolder.java b/src/github/daneren2005/dsub/domain/MusicFolder.java deleted file mode 100644 index 99e86e23..00000000 --- a/src/github/daneren2005/dsub/domain/MusicFolder.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import java.io.Serializable; - -/** - * Represents a top level directory in which music or other media is stored. - * - * @author Sindre Mehus - * @version $Id$ - */ -public class MusicFolder implements Serializable { - - private String id; - private String name; - - public MusicFolder() { - - } - public MusicFolder(String id, String name) { - this.id = id; - this.name = name; - } - - public String getId() { - return id; - } - - public String getName() { - return name; - } -} diff --git a/src/github/daneren2005/dsub/domain/PlayerQueue.java b/src/github/daneren2005/dsub/domain/PlayerQueue.java deleted file mode 100644 index 32f29725..00000000 --- a/src/github/daneren2005/dsub/domain/PlayerQueue.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2015 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.domain; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -public class PlayerQueue implements Serializable { - public List songs = new ArrayList(); - public List toDelete = new ArrayList(); - public int currentPlayingIndex; - public int currentPlayingPosition; - public boolean renameCurrent = false; - public Date changed = null; -} diff --git a/src/github/daneren2005/dsub/domain/PlayerState.java b/src/github/daneren2005/dsub/domain/PlayerState.java deleted file mode 100644 index 21f1b1a4..00000000 --- a/src/github/daneren2005/dsub/domain/PlayerState.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import android.media.RemoteControlClient; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public enum PlayerState { - IDLE(RemoteControlClient.PLAYSTATE_STOPPED), - DOWNLOADING(RemoteControlClient.PLAYSTATE_BUFFERING), - PREPARING(RemoteControlClient.PLAYSTATE_BUFFERING), - PREPARED(RemoteControlClient.PLAYSTATE_STOPPED), - STARTED(RemoteControlClient.PLAYSTATE_PLAYING), - STOPPED(RemoteControlClient.PLAYSTATE_STOPPED), - PAUSED(RemoteControlClient.PLAYSTATE_PAUSED), - PAUSED_TEMP(RemoteControlClient.PLAYSTATE_PAUSED), - COMPLETED(RemoteControlClient.PLAYSTATE_STOPPED); - - private final int mRemoteControlClientPlayState; - - private PlayerState(int playState) { - mRemoteControlClientPlayState = playState; - } - - public int getRemoteControlClientPlayState() { - return mRemoteControlClientPlayState; - } -} diff --git a/src/github/daneren2005/dsub/domain/Playlist.java b/src/github/daneren2005/dsub/domain/Playlist.java deleted file mode 100644 index 7cd820c0..00000000 --- a/src/github/daneren2005/dsub/domain/Playlist.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import java.io.Serializable; - -/** - * @author Sindre Mehus - */ -public class Playlist implements Serializable { - - private String id; - private String name; - private String owner; - private String comment; - private String songCount; - private String created; - private Boolean pub; - - public Playlist() { - - } - public Playlist(String id, String name) { - this.id = id; - this.name = name; - } - public Playlist(String id, String name, String owner, String comment, String songCount, String created, String pub) { - this.id = id; - this.name = name; - this.owner = (owner == null) ? "" : owner; - this.comment = (comment == null) ? "" : comment; - this.songCount = (songCount == null) ? "" : songCount; - this.created = (created == null) ? "" : created; - this.pub = (pub == null) ? null : (pub.equals("true")); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getOwner() { - return this.owner; - } - - public void setOwner(String owner) { - this.owner = owner; - } - - public String getComment() { - return this.comment; - } - - public void setComment(String comment) { - this.comment = comment; - } - - public String getSongCount() { - return this.songCount; - } - - public void setSongCount(String songCount) { - this.songCount = songCount; - } - - public String getCreated() { - return this.created; - } - - public void setCreated(String created) { - this.created = created; - } - - public Boolean getPublic() { - return this.pub; - } - public void setPublic(Boolean pub) { - this.pub = pub; - } - - @Override - public String toString() { - return name; - } - - @Override - public boolean equals(Object o) { - if(o == this) { - return true; - } else if(o == null) { - return false; - } else if(o instanceof String) { - return o.equals(this.id); - } else if(o.getClass() != getClass()) { - return false; - } - - Playlist playlist = (Playlist) o; - return playlist.id.equals(this.id); - } -} diff --git a/src/github/daneren2005/dsub/domain/PodcastChannel.java b/src/github/daneren2005/dsub/domain/PodcastChannel.java deleted file mode 100644 index a1c1617e..00000000 --- a/src/github/daneren2005/dsub/domain/PodcastChannel.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import android.content.Context; -import android.content.SharedPreferences; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; - -/** - * - * @author Scott - */ -public class PodcastChannel implements Serializable { - private String id; - private String name; - private String url; - private String description; - private String status; - private String errorMessage; - - public PodcastChannel() { - - } - - public String getId() { - return id; - } - public void setId(String id) { - this.id = id; - } - - public String getName() { - return name; - } - public void setName(String name) { - this.name = name; - } - - public String getUrl() { - return url; - } - public void setUrl(String url) { - this.url = url; - } - - public String getDescription() { - return description; - } - public void setDescription(String description) { - this.description = description; - } - - public String getStatus() { - return status; - } - public void setStatus(String status) { - this.status = status; - } - - public String getErrorMessage() { - return errorMessage; - } - public void setErrorMessage(String errorMessage) { - this.errorMessage = errorMessage; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - PodcastChannel entry = (PodcastChannel) o; - return id.equals(entry.id); - } - - public static class PodcastComparator implements Comparator { - private static String[] ignoredArticles; - - @Override - public int compare(PodcastChannel podcast1, PodcastChannel podcast2) { - String lhs = podcast1.getName(); - String rhs = podcast2.getName(); - if(lhs == null && rhs == null) { - return 0; - } else if(lhs == null) { - return 1; - } else if(rhs == null) { - return -1; - } - - lhs = lhs.toLowerCase(); - rhs = rhs.toLowerCase(); - - for(String article: ignoredArticles) { - int index = lhs.indexOf(article.toLowerCase() + " "); - if(index == 0) { - lhs = lhs.substring(article.length() + 1); - } - index = rhs.indexOf(article.toLowerCase() + " "); - if(index == 0) { - rhs = rhs.substring(article.length() + 1); - } - } - - return lhs.compareToIgnoreCase(rhs); - } - - public static List sort(List podcasts, Context context) { - SharedPreferences prefs = Util.getPreferences(context); - String ignoredArticlesString = prefs.getString(Constants.CACHE_KEY_IGNORE, "The El La Los Las Le Les"); - ignoredArticles = ignoredArticlesString.split(" "); - - Collections.sort(podcasts, new PodcastComparator()); - return podcasts; - } - - } -} diff --git a/src/github/daneren2005/dsub/domain/PodcastEpisode.java b/src/github/daneren2005/dsub/domain/PodcastEpisode.java deleted file mode 100644 index 01821072..00000000 --- a/src/github/daneren2005/dsub/domain/PodcastEpisode.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -/** - * - * @author Scott - */ -public class PodcastEpisode extends MusicDirectory.Entry { - private String episodeId; - private String date; - private String status; - - public PodcastEpisode() { - setDirectory(false); - } - - public String getEpisodeId() { - return episodeId; - } - public void setEpisodeId(String episodeId) { - this.episodeId = episodeId; - } - - public String getDate() { - return date; - } - public void setDate(String date) { - this.date = date; - } - - public String getStatus() { - return status; - } - public void setStatus(String status) { - this.status = status; - } -} diff --git a/src/github/daneren2005/dsub/domain/RemoteControlState.java b/src/github/daneren2005/dsub/domain/RemoteControlState.java deleted file mode 100644 index 47895984..00000000 --- a/src/github/daneren2005/dsub/domain/RemoteControlState.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus -*/ - -package github.daneren2005.dsub.domain; - -public enum RemoteControlState { - LOCAL(0), - JUKEBOX_SERVER(1), - CHROMECAST(2), - REMOTE_CLIENT(3), - DLNA(4); - - private final int mRemoteControlState; - - private RemoteControlState(int value) { - mRemoteControlState = value; - } - - public int getValue() { - return mRemoteControlState; - } -} diff --git a/src/github/daneren2005/dsub/domain/RemoteStatus.java b/src/github/daneren2005/dsub/domain/RemoteStatus.java deleted file mode 100644 index e9749120..00000000 --- a/src/github/daneren2005/dsub/domain/RemoteStatus.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public class RemoteStatus { - - private Integer positionSeconds; - private Integer currentPlayingIndex; - private Float gain; - private boolean playing; - - public Integer getPositionSeconds() { - return positionSeconds; - } - - public void setPositionSeconds(Integer positionSeconds) { - this.positionSeconds = positionSeconds; - } - - public Integer getCurrentPlayingIndex() { - return currentPlayingIndex; - } - - public void setCurrentIndex(Integer currentPlayingIndex) { - this.currentPlayingIndex = currentPlayingIndex; - } - - public boolean isPlaying() { - return playing; - } - - public void setPlaying(boolean playing) { - this.playing = playing; - } - - public Float getGain() { - return gain; - } - - public void setGain(float gain) { - this.gain = gain; - } -} diff --git a/src/github/daneren2005/dsub/domain/RepeatMode.java b/src/github/daneren2005/dsub/domain/RepeatMode.java deleted file mode 100644 index 7139029c..00000000 --- a/src/github/daneren2005/dsub/domain/RepeatMode.java +++ /dev/null @@ -1,28 +0,0 @@ -package github.daneren2005.dsub.domain; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public enum RepeatMode { - OFF { - @Override - public RepeatMode next() { - return ALL; - } - }, - ALL { - @Override - public RepeatMode next() { - return SINGLE; - } - }, - SINGLE { - @Override - public RepeatMode next() { - return OFF; - } - }; - - public abstract RepeatMode next(); -} diff --git a/src/github/daneren2005/dsub/domain/SearchCritera.java b/src/github/daneren2005/dsub/domain/SearchCritera.java deleted file mode 100644 index 20d46aa0..00000000 --- a/src/github/daneren2005/dsub/domain/SearchCritera.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -/** - * The criteria for a music search. - * - * @author Sindre Mehus - */ -public class SearchCritera { - - private final String query; - private final int artistCount; - private final int albumCount; - private final int songCount; - - public SearchCritera(String query, int artistCount, int albumCount, int songCount) { - this.query = query; - this.artistCount = artistCount; - this.albumCount = albumCount; - this.songCount = songCount; - } - - public String getQuery() { - return query; - } - - public int getArtistCount() { - return artistCount; - } - - public int getAlbumCount() { - return albumCount; - } - - public int getSongCount() { - return songCount; - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/domain/SearchResult.java b/src/github/daneren2005/dsub/domain/SearchResult.java deleted file mode 100644 index 3427f2ca..00000000 --- a/src/github/daneren2005/dsub/domain/SearchResult.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import java.io.Serializable; -import java.util.List; - -/** - * The result of a search. Contains matching artists, albums and songs. - * - * @author Sindre Mehus - */ -public class SearchResult implements Serializable { - - private final List artists; - private final List albums; - private final List songs; - - public SearchResult(List artists, List albums, List songs) { - this.artists = artists; - this.albums = albums; - this.songs = songs; - } - - public List getArtists() { - return artists; - } - - public List getAlbums() { - return albums; - } - - public List getSongs() { - return songs; - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/domain/ServerInfo.java b/src/github/daneren2005/dsub/domain/ServerInfo.java deleted file mode 100644 index 3ece6af9..00000000 --- a/src/github/daneren2005/dsub/domain/ServerInfo.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import android.content.Context; - -import java.io.Serializable; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Util; - -/** - * Information about the Subsonic server. - * - * @author Sindre Mehus - */ -public class ServerInfo implements Serializable { - public static final int TYPE_SUBSONIC = 1; - public static final int TYPE_MADSONIC = 2; - private static final Map SERVERS = new ConcurrentHashMap(); - - private boolean isLicenseValid; - private Version restVersion; - private int type; - - public ServerInfo() { - type = TYPE_SUBSONIC; - } - - public boolean isLicenseValid() { - return isLicenseValid; - } - - public void setLicenseValid(boolean licenseValid) { - isLicenseValid = licenseValid; - } - - public Version getRestVersion() { - return restVersion; - } - - public void setRestVersion(Version restVersion) { - this.restVersion = restVersion; - } - - public int getRestType() { - return type; - } - public void setRestType(int type) { - this.type = type; - } - - public boolean isStockSubsonic() { - return type == TYPE_SUBSONIC; - } - public boolean isMadsonic() { - return type == TYPE_MADSONIC; - } - - @Override - public boolean equals(Object o) { - if(this == o) { - return true; - } else if(o == null || getClass() != o.getClass()) { - return false; - } - - final ServerInfo info = (ServerInfo) o; - - if(this.type != info.type) { - return false; - } else if(this.restVersion == null || info.restVersion == null) { - // Should never be null unless just starting up - return false; - } else { - return this.restVersion.equals(info.restVersion); - } - } - - // Stub to make sure this is never used, too easy to screw up - private void saveServerInfo(Context context) { - - } - public void saveServerInfo(Context context, int instance) { - ServerInfo current = SERVERS.get(instance); - if(!this.equals(current)) { - SERVERS.put(instance, this); - FileUtil.serialize(context, this, getCacheName(context, instance)); - } - } - - public static ServerInfo getServerInfo(Context context) { - return getServerInfo(context, Util.getActiveServer(context)); - } - public static ServerInfo getServerInfo(Context context, int instance) { - ServerInfo current = SERVERS.get(instance); - if(current != null) { - return current; - } - - current = FileUtil.deserialize(context, getCacheName(context, instance), ServerInfo.class); - if(current != null) { - SERVERS.put(instance, current); - } - - return current; - } - - public static Version getServerVersion(Context context) { - return getServerVersion(context, Util.getActiveServer(context)); - } - public static Version getServerVersion(Context context, int instance) { - ServerInfo server = getServerInfo(context, instance); - if(server == null) { - return null; - } - - return server.getRestVersion(); - } - - public static boolean checkServerVersion(Context context, String requiredVersion) { - return checkServerVersion(context, requiredVersion, Util.getActiveServer(context)); - } - public static boolean checkServerVersion(Context context, String requiredVersion, int instance) { - ServerInfo server = getServerInfo(context, instance); - if(server == null) { - return false; - } - - Version version = server.getRestVersion(); - if(version == null) { - return false; - } - - Version required = new Version(requiredVersion); - return version.compareTo(required) >= 0; - } - - public static int getServerType(Context context) { - return getServerType(context, Util.getActiveServer(context)); - } - public static int getServerType(Context context, int instance) { - if(Util.isOffline(context)) { - return 0; - } - - ServerInfo server = getServerInfo(context, instance); - if(server == null) { - return 0; - } - - return server.getRestType(); - } - - public static boolean isStockSubsonic(Context context) { - return isStockSubsonic(context, Util.getActiveServer(context)); - } - public static boolean isStockSubsonic(Context context, int instance) { - return getServerType(context, instance) == TYPE_SUBSONIC; - } - - public static boolean isMadsonic(Context context) { - return isMadsonic(context, Util.getActiveServer(context)); - } - public static boolean isMadsonic(Context context, int instance) { - return getServerType(context, instance) == TYPE_MADSONIC; - } - - private static String getCacheName(Context context, int instance) { - return "server-" + Util.getRestUrl(context, null, instance, false).hashCode() + ".ser"; - } - - public static boolean hasArtistInfo(Context context) { - if(isStockSubsonic(context) && ServerInfo.checkServerVersion(context, "1.11")) { - return true; - } else if(isMadsonic(context)) { - // TODO: When madsonic adds support, figure out what REST version it is added on - return false; - } else { - return false; - } - } - - public static boolean canBookmark(Context context) { - return checkServerVersion(context, "1.9"); - } - - public static boolean canSavePlayQueue(Context context) { - return ServerInfo.checkServerVersion(context, "1.12") && !ServerInfo.isMadsonic(context); - } - - public static boolean canAlbumListPerFolder(Context context) { - return ServerInfo.checkServerVersion(context, "1.11") && !ServerInfo.isMadsonic(context); - } -} diff --git a/src/github/daneren2005/dsub/domain/Share.java b/src/github/daneren2005/dsub/domain/Share.java deleted file mode 100644 index aa22956d..00000000 --- a/src/github/daneren2005/dsub/domain/Share.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import github.daneren2005.dsub.domain.MusicDirectory.Entry; -import java.io.Serializable; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Locale; - -public class Share implements Serializable { - private String id; - private String url; - private String description; - private String username; - private Date created; - private Date lastVisited; - private Date expires; - private Long visitCount; - private List entries; - - public Share() { - entries = new ArrayList(); - } - - public String getName() { - if(description != null && !"".equals(description)) { - return description; - } else { - return url.replaceFirst(".*/([^/?]+).*", "$1"); - } - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public Date getCreated() { - return created; - } - - public void setCreated(String created) { - if (created != null) { - try { - this.created = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(created); - } catch (ParseException e) { - this.created = null; - } - } else { - this.created = null; - } - } - public void setCreated(Date created) { - this.created = created; - } - - public Date getLastVisited() { - return lastVisited; - } - - public void setLastVisited(String lastVisited) { - if (lastVisited != null) { - try { - this.lastVisited = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(lastVisited); - } catch (ParseException e) { - this.lastVisited = null; - } - } else { - this.lastVisited = null; - } - } - public void setLastVisited(Date lastVisited) { - this.lastVisited = lastVisited; - } - - public Date getExpires() { - return expires; - } - - public void setExpires(String expires) { - if (expires != null) { - try { - this.expires = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(expires); - } catch (ParseException e) { - this.expires = null; - } - } else { - this.expires = null; - } - } - public void setExpires(Date expires) { - this.expires = expires; - } - - public Long getVisitCount() { - return visitCount; - } - - public void setVisitCount(Long visitCount) { - this.visitCount = visitCount; - } - - public MusicDirectory getMusicDirectory() { - MusicDirectory dir = new MusicDirectory(); - dir.addChildren(entries); - dir.setId(getId()); - dir.setName(getName()); - return dir; - } - - public List getEntries() { - return this.entries; - } - - public void addEntry(Entry entry) { - entries.add(entry); - } - } diff --git a/src/github/daneren2005/dsub/domain/User.java b/src/github/daneren2005/dsub/domain/User.java deleted file mode 100644 index 179ac033..00000000 --- a/src/github/daneren2005/dsub/domain/User.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.domain; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -public class User implements Serializable { - public static final String SCROBBLING = "scrobblingEnabled"; - public static final String ADMIN = "adminRole"; - public static final String SETTINGS = "settingsRole"; - public static final String DOWNLOAD = "downloadRole"; - public static final String UPLOAD = "uploadRole"; - public static final String COVERART = "coverArtRole"; - public static final String COMMENT = "commentRole"; - public static final String PODCAST = "podcastRole"; - public static final String STREAM = "streamRole"; - public static final String JUKEBOX = "jukeboxRole"; - public static final String SHARE = "shareRole"; - public static final String LASTFM = "lastFMRole"; - public static final List ROLES = new ArrayList(); - - static { - ROLES.add(ADMIN); - ROLES.add(SETTINGS); - ROLES.add(STREAM); - ROLES.add(DOWNLOAD); - ROLES.add(UPLOAD); - ROLES.add(COVERART); - ROLES.add(COMMENT); - ROLES.add(PODCAST); - ROLES.add(JUKEBOX); - ROLES.add(SHARE); - } - - private String username; - private String password; - private String email; - - private List settings = new ArrayList(); - - public User() { - - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public List getSettings() { - return settings; - } - public void setSettings(List settings) { - this.settings.clear(); - this.settings.addAll(settings); - } - public void addSetting(String name, Boolean value) { - settings.add(new Setting(name, value)); - } - - public static class Setting implements Serializable { - String name; - Boolean value; - - public Setting() { - - } - public Setting(String name, Boolean value) { - this.name = name; - this.value = value; - } - - public String getName() { - return name; - } - public Boolean getValue() { - return value; - } - public void setValue(Boolean value) { - this.value = value; - } - } -} diff --git a/src/github/daneren2005/dsub/domain/Version.java b/src/github/daneren2005/dsub/domain/Version.java deleted file mode 100644 index 6b82ea99..00000000 --- a/src/github/daneren2005/dsub/domain/Version.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.domain; - -import java.io.Serializable; - -/** - * Represents the version number of the Subsonic Android app. - * - * @author Sindre Mehus - * @version $Revision: 1.3 $ $Date: 2006/01/20 21:25:16 $ - */ -public class Version implements Comparable, Serializable { - private int major; - private int minor; - private int beta; - private int bugfix; - - public Version() { - // For Kryo - } - - /** - * Creates a new version instance by parsing the given string. - * @param version A string of the format "1.27", "1.27.2" or "1.27.beta3". - */ - public Version(String version) { - String[] s = version.split("\\."); - major = Integer.valueOf(s[0]); - minor = Integer.valueOf(s[1]); - - if (s.length > 2) { - if (s[2].contains("beta")) { - beta = Integer.valueOf(s[2].replace("beta", "")); - } else { - bugfix = Integer.valueOf(s[2]); - } - } - } - - public int getMajor() { - return major; - } - - public int getMinor() { - return minor; - } - - public String getVersion() { - switch(major) { - case 1: - switch(minor) { - case 0: - return "3.8"; - case 1: - return "3.9"; - case 2: - return "4.0"; - case 3: - return "4.1"; - case 4: - return "4.2"; - case 5: - return "4.3.1"; - case 6: - return "4.5"; - case 7: - return "4.6"; - case 8: - return "4.7"; - case 9: - return "4.8"; - case 10: - return "4.9"; - case 11: - return "5.1"; - } - } - return ""; - } - - /** - * Return whether this object is equal to another. - * @param o Object to compare to. - * @return Whether this object is equals to another. - */ - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - final Version version = (Version) o; - - if (beta != version.beta) return false; - if (bugfix != version.bugfix) return false; - if (major != version.major) return false; - return minor == version.minor; - } - - /** - * Returns a hash code for this object. - * @return A hash code for this object. - */ - public int hashCode() { - int result; - result = major; - result = 29 * result + minor; - result = 29 * result + beta; - result = 29 * result + bugfix; - return result; - } - - /** - * Returns a string representation of the form "1.27", "1.27.2" or "1.27.beta3". - * @return A string representation of the form "1.27", "1.27.2" or "1.27.beta3". - */ - public String toString() { - StringBuffer buf = new StringBuffer(); - buf.append(major).append('.').append(minor); - if (beta != 0) { - buf.append(".beta").append(beta); - } else if (bugfix != 0) { - buf.append('.').append(bugfix); - } - - return buf.toString(); - } - - /** - * Compares this object with the specified object for order. - * @param version The object to compare to. - * @return A negative integer, zero, or a positive integer as this object is less than, equal to, or - * greater than the specified object. - */ - @Override - public int compareTo(Version version) { - if (major < version.major) { - return -1; - } else if (major > version.major) { - return 1; - } - - if (minor < version.minor) { - return -1; - } else if (minor > version.minor) { - return 1; - } - - if (bugfix < version.bugfix) { - return -1; - } else if (bugfix > version.bugfix) { - return 1; - } - - int thisBeta = beta == 0 ? Integer.MAX_VALUE : beta; - int otherBeta = version.beta == 0 ? Integer.MAX_VALUE : version.beta; - - if (thisBeta < otherBeta) { - return -1; - } else if (thisBeta > otherBeta) { - return 1; - } - - return 0; - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/fragments/AdminFragment.java b/src/github/daneren2005/dsub/fragments/AdminFragment.java deleted file mode 100644 index d59526b6..00000000 --- a/src/github/daneren2005/dsub/fragments/AdminFragment.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.fragments; - -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.User; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.parser.SubsonicRESTException; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.UserUtil; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.UserAdapter; - -public class AdminFragment extends SelectListFragment { - private static String TAG = AdminFragment.class.getSimpleName(); - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(super.onOptionsItemSelected(item)) { - return true; - } - - switch (item.getItemId()) { - case R.id.menu_add_user: - UserUtil.addNewUser(context, this); - break; - } - - return false; - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - MenuInflater inflater = context.getMenuInflater(); - if(UserUtil.isCurrentAdmin()) { - inflater.inflate(R.menu.admin_context, menu); - } else if(UserUtil.isCurrentRole(User.SETTINGS)) { - inflater.inflate(R.menu.admin_context_user, menu); - } - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - User user = objects.get(info.position); - - switch(menuItem.getItemId()) { - case R.id.admin_change_email: - UserUtil.changeEmail(context, user); - break; - case R.id.admin_change_password: - UserUtil.changePassword(context, user); - break; - case R.id.admin_delete_user: - UserUtil.deleteUser(context, user, adapter); - break; - } - - return true; - } - - @Override - public int getOptionsMenu() { - if(UserUtil.isCurrentAdmin()) { - return R.menu.admin; - } else { - return R.menu.empty; - } - } - - @Override - public ArrayAdapter getAdapter(List objs) { - return new UserAdapter(context, objs, getImageLoader()); - } - - @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - try { - // Will only work if user is admin - List users = musicService.getUsers(refresh, context, listener); - if(refresh) { - UserUtil.refreshCurrentUser(context, true); - } - return users; - } catch(SubsonicRESTException e) { - // Delete cached users if not allowed to get them - String s = Util.getRestUrl(context, null, false); - String cache = "users-" + s.hashCode() + ".ser"; - File file = new File(context.getCacheDir(), cache); - file.delete(); - - List users = new ArrayList(); - User user = musicService.getUser(refresh, UserUtil.getCurrentUsername(context), context, listener); - if(user != null) { - users.add(user); - } - - UserUtil.refreshCurrentUser(context, false); - return users; - } - } - - @Override - public int getTitleResource() { - return R.string.button_bar_admin; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - User user = (User) parent.getItemAtPosition(position); - - SubsonicFragment fragment = new UserFragment(); - Bundle args = new Bundle(); - args.putSerializable(Constants.INTENT_EXTRA_NAME_ID, user); - fragment.setArguments(args); - - replaceFragment(fragment); - } -} diff --git a/src/github/daneren2005/dsub/fragments/ChatFragment.java b/src/github/daneren2005/dsub/fragments/ChatFragment.java deleted file mode 100644 index 5d017fa7..00000000 --- a/src/github/daneren2005/dsub/fragments/ChatFragment.java +++ /dev/null @@ -1,250 +0,0 @@ -package github.daneren2005.dsub.fragments; - -import android.content.Context; -import android.content.SharedPreferences; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import android.os.Bundle; -import android.os.Handler; -import android.support.v4.widget.SwipeRefreshLayout; -import android.text.Editable; -import android.text.TextWatcher; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.ListView; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.ChatMessage; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.BackgroundTask; -import github.daneren2005.dsub.util.TabBackgroundTask; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.ChatAdapter; -import github.daneren2005.dsub.util.Constants; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -/** - * @author Joshua Bahnsen - */ -public class ChatFragment extends SubsonicFragment { - private static final String TAG = ChatFragment.class.getSimpleName(); - private ListView chatListView; - private EditText messageEditText; - private ImageButton sendButton; - private Long lastChatMessageTime = (long) 0; - private ArrayList messageList; - private ScheduledExecutorService executorService; - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - - if(bundle != null) { - List abstractList = (List) bundle.getSerializable(Constants.FRAGMENT_LIST); - messageList = new ArrayList(abstractList); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable(Constants.FRAGMENT_LIST, (Serializable) messageList); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - rootView = inflater.inflate(R.layout.chat, container, false); - - messageEditText = (EditText) rootView.findViewById(R.id.chat_edittext); - sendButton = (ImageButton) rootView.findViewById(R.id.chat_send); - - sendButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - sendMessage(); - } - }); - - chatListView = (ListView) rootView.findViewById(R.id.chat_entries); - - messageEditText.setImeActionLabel("Send", KeyEvent.KEYCODE_ENTER); - messageEditText.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { - } - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { - } - - @Override - public void afterTextChanged(Editable editable) { - sendButton.setEnabled(!Util.isNullOrWhiteSpace(editable.toString())); - } - }); - - messageEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { - - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_DONE || (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_DOWN)) { - sendMessage(); - return true; - } - - return false; - } - }); - - if(messageList == null) { - messageList = new ArrayList(); - refresh(true); - } else { - for (ChatMessage message : messageList) { - if (message.getTime() > lastChatMessageTime) { - lastChatMessageTime = message.getTime(); - } - } - - ChatAdapter chatAdapter = new ChatAdapter(context, messageList, getImageLoader()); - chatListView.setAdapter(chatAdapter); - } - setTitle(R.string.button_bar_chat); - - refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); - refreshLayout.setOnRefreshListener(this); - setupScrollList(chatListView); - - return rootView; - } - - @Override - public void onResume() { - super.onResume(); - - final Handler handler = new Handler(); - Runnable runnable = new Runnable() { - @Override - public void run() { - handler.post(new Runnable() { - @Override - public void run() { - if(primaryFragment) { - load(false); - } else { - invalidated = true; - } - } - }); - } - }; - - SharedPreferences prefs = Util.getPreferences(context); - long refreshRate = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_CHAT_REFRESH, "30")); - if(refreshRate > 0) { - executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleWithFixedDelay(runnable, refreshRate * 1000L, refreshRate * 1000L, TimeUnit.MILLISECONDS); - } - } - - @Override - public void onPause() { - super.onPause(); - if(executorService != null) { - executorService.shutdown(); - executorService = null; - } - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - menuInflater.inflate(R.menu.abstract_top_menu, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - return super.onOptionsItemSelected(item); - - } - - @Override - protected void refresh(boolean refresh) { - load(refresh); - } - - private synchronized void load(final boolean refresh) { - BackgroundTask> task = new TabBackgroundTask>(this) { - @Override - protected List doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - return musicService.getChatMessages(refresh ? 0L : lastChatMessageTime, context, this); - } - - @Override - protected void done(List result) { - if (result != null && !result.isEmpty()) { - if(refresh) { - messageList.clear(); - } - - // Reset lastChatMessageTime if we have a newer message - for (ChatMessage message : result) { - if (message.getTime() > lastChatMessageTime) { - lastChatMessageTime = message.getTime(); - } - } - - // Reverse results to show them on the bottom - Collections.reverse(result); - messageList.addAll(result); - - ChatAdapter chatAdapter = new ChatAdapter(context, messageList, getImageLoader()); - chatListView.setAdapter(chatAdapter); - } - } - }; - - task.execute(); - } - - private void sendMessage() { - final String message = messageEditText.getText().toString(); - - if (!Util.isNullOrWhiteSpace(message)) { - messageEditText.setText(""); - InputMethodManager mgr = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - mgr.hideSoftInputFromWindow(messageEditText.getWindowToken(), 0); - - BackgroundTask task = new TabBackgroundTask(this) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.addChatMessage(message, context, this); - return null; - } - - @Override - protected void done(Void result) { - load(false); - } - }; - - task.execute(); - } - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/fragments/DownloadFragment.java b/src/github/daneren2005/dsub/fragments/DownloadFragment.java deleted file mode 100644 index 24c9d303..00000000 --- a/src/github/daneren2005/dsub/fragments/DownloadFragment.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.fragments; - -import android.content.DialogInterface; -import android.os.Handler; -import android.view.ContextMenu; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.DownloadFileAdapter; - -public class DownloadFragment extends SelectListFragment { - private long currentRevision; - private ScheduledExecutorService executorService; - - public DownloadFragment() { - serialize = false; - } - - @Override - public void onResume() { - super.onResume(); - - final Handler handler = new Handler(); - Runnable runnable = new Runnable() { - @Override - public void run() { - handler.post(new Runnable() { - @Override - public void run() { - update(); - } - }); - } - }; - - executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS); - } - - @Override - public void onPause() { - super.onPause(); - executorService.shutdown(); - } - - @Override - public int getOptionsMenu() { - return R.menu.downloading; - } - - @Override - public ArrayAdapter getAdapter(List objs) { - return new DownloadFileAdapter(context, objs); - } - - @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - DownloadService downloadService = getDownloadService(); - if(downloadService == null) { - return new ArrayList(); - } - - listView.setOnScrollListener(null); - refreshLayout.setEnabled(false); - - List songList = new ArrayList(); - songList.addAll(downloadService.getBackgroundDownloads()); - currentRevision = downloadService.getDownloadListUpdateRevision(); - return songList; - } - - @Override - public int getTitleResource() { - return R.string.button_bar_downloading; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - - } - - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - if(super.onOptionsItemSelected(menuItem)) { - return true; - } - - switch (menuItem.getItemId()) { - case R.id.menu_remove_all: - Util.confirmDialog(context, R.string.download_menu_remove_all, "", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().clearBackground(); - return null; - } - - @Override - protected void done(Void result) { - update(); - } - }.execute(); - } - }); - return true; - } - - return false; - } - - @Override - public void onCreateContextMenu(android.view.ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object selectedItem = ((DownloadFile) listView.getItemAtPosition(info.position)).getSong(); - onCreateContextMenu(menu, view, menuInfo, selectedItem); - if(selectedItem instanceof MusicDirectory.Entry && !((MusicDirectory.Entry) selectedItem).isVideo() && !Util.isOffline(context)) { - menu.removeItem(R.id.song_menu_remove_playlist); - } - - recreateContextMenu(menu); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Object selectedItem = ((DownloadFile) listView.getItemAtPosition(info.position)).getSong(); - - if(onContextItemSelected(menuItem, selectedItem)) { - return true; - } - - return true; - } - - private void update() { - DownloadService downloadService = getDownloadService(); - if (downloadService == null || objects == null || adapter == null) { - return; - } - - if (currentRevision != downloadService.getDownloadListUpdateRevision()) { - List downloadFileList = downloadService.getBackgroundDownloads(); - objects.clear(); - objects.addAll(downloadFileList); - adapter.notifyDataSetChanged(); - - currentRevision = downloadService.getDownloadListUpdateRevision(); - } - } -} diff --git a/src/github/daneren2005/dsub/fragments/EqualizerFragment.java b/src/github/daneren2005/dsub/fragments/EqualizerFragment.java deleted file mode 100644 index d957b745..00000000 --- a/src/github/daneren2005/dsub/fragments/EqualizerFragment.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.fragments; - -import android.content.SharedPreferences; -import android.media.audiofx.BassBoost; -import android.media.audiofx.Equalizer; -import android.os.Bundle; -import android.util.Log; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.LinearLayout; -import android.widget.SeekBar; -import android.widget.TextView; - -import java.util.HashMap; -import java.util.Map; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.audiofx.EqualizerController; -import github.daneren2005.dsub.audiofx.LoudnessEnhancerController; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; - -/** - * Created by Scott on 10/27/13. - */ -public class EqualizerFragment extends SubsonicFragment { - private static final String TAG = EqualizerFragment.class.getSimpleName(); - - private static final int MENU_GROUP_PRESET = 100; - - private final Map bars = new HashMap(); - private SeekBar bassBar; - private SeekBar loudnessBar; - private EqualizerController equalizerController; - private Equalizer equalizer; - private BassBoost bass; - private LoudnessEnhancerController loudnessEnhancer; - private short masterLevel = 0; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - rootView = inflater.inflate(R.layout.equalizer, container, false); - - try { - DownloadService service = DownloadService.getInstance(); - equalizerController = service.getEqualizerController(); - equalizer = equalizerController.getEqualizer(); - bass = equalizerController.getBassBoost(); - loudnessEnhancer = equalizerController.getLoudnessEnhancerController(); - - initEqualizer(); - } catch(Exception e) { - Log.e(TAG, "Failed to initialize EQ", e); - Util.toast(context, "Failed to initialize EQ"); - context.onBackPressed(); - } - - final View presetButton = rootView.findViewById(R.id.equalizer_preset); - registerForContextMenu(presetButton); - presetButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - presetButton.showContextMenu(); - } - }); - - CheckBox enabledCheckBox = (CheckBox) rootView.findViewById(R.id.equalizer_enabled); - enabledCheckBox.setChecked(equalizer.getEnabled()); - enabledCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean b) { - try { - setEqualizerEnabled(b); - } catch(Exception e) { - Log.e(TAG, "Failed to set EQ enabled", e); - Util.toast(context, "Failed to set EQ enabled"); - context.onBackPressed(); - } - } - }); - - setTitle(R.string.equalizer_label); - - return rootView; - } - - @Override - public void onPause() { - super.onPause(); - equalizerController.saveSettings(); - - if(!equalizer.getEnabled()) { - equalizerController.release(); - } - } - - @Override - public void onResume() { - super.onResume(); - equalizerController = DownloadService.getInstance().getEqualizerController(); - equalizer = equalizerController.getEqualizer(); - bass = equalizerController.getBassBoost(); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - if(!primaryFragment) { - return; - } - - short currentPreset; - try { - currentPreset = equalizer.getCurrentPreset(); - } catch (Exception x) { - currentPreset = -1; - } - - for (short preset = 0; preset < equalizer.getNumberOfPresets(); preset++) { - MenuItem menuItem = menu.add(MENU_GROUP_PRESET, preset, preset, equalizer.getPresetName(preset)); - if (preset == currentPreset) { - menuItem.setChecked(true); - } - } - menu.setGroupCheckable(MENU_GROUP_PRESET, true, true); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - short preset = (short) menuItem.getItemId(); - for(int i = 0; i < 10; i++) { - try { - equalizer.usePreset(preset); - i = 10; - } catch (UnsupportedOperationException e) { - equalizerController.release(); - equalizer = equalizerController.getEqualizer(); - bass = equalizerController.getBassBoost(); - loudnessEnhancer = equalizerController.getLoudnessEnhancerController(); - } - } - updateBars(false); - return true; - } - - private void setEqualizerEnabled(boolean enabled) { - SharedPreferences prefs = Util.getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(Constants.PREFERENCES_EQUALIZER_ON, enabled); - editor.commit(); - for(int i = 0; i < 10; i++) { - try { - equalizer.setEnabled(enabled); - updateBars(true); - i = 10; - } catch (UnsupportedOperationException e) { - equalizerController.release(); - equalizer = equalizerController.getEqualizer(); - bass = equalizerController.getBassBoost(); - loudnessEnhancer = equalizerController.getLoudnessEnhancerController(); - } - } - } - - private void updateBars(boolean changedEnabled) { - boolean isEnabled = equalizer.getEnabled(); - short minEQLevel = equalizer.getBandLevelRange()[0]; - short maxEQLevel = equalizer.getBandLevelRange()[1]; - for (Map.Entry entry : bars.entrySet()) { - short band = entry.getKey(); - SeekBar bar = entry.getValue(); - bar.setEnabled(isEnabled); - if(band >= (short)0) { - short setLevel; - if(changedEnabled) { - setLevel = (short)(equalizer.getBandLevel(band) - masterLevel); - if(isEnabled) { - bar.setProgress(equalizer.getBandLevel(band) - minEQLevel); - } else { - bar.setProgress(-minEQLevel); - } - } else { - bar.setProgress(equalizer.getBandLevel(band) - minEQLevel); - setLevel = (short)(equalizer.getBandLevel(band) + masterLevel); - } - if(setLevel < minEQLevel) { - setLevel = minEQLevel; - } else if(setLevel > maxEQLevel) { - setLevel = maxEQLevel; - } - equalizer.setBandLevel(band, setLevel); - } else if(!isEnabled) { - bar.setProgress(-minEQLevel); - } - } - - bassBar.setEnabled(isEnabled); - if(loudnessBar != null) { - loudnessBar.setEnabled(isEnabled); - } - if(changedEnabled && !isEnabled) { - bass.setStrength((short) 0); - bassBar.setProgress(0); - if(loudnessBar != null) { - loudnessEnhancer.setGain(0); - loudnessBar.setProgress(0); - } - } - - if(!isEnabled) { - masterLevel = 0; - SharedPreferences prefs = Util.getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel); - editor.commit(); - } - } - - private void initEqualizer() { - LinearLayout layout = (LinearLayout) rootView.findViewById(R.id.equalizer_layout); - - final short minEQLevel = equalizer.getBandLevelRange()[0]; - final short maxEQLevel = equalizer.getBandLevelRange()[1]; - - // Setup Pregain - SharedPreferences prefs = Util.getPreferences(context); - masterLevel = (short)prefs.getInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, 0); - initPregain(layout, minEQLevel, maxEQLevel); - - for (short i = 0; i < equalizer.getNumberOfBands(); i++) { - final short band = i; - - View bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null); - TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency); - final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); - SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); - - freqTextView.setText((equalizer.getCenterFreq(band) / 1000) + " Hz"); - - bars.put(band, bar); - bar.setMax(maxEQLevel - minEQLevel); - short level = equalizer.getBandLevel(band); - if(equalizer.getEnabled()) { - level = (short) (level - masterLevel); - } - bar.setProgress(level - minEQLevel); - bar.setEnabled(equalizer.getEnabled()); - updateLevelText(levelTextView, level); - - bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - short level = (short) (progress + minEQLevel); - if (fromUser) { - equalizer.setBandLevel(band, (short)(level + masterLevel)); - } - updateLevelText(levelTextView, level); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } - }); - layout.addView(bandBar); - } - - LinearLayout specialLayout = (LinearLayout) rootView.findViewById(R.id.special_effects_layout); - - // Setup bass booster - View bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null); - TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency); - final TextView bassTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); - bassBar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); - - freqTextView.setText(R.string.equalizer_bass_booster); - bassBar.setEnabled(equalizer.getEnabled()); - short bassLevel = 0; - if(bass.getEnabled()) { - bassLevel = bass.getRoundedStrength(); - } - bassTextView.setText(context.getResources().getString(R.string.equalizer_bass_size, bassLevel)); - bassBar.setMax(1000); - bassBar.setProgress(bassLevel); - bassBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - try { - bassTextView.setText(context.getResources().getString(R.string.equalizer_bass_size, progress)); - if (fromUser) { - if (progress > 0) { - if (!bass.getEnabled()) { - bass.setEnabled(true); - } - bass.setStrength((short) progress); - } else if (progress == 0 && bass.getEnabled()) { - bass.setStrength((short) progress); - bass.setEnabled(false); - } - } - } catch(Exception e) { - Log.w(TAG, "Error on changing bass: ", e); - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - - } - }); - specialLayout.addView(bandBar); - - if(loudnessEnhancer != null && loudnessEnhancer.isAvailable()) { - // Setup loudness enhancer - bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null); - freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency); - final TextView loudnessTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); - loudnessBar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); - - freqTextView.setText(R.string.equalizer_voice_booster); - loudnessBar.setEnabled(equalizer.getEnabled()); - int loudnessLevel = 0; - if(loudnessEnhancer.isEnabled()) { - loudnessLevel = (int) loudnessEnhancer.getGain(); - } - loudnessBar.setProgress(loudnessLevel / 100); - loudnessTextView.setText(context.getResources().getString(R.string.equalizer_db_size, loudnessLevel / 100)); - loudnessBar.setMax(15); - loudnessBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - try { - loudnessTextView.setText(context.getResources().getString(R.string.equalizer_db_size, progress)); - if(fromUser) { - if(progress > 0) { - if(!loudnessEnhancer.isEnabled()) { - loudnessEnhancer.enable(); - } - loudnessEnhancer.setGain(progress * 100); - } else if(progress == 0 && loudnessEnhancer.isEnabled()) { - loudnessEnhancer.setGain(progress * 100); - loudnessEnhancer.disable(); - } - } - } catch(Exception e) { - Log.w(TAG, "Error on changing loudness: ", e); - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - - } - }); - specialLayout.addView(bandBar); - } - } - - private void initPregain(LinearLayout layout, final short minEQLevel, final short maxEQLevel) { - View bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null); - TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency); - final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); - SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); - - freqTextView.setText("Master"); - - bars.put((short)-1, bar); - bar.setMax(maxEQLevel - minEQLevel); - bar.setProgress(masterLevel - minEQLevel); - bar.setEnabled(equalizer.getEnabled()); - updateLevelText(levelTextView, masterLevel); - - bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - masterLevel = (short) (progress + minEQLevel); - if (fromUser) { - SharedPreferences prefs = Util.getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel); - editor.commit(); - for (short i = 0; i < equalizer.getNumberOfBands(); i++) { - short level = (short) ((bars.get(i).getProgress() + minEQLevel) + masterLevel); - equalizer.setBandLevel(i, level); - } - } - updateLevelText(levelTextView, masterLevel); - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } - }); - layout.addView(bandBar); - } - - private void updateLevelText(TextView levelTextView, short level) { - levelTextView.setText((level > 0 ? "+" : "") + context.getResources().getString(R.string.equalizer_db_size, level / 100)); - } -} diff --git a/src/github/daneren2005/dsub/fragments/LyricsFragment.java b/src/github/daneren2005/dsub/fragments/LyricsFragment.java deleted file mode 100644 index 826029f5..00000000 --- a/src/github/daneren2005/dsub/fragments/LyricsFragment.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.fragments; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Lyrics; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.BackgroundTask; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.TabBackgroundTask; - -/** - * Displays song lyrics. - * - * @author Sindre Mehus - */ -public final class LyricsFragment extends SubsonicFragment { - private TextView artistView; - private TextView titleView; - private TextView textView; - - private Lyrics lyrics; - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - - if(bundle != null) { - lyrics = (Lyrics) bundle.getSerializable(Constants.FRAGMENT_LIST); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable(Constants.FRAGMENT_LIST, lyrics); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - setTitle(R.string.download_menu_lyrics); - rootView = inflater.inflate(R.layout.lyrics, container, false); - artistView = (TextView) rootView.findViewById(R.id.lyrics_artist); - titleView = (TextView) rootView.findViewById(R.id.lyrics_title); - textView = (TextView) rootView.findViewById(R.id.lyrics_text); - - if(lyrics == null) { - load(); - } else { - setLyrics(); - } - - return rootView; - } - - private void load() { - BackgroundTask task = new TabBackgroundTask(this) { - @Override - protected Lyrics doInBackground() throws Throwable { - String artist = getArguments().getString(Constants.INTENT_EXTRA_NAME_ARTIST); - String title = getArguments().getString(Constants.INTENT_EXTRA_NAME_TITLE); - MusicService musicService = MusicServiceFactory.getMusicService(context); - return musicService.getLyrics(artist, title, context, this); - } - - @Override - protected void done(Lyrics result) { - lyrics = result; - setLyrics(); - } - }; - task.execute(); - } - - private void setLyrics() { - if (lyrics != null && lyrics.getArtist() != null) { - artistView.setText(lyrics.getArtist()); - titleView.setText(lyrics.getTitle()); - textView.setText(lyrics.getText()); - } else { - artistView.setText(R.string.lyrics_nomatch); - } - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/fragments/MainFragment.java b/src/github/daneren2005/dsub/fragments/MainFragment.java deleted file mode 100644 index ce488aff..00000000 --- a/src/github/daneren2005/dsub/fragments/MainFragment.java +++ /dev/null @@ -1,586 +0,0 @@ -package github.daneren2005.dsub.fragments; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.StatFs; -import android.util.Log; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.ListView; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.LoadingTask; -import github.daneren2005.dsub.util.Pair; -import github.daneren2005.dsub.util.UserUtil; -import github.daneren2005.dsub.adapter.MergeAdapter; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.view.ChangeLog; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class MainFragment extends SubsonicFragment { - private static final String TAG = MainFragment.class.getSimpleName(); - private LayoutInflater inflater; - private TextView countView; - - private static final int MENU_GROUP_SERVER = 10; - private static final int MENU_ITEM_SERVER_BASE = 100; - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - this.inflater = inflater; - rootView = inflater.inflate(R.layout.home, container, false); - - createLayout(); - - return rootView; - } - - @Override - public void onResume() { - super.onResume(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - menuInflater.inflate(R.menu.main, menu); - - try { - if (!ServerInfo.isMadsonic(context) || !UserUtil.isCurrentAdmin()) { - menu.setGroupVisible(R.id.madsonic, false); - } - } catch(Exception e) { - Log.w(TAG, "Error on setting madsonic invisible", e); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(super.onOptionsItemSelected(item)) { - return true; - } - - switch (item.getItemId()) { - case R.id.menu_log: - getLogs(); - return true; - case R.id.menu_about: - showAboutDialog(); - return true; - case R.id.menu_changelog: - ChangeLog changeLog = new ChangeLog(context, Util.getPreferences(context)); - changeLog.getFullLogDialog().show(); - return true; - case R.id.menu_faq: - showFAQDialog(); - return true; - case R.id.menu_rescan: - rescanServer(); - return true; - } - - return false; - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - int serverCount = Util.getServerCount(context); - int activeServer = Util.getActiveServer(context); - for(int i = 1; i <= serverCount; i++) { - android.view.MenuItem menuItem = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_BASE + i, MENU_ITEM_SERVER_BASE + i, Util.getServerName(context, i)); - if(i == activeServer) { - menuItem.setChecked(true); - } - } - menu.setGroupCheckable(MENU_GROUP_SERVER, true, true); - menu.setHeaderTitle(R.string.main_select_server); - - recreateContextMenu(menu); - } - - @Override - public boolean onContextItemSelected(android.view.MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - int activeServer = menuItem.getItemId() - MENU_ITEM_SERVER_BASE; - setActiveServer(activeServer); - return true; - } - - @Override - protected void refresh(boolean refresh) { - createLayout(); - } - - private void createLayout() { - View buttons = inflater.inflate(R.layout.main_buttons, null); - - final View serverButton = buttons.findViewById(R.id.main_select_server); - final TextView serverTextView = (TextView) serverButton.findViewById(R.id.main_select_server_2); - final TextView offlineButton = (TextView) buttons.findViewById(R.id.main_offline); - offlineButton.setText(Util.isOffline(context) ? R.string.main_online : R.string.main_offline); - - final View albumsTitle = buttons.findViewById(R.id.main_albums); - final View videoTitle = buttons.findViewById(R.id.main_video_section); - final View albumsNewestButton = buttons.findViewById(R.id.main_albums_newest); - countView = (TextView) buttons.findViewById(R.id.main_albums_recent_count); - final View albumsRandomButton = buttons.findViewById(R.id.main_albums_random); - final View albumsHighestButton = buttons.findViewById(R.id.main_albums_highest); - final View albumsRecentButton = buttons.findViewById(R.id.main_albums_recent); - final View albumsFrequentButton = buttons.findViewById(R.id.main_albums_frequent); - final View albumsStarredButton = buttons.findViewById(R.id.main_albums_starred); - final View albumsGenresButton = buttons.findViewById(R.id.main_albums_genres); - final View albumsYearButton = buttons.findViewById(R.id.main_albums_year); - final View albumsAlphabeticalButton = buttons.findViewById(R.id.main_albums_alphabetical); - final View videosButton = buttons.findViewById(R.id.main_videos); - - final View dummyView = rootView.findViewById(R.id.main_dummy); - - final CheckBox albumsPerFolderCheckbox = (CheckBox) buttons.findViewById(R.id.main_albums_per_folder); - if(!Util.isOffline(context) && ServerInfo.canAlbumListPerFolder(context)) { - albumsPerFolderCheckbox.setChecked(Util.getAlbumListsPerFolder(context)); - albumsPerFolderCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - Util.setAlbumListsPerFolder(context, isChecked); - } - }); - } else { - albumsPerFolderCheckbox.setVisibility(View.GONE); - } - - int instance = Util.getActiveServer(context); - String name = Util.getServerName(context, instance); - serverTextView.setText(name); - - ListView list = (ListView) rootView.findViewById(R.id.main_list); - - MergeAdapter adapter = new MergeAdapter(); - if (!Util.isOffline(context)) { - adapter.addViews(Arrays.asList(serverButton), true); - } - adapter.addView(offlineButton, true); - if (!Util.isOffline(context)) { - adapter.addView(albumsTitle, false); - adapter.addViews(Arrays.asList(albumsNewestButton, albumsRandomButton), true); - if(ServerInfo.checkServerVersion(context, "1.8")) { - adapter.addView(albumsAlphabeticalButton, true); - } - if(!Util.isTagBrowsing(context)) { - adapter.addView(albumsHighestButton, true); - } - adapter.addViews(Arrays.asList(albumsStarredButton, albumsGenresButton, albumsYearButton, albumsRecentButton, albumsFrequentButton), true); - if(ServerInfo.checkServerVersion(context, "1.8") && !Util.isTagBrowsing(context)) { - adapter.addView(videoTitle, false); - adapter.addView(videosButton, true); - } - } - list.setAdapter(adapter); - registerForContextMenu(dummyView); - - list.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (view == serverButton) { - dummyView.showContextMenu(); - } else if (view == offlineButton) { - toggleOffline(); - } else if (view == albumsNewestButton) { - showAlbumList("newest"); - } else if (view == albumsRandomButton) { - showAlbumList("random"); - } else if (view == albumsHighestButton) { - showAlbumList("highest"); - } else if (view == albumsRecentButton) { - showAlbumList("recent"); - } else if (view == albumsFrequentButton) { - showAlbumList("frequent"); - } else if (view == albumsStarredButton) { - showAlbumList("starred"); - } else if(view == albumsGenresButton) { - showAlbumList("genres"); - } else if(view == albumsYearButton) { - showAlbumList("years"); - } else if(view == albumsAlphabeticalButton) { - showAlbumList("alphabeticalByName"); - } else if(view == videosButton) { - showVideos(); - } - } - }); - setTitle(R.string.common_appname); - - if(!Util.isOffline(context)) { - getMostRecentCount(); - } - } - - private void setActiveServer(int instance) { - if (Util.getActiveServer(context) != instance) { - final DownloadService service = getDownloadService(); - if (service != null) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - service.clearIncomplete(); - return null; - } - }.execute(); - - } - Util.setActiveServer(context, instance); - context.invalidate(); - UserUtil.refreshCurrentUser(context, false, true); - } - } - - private void toggleOffline() { - boolean isOffline = Util.isOffline(context); - Util.setOffline(context, !isOffline); - context.invalidate(); - DownloadService service = getDownloadService(); - if (service != null) { - service.setOnline(isOffline); - } - - // Coming back online - if(isOffline) { - int scrobblesCount = Util.offlineScrobblesCount(context); - int starsCount = Util.offlineStarsCount(context); - if(scrobblesCount > 0 || starsCount > 0){ - showOfflineSyncDialog(scrobblesCount, starsCount); - } - } - - UserUtil.seedCurrentUser(context); - } - - private void showAlbumList(String type) { - if("genres".equals(type)) { - SubsonicFragment fragment = new SelectGenreFragment(); - replaceFragment(fragment); - } else if("years".equals(type)) { - SubsonicFragment fragment = new SelectYearFragment(); - replaceFragment(fragment); - } else { - // Clear out recently added count when viewing - if("newest".equals(type)) { - SharedPreferences.Editor editor = Util.getPreferences(context).edit(); - editor.putInt(Constants.PREFERENCES_KEY_RECENT_COUNT + Util.getActiveServer(context), 0); - editor.commit(); - - // Clear immediately so doesn't still show when pressing back - setMostRecentCount(0); - } - - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type); - args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); - args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); - fragment.setArguments(args); - - replaceFragment(fragment); - } - } - private void showVideos() { - SubsonicFragment fragment = new SelectVideoFragment(); - replaceFragment(fragment); - } - - private void showOfflineSyncDialog(final int scrobbleCount, final int starsCount) { - String syncDefault = Util.getSyncDefault(context); - if(syncDefault != null) { - if("sync".equals(syncDefault)) { - syncOffline(scrobbleCount, starsCount); - return; - } else if("delete".equals(syncDefault)) { - deleteOffline(); - return; - } - } - - View checkBoxView = context.getLayoutInflater().inflate(R.layout.sync_dialog, null); - final CheckBox checkBox = (CheckBox)checkBoxView.findViewById(R.id.sync_default); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setIcon(android.R.drawable.ic_dialog_info) - .setTitle(R.string.offline_sync_dialog_title) - .setMessage(context.getResources().getString(R.string.offline_sync_dialog_message, scrobbleCount, starsCount)) - .setView(checkBoxView) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if(checkBox.isChecked()) { - Util.setSyncDefault(context, "sync"); - } - syncOffline(scrobbleCount, starsCount); - } - }).setNeutralButton(R.string.common_cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.dismiss(); - } - }).setNegativeButton(R.string.common_delete, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if(checkBox.isChecked()) { - Util.setSyncDefault(context, "delete"); - } - deleteOffline(); - } - }); - - builder.create().show(); - } - - private void syncOffline(final int scrobbleCount, final int starsCount) { - new SilentBackgroundTask(context) { - @Override - protected Integer doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - return musicService.processOfflineSyncs(context, null); - } - - @Override - protected void done(Integer result) { - if(result == scrobbleCount) { - Util.toast(context, context.getResources().getString(R.string.offline_sync_success, result)); - } else { - Util.toast(context, context.getResources().getString(R.string.offline_sync_partial, result, scrobbleCount + starsCount)); - } - } - - @Override - protected void error(Throwable error) { - Log.w(TAG, "Failed to sync offline stats", error); - String msg = context.getResources().getString(R.string.offline_sync_error) + " " + getErrorMessage(error); - Util.toast(context, msg); - } - }.execute(); - } - private void deleteOffline() { - SharedPreferences.Editor offline = Util.getOfflineSync(context).edit(); - offline.putInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); - offline.putInt(Constants.OFFLINE_STAR_COUNT, 0); - offline.commit(); - } - - private void showAboutDialog() { - new LoadingTask(context) { - @Override - protected String doInBackground() throws Throwable { - File rootFolder = FileUtil.getMusicDirectory(context); - StatFs stat = new StatFs(rootFolder.getPath()); - long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize(); - long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize(); - - Pair used = FileUtil.getUsedSize(context, rootFolder); - - return getResources().getString(R.string.main_about_text, - context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName, - used.getFirst(), - Util.formatLocalizedBytes(used.getSecond(), context), - Util.formatLocalizedBytes(Util.getCacheSizeMB(context) * 1024L * 1024L, context), - Util.formatLocalizedBytes(bytesAvailableFs, context), - Util.formatLocalizedBytes(bytesTotalFs, context)); - } - - @Override - protected void done(String msg) { - try { - Util.info(context, R.string.main_about_title, msg); - } catch(Exception e) { - Util.toast(context, "Failed to open dialog"); - } - } - }.execute(); - } - - private void showFAQDialog() { - Util.showHTMLDialog(context, R.string.main_faq_title, R.string.main_faq_text); - } - - private void rescanServer() { - new LoadingTask(context, false) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.startRescan(context, this); - return null; - } - - @Override - protected void done(Void value) { - Util.toast(context, R.string.main_scan_complete); - } - }.execute(); - } - - private void getLogs() { - try { - final String version = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; - new LoadingTask(context) { - @Override - protected File doInBackground() throws Throwable { - updateProgress("Gathering Logs"); - File logcat = new File(FileUtil.getSubsonicDirectory(context), "logcat.txt"); - Util.delete(logcat); - Process logcatProc = null; - - try { - List progs = new ArrayList(); - progs.add("logcat"); - progs.add("-v"); - progs.add("time"); - progs.add("-d"); - progs.add("-f"); - progs.add(logcat.getCanonicalPath()); - progs.add("*:I"); - - logcatProc = Runtime.getRuntime().exec(progs.toArray(new String[progs.size()])); - logcatProc.waitFor(); - } catch(Exception e) { - Util.toast(context, "Failed to gather logs"); - } finally { - if(logcatProc != null) { - logcatProc.destroy(); - } - } - - return logcat; - } - - @Override - protected void done(File logcat) { - String footer = "Android SDK: " + Build.VERSION.SDK; - footer += "\nDevice Model: " + Build.MODEL; - footer += "\nDevice Name: " + Build.MANUFACTURER + " " + Build.PRODUCT; - footer += "\nROM: " + Build.DISPLAY; - - Intent email = new Intent(Intent.ACTION_SENDTO, - Uri.fromParts("mailto", "dsub.android@gmail.com", null)); - email.putExtra(Intent.EXTRA_SUBJECT, "DSub " + version + " Error Logs"); - email.putExtra(Intent.EXTRA_TEXT, "Describe the problem here\n\n\n" + footer); - Uri attachment = Uri.fromFile(logcat); - email.putExtra(Intent.EXTRA_STREAM, attachment); - startActivity(email); - } - }.execute(); - } catch(Exception e) {} - } - - private void getMostRecentCount() { - // Use stashed value until after refresh occurs - SharedPreferences prefs = Util.getPreferences(context); - final int startCount = prefs.getInt(Constants.PREFERENCES_KEY_RECENT_COUNT + Util.getActiveServer(context), 0); - setMostRecentCount(startCount); - - new SilentBackgroundTask(context) { - @Override - public Integer doInBackground() throws Exception { - String recentAddedFile = Util.getCacheName(context, "recent_count"); - ArrayList recents = FileUtil.deserialize(context, recentAddedFile, ArrayList.class); - if(recents == null) { - recents = new ArrayList(); - } - - MusicService musicService = MusicServiceFactory.getMusicService(context); - MusicDirectory recentlyAdded = musicService.getAlbumList("newest", 20, 0, context, null); - - // If first run, just put everything in it and return 0 - boolean firstRun = recents.isEmpty(); - - // Count how many new albums are in the list - int count = 0; - for(MusicDirectory.Entry album: recentlyAdded.getChildren()) { - if(!recents.contains(album.getId())) { - recents.add(album.getId()); - count++; - } - } - - // Keep recents list from growing infinitely - while(recents.size() > 40) { - recents.remove(0); - } - FileUtil.serialize(context, recents, recentAddedFile); - - if(firstRun) { - return 0; - } else { - // Add the old count which will get cleared out after viewing recents - count += startCount; - SharedPreferences.Editor editor = Util.getPreferences(context).edit(); - editor.putInt(Constants.PREFERENCES_KEY_RECENT_COUNT + Util.getActiveServer(context), count); - editor.commit(); - - return count; - } - } - - @Override - public void done(Integer result) { - setMostRecentCount(result); - } - - @Override - public void error(Throwable x) { - Log.w(TAG, "Failed to refresh most recent count", x); - } - }.execute(); - } - - private void setMostRecentCount(int count) { - if(count <= 0) { - countView.setVisibility(View.GONE); - } else { - String displayValue; - if(count < 10) { - displayValue = "0" + count; - } else { - displayValue = "" + count; - } - - countView.setText(displayValue); - countView.setVisibility(View.VISIBLE); - } - } -} diff --git a/src/github/daneren2005/dsub/fragments/NowPlayingFragment.java b/src/github/daneren2005/dsub/fragments/NowPlayingFragment.java deleted file mode 100644 index 4a720ead..00000000 --- a/src/github/daneren2005/dsub/fragments/NowPlayingFragment.java +++ /dev/null @@ -1,1568 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ -package github.daneren2005.dsub.fragments; - -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.Configuration; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.support.v4.view.MenuItemCompat; -import android.support.v7.app.MediaRouteButton; -import android.util.Log; -import android.view.ContextMenu; -import android.view.Display; -import android.view.GestureDetector; -import android.view.GestureDetector.OnGestureListener; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.view.animation.AnimationUtils; -import android.widget.AdapterView; -import android.widget.EditText; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.SeekBar; -import android.widget.TextView; -import android.widget.ViewFlipper; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.SubsonicFragmentActivity; -import github.daneren2005.dsub.audiofx.EqualizerController; -import github.daneren2005.dsub.domain.Bookmark; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.domain.RepeatMode; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.service.OfflineException; -import github.daneren2005.dsub.service.ServerTooOldException; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.adapter.DownloadFileAdapter; -import github.daneren2005.dsub.view.FadeOutAnimation; -import github.daneren2005.dsub.view.UpdateView; -import github.daneren2005.dsub.util.Util; - -import static github.daneren2005.dsub.domain.MusicDirectory.Entry; -import static github.daneren2005.dsub.domain.PlayerState.*; -import github.daneren2005.dsub.util.*; -import github.daneren2005.dsub.view.AutoRepeatButton; -import java.util.ArrayList; -import java.util.concurrent.ScheduledFuture; -import com.mobeta.android.dslv.*; -import github.daneren2005.dsub.activity.SubsonicActivity; - -public class NowPlayingFragment extends SubsonicFragment implements OnGestureListener { - private static final String TAG = NowPlayingFragment.class.getSimpleName(); - private static final int PERCENTAGE_OF_SCREEN_FOR_SWIPE = 10; - private static final int INCREMENT_TIME = 5000; - private static final int SERVICE_BACKOFF = 200; - - private static final int ACTION_PREVIOUS = 1; - private static final int ACTION_NEXT = 2; - private static final int ACTION_REWIND = 3; - private static final int ACTION_FORWARD = 4; - - private ViewFlipper playlistFlipper; - private TextView emptyTextView; - private TextView songTitleTextView; - private ImageView albumArtImageView; - private DragSortListView playlistView; - private TextView positionTextView; - private TextView durationTextView; - private TextView statusTextView; - private SeekBar progressBar; - private AutoRepeatButton previousButton; - private AutoRepeatButton nextButton; - private View pauseButton; - private View stopButton; - private View startButton; - private ImageButton repeatButton; - private View toggleListButton; - private ImageButton starButton; - private ImageButton bookmarkButton; - private ImageButton rateBadButton; - private ImageButton rateGoodButton; - private View mainLayout; - private ScheduledExecutorService executorService; - private DownloadFile currentPlaying; - private long currentRevision; - private int swipeDistance; - private int swipeVelocity; - private ScheduledFuture hideControlsFuture; - private List songList; - private DownloadFileAdapter songListAdapter; - private SilentBackgroundTask onProgressChangedTask; - private SilentBackgroundTask onCurrentChangedTask; - private SilentBackgroundTask onDownloadListChangedTask; - private boolean seekInProgress = false; - private boolean startFlipped = false; - private boolean scrollWhenLoaded = false; - private int lastY = 0; - - /** - * Called when the activity is first created. - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if(savedInstanceState != null) { - if(savedInstanceState.getInt(Constants.FRAGMENT_DOWNLOAD_FLIPPER) == 1) { - startFlipped = true; - } - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putInt(Constants.FRAGMENT_DOWNLOAD_FLIPPER, playlistFlipper.getDisplayedChild()); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - rootView = inflater.inflate(R.layout.download, container, false); - setTitle(R.string.button_bar_now_playing); - - mainLayout = rootView.findViewById(R.id.download_layout); - if(!primaryFragment) { - mainLayout.setVisibility(View.GONE); - } - - WindowManager w = context.getWindowManager(); - Display d = w.getDefaultDisplay(); - swipeDistance = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100; - swipeVelocity = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100; - gestureScanner = new GestureDetector(this); - - playlistFlipper = (ViewFlipper)rootView.findViewById(R.id.download_playlist_flipper); - emptyTextView = (TextView)rootView.findViewById(R.id.download_empty); - songTitleTextView = (TextView)rootView.findViewById(R.id.download_song_title); - albumArtImageView = (ImageView)rootView.findViewById(R.id.download_album_art_image); - positionTextView = (TextView)rootView.findViewById(R.id.download_position); - durationTextView = (TextView)rootView.findViewById(R.id.download_duration); - statusTextView = (TextView)rootView.findViewById(R.id.download_status); - progressBar = (SeekBar)rootView.findViewById(R.id.download_progress_bar); - playlistView = (DragSortListView)rootView.findViewById(R.id.download_list); - previousButton = (AutoRepeatButton)rootView.findViewById(R.id.download_previous); - nextButton = (AutoRepeatButton)rootView.findViewById(R.id.download_next); - pauseButton =rootView.findViewById(R.id.download_pause); - stopButton =rootView.findViewById(R.id.download_stop); - startButton =rootView.findViewById(R.id.download_start); - repeatButton = (ImageButton)rootView.findViewById(R.id.download_repeat); - bookmarkButton = (ImageButton) rootView.findViewById(R.id.download_bookmark); - rateBadButton = (ImageButton) rootView.findViewById(R.id.download_rating_bad); - rateGoodButton = (ImageButton) rootView.findViewById(R.id.download_rating_good); - toggleListButton =rootView.findViewById(R.id.download_toggle_list); - - starButton = (ImageButton)rootView.findViewById(R.id.download_star); - if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_MENU_STAR, true)) { - starButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - DownloadFile currentDownload = getDownloadService().getCurrentPlaying(); - if (currentDownload != null) { - final Entry currentSong = currentDownload.getSong(); - toggleStarred(currentSong, new OnStarChange() { - @Override - void starChange(boolean starred) { - starButton.setImageResource(currentSong.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); - } - }); - } - } - }); - } else { - starButton.setVisibility(View.GONE); - } - - View.OnTouchListener touchListener = new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent me) { - return gestureScanner.onTouchEvent(me); - } - }; - pauseButton.setOnTouchListener(touchListener); - stopButton.setOnTouchListener(touchListener); - startButton.setOnTouchListener(touchListener); - bookmarkButton.setOnTouchListener(touchListener); - rateBadButton.setOnTouchListener(touchListener); - rateGoodButton.setOnTouchListener(touchListener); - emptyTextView.setOnTouchListener(touchListener); - albumArtImageView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent me) { - if(me.getAction() == MotionEvent.ACTION_DOWN) { - lastY = (int) me.getRawY(); - } - return gestureScanner.onTouchEvent(me); - } - }); - - previousButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - warnIfStorageUnavailable(); - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().previous(); - return null; - } - - @Override - protected void done(Void result) { - onCurrentChanged(); - onProgressChanged(); - } - }.execute(); - setControlsVisible(true); - } - }); - previousButton.setOnRepeatListener(new Runnable() { - public void run() { - changeProgress(-INCREMENT_TIME); - } - }); - - nextButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - warnIfStorageUnavailable(); - new SilentBackgroundTask(context) { - @Override - protected Boolean doInBackground() throws Throwable { - getDownloadService().next(); - return true; - } - - @Override - protected void done(Boolean result) { - if(result) { - onCurrentChanged(); - onProgressChanged(); - } - } - }.execute(); - setControlsVisible(true); - } - }); - nextButton.setOnRepeatListener(new Runnable() { - public void run() { - changeProgress(INCREMENT_TIME); - } - }); - - pauseButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().pause(); - return null; - } - - @Override - protected void done(Void result) { - onCurrentChanged(); - onProgressChanged(); - } - }.execute(); - } - }); - - stopButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().reset(); - return null; - } - - @Override - protected void done(Void result) { - onCurrentChanged(); - onProgressChanged(); - } - }.execute(); - } - }); - - startButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - warnIfStorageUnavailable(); - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - start(); - return null; - } - - @Override - protected void done(Void result) { - onCurrentChanged(); - onProgressChanged(); - } - }.execute(); - } - }); - - repeatButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - RepeatMode repeatMode = getDownloadService().getRepeatMode().next(); - getDownloadService().setRepeatMode(repeatMode); - onDownloadListChanged(); - switch (repeatMode) { - case OFF: - Util.toast(context, R.string.download_repeat_off); - break; - case ALL: - Util.toast(context, R.string.download_repeat_all); - break; - case SINGLE: - Util.toast(context, R.string.download_repeat_single); - break; - default: - break; - } - setControlsVisible(true); - } - }); - - bookmarkButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - createBookmark(); - } - }); - - rateBadButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - DownloadService downloadService = getDownloadService(); - if(downloadService == null) { - return; - } - - DownloadFile downloadFile = downloadService.getCurrentPlaying(); - if(downloadFile == null) { - return; - } - Entry entry = downloadFile.getSong(); - - // If rating == 1, already set so unset - if(entry.getRating() == 1) { - setRating(entry, 0); - - if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_dark); - } else { - rateBadButton.setImageResource(Util.getAttribute(context, R.attr.rating_bad)); - } - } else { - // Immediately skip to the next song - downloadService.next(true); - - // Otherwise set rating to 1 - setRating(entry, 1); - rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_selected); - - // Make sure good rating is blank - if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_dark); - } else { - rateGoodButton.setImageResource(Util.getAttribute(context, R.attr.rating_good)); - } - } - } - }); - rateGoodButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - DownloadService downloadService = getDownloadService(); - if(downloadService == null) { - return; - } - - DownloadFile downloadFile = downloadService.getCurrentPlaying(); - if(downloadFile == null) { - return; - } - Entry entry = downloadFile.getSong(); - - // If rating == 5, already set so unset - if(entry.getRating() == 5) { - setRating(entry, 0); - - if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_dark); - } else { - rateGoodButton.setImageResource(Util.getAttribute(context, R.attr.rating_good)); - } - } else { - // Otherwise set rating to maximum - setRating(entry, 5); - rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_selected); - - // Make sure bad rating is blank - if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_dark); - } else { - rateBadButton.setImageResource(Util.getAttribute(context, R.attr.rating_bad)); - } - } - } - }); - - toggleListButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - toggleFullscreenAlbumArt(); - setControlsVisible(true); - } - }); - - View overlay = rootView.findViewById(R.id.download_overlay_buttons); - final int overlayHeight = overlay != null ? overlay.getHeight() : -1; - albumArtImageView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if(overlayHeight == -1 || lastY < (view.getBottom() - overlayHeight)) { - toggleFullscreenAlbumArt(); - setControlsVisible(true); - } - } - }); - - progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onStopTrackingTouch(final SeekBar seekBar) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().seekTo(progressBar.getProgress()); - return null; - } - - @Override - protected void done(Void result) { - seekInProgress = false; - NowPlayingFragment.this.onProgressChanged(); - } - }.execute(); - } - - @Override - public void onStartTrackingTouch(final SeekBar seekBar) { - seekInProgress = true; - } - - @Override - public void onProgressChanged(final SeekBar seekBar, final int position, final boolean fromUser) { - if (fromUser) { - Util.toast(context, Util.formatDuration(position / 1000), true); - setControlsVisible(true); - } - } - }); - playlistView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, final int position, long id) { - warnIfStorageUnavailable(); - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().play(position); - return null; - } - - @Override - protected void done(Void result) { - onCurrentChanged(); - onProgressChanged(); - } - }.execute(); - } - }); - playlistView.setDropListener(new DragSortListView.DropListener() { - @Override - public void drop(final int from, final int to) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().swap(true, from, to); - onDownloadListChanged(); - - return null; - } - }.execute(); - } - }); - playlistView.setRemoveListener(new DragSortListView.RemoveListener() { - @Override - public void remove(int which) { - getDownloadService().remove(which); - onDownloadListChanged(); - } - }); - - registerForContextMenu(playlistView); - - DownloadService downloadService = getDownloadService(); - if (downloadService != null && context.getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, false)) { - context.getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE); - warnIfStorageUnavailable(); - downloadService.setShufflePlayEnabled(true); - } - - if(Build.MODEL.equals("Nexus 4") || Build.MODEL.equals("GT-I9100")) { - View slider = rootView.findViewById(R.id.download_slider); - slider.setPadding(0, 0, 0, 0); - } - - return rootView; - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - DownloadService downloadService = getDownloadService(); - if(Util.isOffline(context)) { - menuInflater.inflate(R.menu.nowplaying_offline, menu); - } else { - menuInflater.inflate(R.menu.nowplaying, menu); - - if(downloadService != null && downloadService.getSleepTimer()) { - menu.findItem(R.id.menu_toggle_timer).setTitle(R.string.download_stop_timer); - } - } - if(downloadService != null && downloadService.getKeepScreenOn()) { - menu.findItem(R.id.menu_screen_on_off).setChecked(true); - } - if(downloadService != null && downloadService.isRemovePlayed()) { - menu.findItem(R.id.menu_remove_played).setChecked(true); - } - - boolean equalizerAvailable = downloadService != null && downloadService.getEqualizerAvailable(); - if(equalizerAvailable && !downloadService.isRemoteEnabled()) { - SharedPreferences prefs = Util.getPreferences(context); - boolean equalizerOn = prefs.getBoolean(Constants.PREFERENCES_EQUALIZER_ON, false); - if (equalizerOn && getDownloadService() != null && getDownloadService().getEqualizerController() != null && - getDownloadService().getEqualizerController().isEnabled()) { - menu.findItem(R.id.menu_equalizer).setChecked(true); - } - } else { - menu.removeItem(R.id.menu_equalizer); - } - - if(downloadService != null) { - MenuItem mediaRouteItem = menu.findItem(R.id.menu_mediaroute); - if(mediaRouteItem != null) { - MediaRouteButton mediaRouteButton = (MediaRouteButton) MenuItemCompat.getActionView(mediaRouteItem); - mediaRouteButton.setRouteSelector(downloadService.getRemoteSelector()); - } - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem menuItem) { - if(menuItemSelected(menuItem.getItemId(), null)) { - return true; - } - - return super.onOptionsItemSelected(menuItem); - } - - @Override - public void onCreateContextMenu(android.view.ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - if(!primaryFragment) { - return; - } - - if (view == playlistView) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position); - - android.view.MenuInflater inflater = context.getMenuInflater(); - if(Util.isOffline(context)) { - inflater.inflate(R.menu.nowplaying_context_offline, menu); - } else { - inflater.inflate(R.menu.nowplaying_context, menu); - menu.findItem(R.id.menu_star).setTitle(downloadFile.getSong().isStarred() ? R.string.common_unstar : R.string.common_star); - } - - if (downloadFile.getSong().getParent() == null) { - menu.findItem(R.id.menu_show_album).setVisible(false); - menu.findItem(R.id.menu_show_artist).setVisible(false); - } - - hideMenuItems(menu, (AdapterView.AdapterContextMenuInfo) menuInfo); - } - } - - @Override - public boolean onContextItemSelected(android.view.MenuItem menuItem) { - if(!primaryFragment) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position); - return menuItemSelected(menuItem.getItemId(), downloadFile) || super.onContextItemSelected(menuItem); - } - - private boolean menuItemSelected(int menuItemId, final DownloadFile song) { - switch (menuItemId) { - case R.id.menu_show_album: case R.id.menu_show_artist: - Entry entry = song.getSong(); - - Intent intent = new Intent(context, SubsonicFragmentActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_VIEW_ALBUM, true); - String albumId; - String albumName; - if(menuItemId == R.id.menu_show_album) { - if(Util.isTagBrowsing(context)) { - albumId = entry.getAlbumId(); - } else { - albumId = entry.getParent(); - } - albumName = entry.getAlbum(); - } else { - if(Util.isTagBrowsing(context)) { - albumId = entry.getArtistId(); - } else { - albumId = entry.getGrandParent(); - if(albumId == null) { - intent.putExtra(Constants.INTENT_EXTRA_NAME_CHILD_ID, entry.getParent()); - } - } - albumName = entry.getArtist(); - intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, true); - } - intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, albumId); - intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, albumName); - intent.putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, "Artist"); - - if(Util.isOffline(context)) { - try { - // This should only be successful if this is a online song in offline mode - Integer.parseInt(entry.getParent()); - String root = FileUtil.getMusicDirectory(context).getPath(); - String id = root + "/" + entry.getPath(); - id = id.substring(0, id.lastIndexOf("/")); - if(menuItemId == R.id.menu_show_album) { - intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, id); - } - id = id.substring(0, id.lastIndexOf("/")); - if(menuItemId != R.id.menu_show_album) { - intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, id); - intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, entry.getArtist()); - intent.removeExtra(Constants.INTENT_EXTRA_NAME_CHILD_ID); - } - } catch(Exception e) { - // Do nothing, entry.getParent() is fine - } - } - - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - Util.startActivityWithoutTransition(context, intent); - return true; - case R.id.menu_lyrics: { - SubsonicFragment fragment = new LyricsFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ARTIST, song.getSong().getArtist()); - args.putString(Constants.INTENT_EXTRA_NAME_TITLE, song.getSong().getTitle()); - fragment.setArguments(args); - - replaceFragment(fragment); - return true; - } case R.id.menu_remove: - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().remove(song); - return null; - } - - @Override - protected void done(Void result) { - onDownloadListChanged(); - } - }.execute(); - return true; - case R.id.menu_delete: - List songs = new ArrayList(1); - songs.add(song.getSong()); - getDownloadService().delete(songs); - return true; - case R.id.menu_remove_all: - Util.confirmDialog(context, R.string.download_menu_remove_all, "", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().setShufflePlayEnabled(false); - getDownloadService().clear(); - return null; - } - - @Override - protected void done(Void result) { - onDownloadListChanged(); - } - }.execute(); - } - }); - return true; - case R.id.menu_screen_on_off: - if (getDownloadService().getKeepScreenOn()) { - context.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - getDownloadService().setKeepScreenOn(false); - } else { - context.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - getDownloadService().setKeepScreenOn(true); - } - context.supportInvalidateOptionsMenu(); - return true; - case R.id.menu_remove_played: - if (getDownloadService().isRemovePlayed()) { - getDownloadService().setRemovePlayed(false); - } else { - getDownloadService().setRemovePlayed(true); - } - context.supportInvalidateOptionsMenu(); - return true; - case R.id.menu_shuffle: - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().shuffle(); - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, R.string.download_menu_shuffle_notification); - } - }.execute(); - return true; - case R.id.menu_save_playlist: - List entries = new LinkedList(); - for (DownloadFile downloadFile : getDownloadService().getSongs()) { - entries.add(downloadFile.getSong()); - } - createNewPlaylist(entries, true); - return true; - case R.id.menu_star: - toggleStarred(song.getSong()); - return true; - case R.id.menu_rate: - setRating(song.getSong()); - return true; - case R.id.menu_toggle_timer: - if(getDownloadService().getSleepTimer()) { - getDownloadService().stopSleepTimer(); - context.supportInvalidateOptionsMenu(); - } else { - startTimer(); - } - return true; - case R.id.menu_add_playlist: - songs = new ArrayList(1); - songs.add(song.getSong()); - addToPlaylist(songs); - return true; - case R.id.menu_info: - displaySongInfo(song.getSong()); - return true; - case R.id.menu_share: - songs = new ArrayList(1); - songs.add(song.getSong()); - createShare(songs); - return true; - case R.id.menu_equalizer: { - DownloadService downloadService = getDownloadService(); - if (downloadService != null) { - EqualizerController controller = downloadService.getEqualizerController(); - if(controller != null) { - SubsonicFragment fragment = new EqualizerFragment(); - replaceFragment(fragment); - setControlsVisible(true); - - return true; - } - } - - // Any failed condition will get here - Util.toast(context, "Failed to start equalizer. Try restarting."); - return true; - } default: - return false; - } - } - - @Override - public void onResume() { - super.onResume(); - - final Handler handler = new Handler(); - Runnable runnable = new Runnable() { - @Override - public void run() { - handler.post(new Runnable() { - @Override - public void run() { - update(); - } - }); - } - }; - - executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS); - - setControlsVisible(true); - - DownloadService downloadService = getDownloadService(); - if (downloadService == null || downloadService.getCurrentPlaying() == null || startFlipped) { - playlistFlipper.setDisplayedChild(1); - } - if (downloadService != null && downloadService.getKeepScreenOn()) { - context.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } else { - context.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - updateButtons(); - - if(currentPlaying == null && downloadService != null && currentPlaying == downloadService.getCurrentPlaying()) { - getImageLoader().loadImage(albumArtImageView, (Entry) null, true, false); - } - if(downloadService != null) { - downloadService.startRemoteScan(); - } else { - // Make sure to call remote scan once the service is ready - final Runnable waitForService = new Runnable() { - @Override - public void run() { - DownloadService service = getDownloadService(); - if(service != null) { - service.startRemoteScan(); - } else { - handler.postDelayed(this, SERVICE_BACKOFF); - } - } - }; - - handler.postDelayed(waitForService, SERVICE_BACKOFF); - } - } - - @Override - public void onPause() { - super.onPause(); - executorService.shutdown(); - if(getDownloadService() != null) { - getDownloadService().stopRemoteScan(); - } - } - - @Override - public void setPrimaryFragment(boolean primary) { - super.setPrimaryFragment(primary); - if(rootView != null) { - if(primary) { - mainLayout.setVisibility(View.VISIBLE); - updateButtons(); - } else { - mainLayout.setVisibility(View.GONE); - } - } - } - - private void scheduleHideControls() { - if (hideControlsFuture != null) { - hideControlsFuture.cancel(false); - } - - final Handler handler = new Handler(); - Runnable runnable = new Runnable() { - @Override - public void run() { - handler.post(new Runnable() { - @Override - public void run() { - setControlsVisible(false); - } - }); - } - }; - hideControlsFuture = executorService.schedule(runnable, 3000L, TimeUnit.MILLISECONDS); - } - - private void setControlsVisible(boolean visible) { - try { - long duration = 1700L; - FadeOutAnimation.createAndStart(rootView.findViewById(R.id.download_overlay_buttons), !visible, duration); - - if (visible) { - scheduleHideControls(); - } - } catch(Exception e) { - - } - } - - private void updateButtons() { - if(context == null) { - return; - } - - if(Util.isOffline(context)) { - bookmarkButton.setVisibility(View.GONE); - rateBadButton.setVisibility(View.GONE); - rateGoodButton.setVisibility(View.GONE); - } else { - if(ServerInfo.canBookmark(context)) { - bookmarkButton.setVisibility(View.VISIBLE); - } else { - bookmarkButton.setVisibility(View.GONE); - } - rateBadButton.setVisibility(View.VISIBLE); - rateGoodButton.setVisibility(View.VISIBLE); - } - } - - // Scroll to current playing/downloading. - private void scrollToCurrent() { - if (getDownloadService() == null || songListAdapter == null) { - scrollWhenLoaded = true; - return; - } - - for (int i = 0; i < songListAdapter.getCount(); i++) { - if (currentPlaying == playlistView.getItemAtPosition(i)) { - playlistView.setSelectionFromTop(i, 40); - return; - } - } - DownloadFile currentDownloading = getDownloadService().getCurrentDownloading(); - for (int i = 0; i < songListAdapter.getCount(); i++) { - if (currentDownloading == playlistView.getItemAtPosition(i)) { - playlistView.setSelectionFromTop(i, 40); - return; - } - } - } - - private void update() { - if (getDownloadService() == null) { - return; - } - - if (currentRevision != getDownloadService().getDownloadListUpdateRevision()) { - onDownloadListChanged(); - } - - if (currentPlaying != getDownloadService().getCurrentPlaying()) { - onCurrentChanged(); - } - - if(startFlipped) { - startFlipped = false; - scrollToCurrent(); - } - - onProgressChanged(); - } - - protected void startTimer() { - View dialogView = context.getLayoutInflater().inflate(R.layout.start_timer, null); - - // Setup length label - final TextView lengthBox = (TextView) dialogView.findViewById(R.id.timer_length_label); - final SharedPreferences prefs = Util.getPreferences(context); - String lengthString = prefs.getString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, "5"); - int length = Integer.parseInt(lengthString); - lengthBox.setText(Util.formatDuration(length)); - - // Setup length slider - final SeekBar lengthBar = (SeekBar) dialogView.findViewById(R.id.timer_length_bar); - lengthBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (fromUser) { - int length = getMinutes(progress); - lengthBox.setText(Util.formatDuration(length)); - seekBar.setProgress(progress); - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) { - } - }); - lengthBar.setProgress(length - 1); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.menu_set_timer) - .setView(dialogView) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - int length = getMinutes(lengthBar.getProgress()); - - SharedPreferences.Editor editor = prefs.edit(); - editor.putString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, Integer.toString(length)); - editor.commit(); - - getDownloadService().setSleepTimerDuration(length); - getDownloadService().startSleepTimer(); - context.supportInvalidateOptionsMenu(); - } - }) - .setNegativeButton(R.string.common_cancel, null); - AlertDialog dialog = builder.create(); - dialog.show(); - } - - private int getMinutes(int progress) { - if(progress < 30) { - return progress + 1; - } else if(progress < 61) { - return (progress - 30) * 5 + getMinutes(29); - } else { - return (progress - 61) * 15 + getMinutes(60); - } - } - - private void toggleFullscreenAlbumArt() { - if (playlistFlipper.getDisplayedChild() == 1) { - playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_down_in)); - playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_down_out)); - playlistFlipper.setDisplayedChild(0); - } else { - scrollToCurrent(); - playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_up_in)); - playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_up_out)); - playlistFlipper.setDisplayedChild(1); - - UpdateView.triggerUpdate(); - } - } - - private void start() { - DownloadService service = getDownloadService(); - PlayerState state = service.getPlayerState(); - if (state == PAUSED || state == COMPLETED || state == STOPPED) { - service.start(); - } else if (state == STOPPED || state == IDLE) { - warnIfStorageUnavailable(); - int current = service.getCurrentPlayingIndex(); - // TODO: Use play() method. - if (current == -1) { - service.play(0); - } else { - service.play(current); - } - } - } - private void onDownloadListChanged() { - onDownloadListChanged(false); - } - private void onDownloadListChanged(final boolean refresh) { - final DownloadService downloadService = getDownloadService(); - if (downloadService == null || onDownloadListChangedTask != null) { - return; - } - - onDownloadListChangedTask = new SilentBackgroundTask(context) { - int currentPlayingIndex; - int size; - - @Override - protected Void doInBackground() throws Throwable { - currentPlayingIndex = downloadService.getCurrentPlayingIndex() + 1; - size = downloadService.size(); - - return null; - } - - @Override - protected void done(Void result) { - List list; - list = downloadService.getSongs(); - - if(downloadService.isShufflePlayEnabled()) { - emptyTextView.setText(R.string.download_shuffle_loading); - } - else { - emptyTextView.setText(R.string.download_empty); - } - - if(songListAdapter == null || refresh) { - songList = new ArrayList(); - songList.addAll(list); - playlistView.setAdapter(songListAdapter = new DownloadFileAdapter(context, songList)); - } else { - songList.clear(); - songList.addAll(list); - songListAdapter.notifyDataSetChanged(); - } - - emptyTextView.setVisibility(list.isEmpty() ? View.VISIBLE : View.GONE); - currentRevision = downloadService.getDownloadListUpdateRevision(); - - switch (downloadService.getRepeatMode()) { - case OFF: - if("light".equals(SubsonicActivity.getThemeName()) | "light_fullscreen".equals(SubsonicActivity.getThemeName())) { - repeatButton.setImageResource(R.drawable.media_repeat_off_light); - } else { - repeatButton.setImageResource(R.drawable.media_repeat_off); - } - break; - case ALL: - repeatButton.setImageResource(R.drawable.media_repeat_all); - break; - case SINGLE: - repeatButton.setImageResource(R.drawable.media_repeat_single); - break; - default: - break; - } - - if(scrollWhenLoaded) { - scrollToCurrent(); - scrollWhenLoaded = false; - } - - setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex, size)); - onDownloadListChangedTask = null; - if(onCurrentChangedTask != null) { - onCurrentChangedTask.execute(); - } else if(onProgressChangedTask != null) { - onProgressChangedTask.execute(); - } - } - }; - onDownloadListChangedTask.execute(); - } - - private void onCurrentChanged() { - final DownloadService downloadService = getDownloadService(); - if (downloadService == null || onCurrentChangedTask != null) { - return; - } - - onCurrentChangedTask = new SilentBackgroundTask(context) { - int currentPlayingIndex; - int currentPlayingSize; - - @Override - protected Void doInBackground() throws Throwable { - currentPlaying = downloadService.getCurrentPlaying(); - currentPlayingIndex = downloadService.getCurrentPlayingIndex() + 1; - currentPlayingSize = downloadService.size(); - return null; - } - - @Override - protected void done(Void result) { - if (currentPlaying != null) { - Entry song = currentPlaying.getSong(); - songTitleTextView.setText(song.getTitle()); - getImageLoader().loadImage(albumArtImageView, song, true, true); - starButton.setImageResource(song.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); - setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex, currentPlayingSize)); - - int badRating, goodRating, bookmark; - if(song.getRating() == 1) { - badRating = R.drawable.ic_action_rating_bad_selected; - } else if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - badRating = R.drawable.ic_action_rating_bad_dark; - } else { - badRating = Util.getAttribute(context, R.attr.rating_bad); - } - rateBadButton.setImageResource(badRating); - - if(song.getRating() == 5) { - goodRating = R.drawable.ic_action_rating_good_selected; - } else if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - goodRating = R.drawable.ic_action_rating_good_dark; - } else { - goodRating = Util.getAttribute(context, R.attr.rating_good); - } - rateGoodButton.setImageResource(goodRating); - - if(song.getBookmark() != null) { - bookmark = R.drawable.ic_menu_bookmark_selected; - } else if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - bookmark = R.drawable.ic_menu_bookmark_dark; - } else { - bookmark = Util.getAttribute(context, R.attr.bookmark); - } - bookmarkButton.setImageResource(bookmark); - } else { - songTitleTextView.setText(null); - getImageLoader().loadImage(albumArtImageView, (Entry) null, true, false); - starButton.setImageResource(android.R.drawable.btn_star_big_off); - setSubtitle(null); - } - onCurrentChangedTask = null; - if(onProgressChangedTask != null) { - onProgressChangedTask.execute(); - } - } - }; - - if(onDownloadListChangedTask == null) { - onCurrentChangedTask.execute(); - } - } - - private void onProgressChanged() { - // Make sure to only be trying to run one of these at a time - if (getDownloadService() == null || onProgressChangedTask != null) { - return; - } - - onProgressChangedTask = new SilentBackgroundTask(context) { - DownloadService downloadService; - int millisPlayed; - Integer duration; - PlayerState playerState; - boolean isSeekable; - - @Override - protected Void doInBackground() throws Throwable { - downloadService = getDownloadService(); - millisPlayed = Math.max(0, downloadService.getPlayerPosition()); - duration = downloadService.getPlayerDuration(); - playerState = getDownloadService().getPlayerState(); - isSeekable = downloadService.isSeekable(); - return null; - } - - @Override - protected void done(Void result) { - if (currentPlaying != null) { - int millisTotal = duration == null ? 0 : duration; - - positionTextView.setText(Util.formatDuration(millisPlayed / 1000)); - if(millisTotal > 0) { - durationTextView.setText(Util.formatDuration(millisTotal / 1000)); - } else { - durationTextView.setText("-:--"); - } - progressBar.setMax(millisTotal == 0 ? 100 : millisTotal); // Work-around for apparent bug. - if(!seekInProgress) { - progressBar.setProgress(millisPlayed); - } - progressBar.setEnabled(isSeekable); - } else { - positionTextView.setText("0:00"); - durationTextView.setText("-:--"); - progressBar.setProgress(0); - progressBar.setEnabled(false); - } - - switch (playerState) { - case DOWNLOADING: - if(currentPlaying != null) { - long bytes = currentPlaying.getPartialFile().length(); - statusTextView.setText(context.getResources().getString(R.string.download_playerstate_downloading, Util.formatLocalizedBytes(bytes, context))); - } - break; - case PREPARING: - statusTextView.setText(R.string.download_playerstate_buffering); - break; - default: - if(currentPlaying != null) { - String artist = ""; - if(currentPlaying.getSong().getArtist() != null) { - artist = currentPlaying.getSong().getArtist() + " - "; - } - statusTextView.setText(artist + currentPlaying.getSong().getAlbum()); - } else { - statusTextView.setText(null); - } - break; - } - - switch (playerState) { - case STARTED: - pauseButton.setVisibility(View.VISIBLE); - stopButton.setVisibility(View.INVISIBLE); - startButton.setVisibility(View.INVISIBLE); - break; - case DOWNLOADING: - case PREPARING: - pauseButton.setVisibility(View.INVISIBLE); - stopButton.setVisibility(View.VISIBLE); - startButton.setVisibility(View.INVISIBLE); - break; - default: - pauseButton.setVisibility(View.INVISIBLE); - stopButton.setVisibility(View.INVISIBLE); - startButton.setVisibility(View.VISIBLE); - break; - } - - onProgressChangedTask = null; - } - }; - if(onDownloadListChangedTask == null && onCurrentChangedTask == null) { - onProgressChangedTask.execute(); - } - } - - private void changeProgress(final int ms) { - final DownloadService downloadService = getDownloadService(); - if(downloadService == null) { - return; - } - - new SilentBackgroundTask(context) { - boolean isJukeboxEnabled; - int msPlayed; - Integer duration; - PlayerState playerState; - int seekTo; - - @Override - protected Void doInBackground() throws Throwable { - msPlayed = Math.max(0, downloadService.getPlayerPosition()); - duration = downloadService.getPlayerDuration(); - playerState = getDownloadService().getPlayerState(); - int msTotal = duration == null ? 0 : duration; - if(msPlayed + ms > msTotal) { - seekTo = msTotal; - } else { - seekTo = msPlayed + ms; - } - downloadService.seekTo(seekTo); - return null; - } - - @Override - protected void done(Void result) { - progressBar.setProgress(seekTo); - } - }.execute(); - } - - private void createBookmark() { - DownloadService downloadService = getDownloadService(); - if(downloadService == null) { - return; - } - - final DownloadFile currentDownload = downloadService.getCurrentPlaying(); - if(currentDownload == null) { - return; - } - - View dialogView = context.getLayoutInflater().inflate(R.layout.create_bookmark, null); - final EditText commentBox = (EditText)dialogView.findViewById(R.id.comment_text); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.download_save_bookmark_title) - .setView(dialogView) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - String comment = commentBox.getText().toString(); - - createBookmark(currentDownload, comment); - } - }) - .setNegativeButton(R.string.common_cancel, null); - AlertDialog dialog = builder.create(); - dialog.show(); - } - private void createBookmark(final DownloadFile currentDownload, final String comment) { - DownloadService downloadService = getDownloadService(); - if(downloadService == null) { - return; - } - - final Entry currentSong = currentDownload.getSong(); - final int position = downloadService.getPlayerPosition(); - final Bookmark oldBookmark = currentSong.getBookmark(); - currentSong.setBookmark(new Bookmark(position)); - bookmarkButton.setImageResource(R.drawable.ic_menu_bookmark_selected); - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.createBookmark(currentSong, position, comment, context, null); - - new EntryInstanceUpdater(currentSong) { - @Override - public void update(Entry found) { - found.setBookmark(new Bookmark(position)); - } - }.execute(); - - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, R.string.download_save_bookmark); - setControlsVisible(true); - } - - @Override - protected void error(Throwable error) { - Log.w(TAG, "Failed to create bookmark", error); - currentSong.setBookmark(oldBookmark); - - // If no bookmark at start, then return to no bookmark - if(oldBookmark == null) { - int bookmark; - if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - bookmark = R.drawable.ic_menu_bookmark_dark; - } else { - bookmark = Util.getAttribute(context, R.attr.bookmark); - } - bookmarkButton.setImageResource(bookmark); - } - - String msg; - if(error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.download_save_bookmark_failed) + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - @Override - public boolean onDown(MotionEvent me) { - setControlsVisible(true); - return false; - } - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - final DownloadService downloadService = getDownloadService(); - if (downloadService == null || e1 == null || e2 == null) { - return false; - } - - // Right to Left swipe - int action = 0; - if (e1.getX() - e2.getX() > swipeDistance && Math.abs(velocityX) > swipeVelocity) { - action = ACTION_NEXT; - } - // Left to Right swipe - else if (e2.getX() - e1.getX() > swipeDistance && Math.abs(velocityX) > swipeVelocity) { - action = ACTION_PREVIOUS; - } - // Top to Bottom swipe - else if (e2.getY() - e1.getY() > swipeDistance && Math.abs(velocityY) > swipeVelocity) { - action = ACTION_FORWARD; - } - // Bottom to Top swipe - else if (e1.getY() - e2.getY() > swipeDistance && Math.abs(velocityY) > swipeVelocity) { - action = ACTION_REWIND; - } - - if(action > 0) { - final int performAction = action; - warnIfStorageUnavailable(); - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - switch(performAction) { - case ACTION_NEXT: - downloadService.next(); - break; - case ACTION_PREVIOUS: - downloadService.previous(); - break; - case ACTION_FORWARD: - downloadService.seekTo(downloadService.getPlayerPosition() + DownloadService.FAST_FORWARD); - break; - case ACTION_REWIND: - downloadService.seekTo(downloadService.getPlayerPosition() - DownloadService.REWIND); - break; - } - - onProgressChanged(); - if(performAction == ACTION_NEXT || performAction == ACTION_PREVIOUS) { - onCurrentChanged(); - } - return null; - } - }.execute(); - - return true; - } else { - return false; - } - } - - @Override - public void onLongPress(MotionEvent e) { - } - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - return false; - } - - @Override - public void onShowPress(MotionEvent e) { - } - - @Override - public boolean onSingleTapUp(MotionEvent e) { - return false; - } -} diff --git a/src/github/daneren2005/dsub/fragments/PreferenceCompatFragment.java b/src/github/daneren2005/dsub/fragments/PreferenceCompatFragment.java deleted file mode 100644 index 9f413b3b..00000000 --- a/src/github/daneren2005/dsub/fragments/PreferenceCompatFragment.java +++ /dev/null @@ -1,313 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.fragments; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.preference.Preference; -import android.preference.PreferenceFragment; -import android.preference.PreferenceManager; -import android.preference.PreferenceScreen; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListView; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.util.Constants; - -public class PreferenceCompatFragment extends SubsonicFragment { - private static final int FIRST_REQUEST_CODE = 100; - private static final int MSG_BIND_PREFERENCES = 1; - private static final String PREFERENCES_TAG = "android:preferences"; - private boolean mHavePrefs; - private boolean mInitDone; - private ListView mList; - private PreferenceManager mPreferenceManager; - - private Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - - case MSG_BIND_PREFERENCES: - bindPreferences(); - break; - } - } - }; - - final private Runnable mRequestFocus = new Runnable() { - public void run() { - mList.focusableViewAvailable(mList); - } - }; - - private void bindPreferences() { - PreferenceScreen localPreferenceScreen = getPreferenceScreen(); - if (localPreferenceScreen != null) { - ListView localListView = getListView(); - localPreferenceScreen.bind(localListView); - } - } - - private void ensureList() { - if (mList == null) { - View view = getView(); - if (view == null) { - throw new IllegalStateException("Content view not yet created"); - } - - View listView = view.findViewById(android.R.id.list); - if (!(listView instanceof ListView)) { - throw new RuntimeException("Content has view with id attribute 'android.R.id.list' that is not a ListView class"); - } - - mList = (ListView)listView; - if (mList == null) { - throw new RuntimeException("Your content must have a ListView whose id attribute is 'android.R.id.list'"); - } - - mHandler.post(mRequestFocus); - } - } - - private void postBindPreferences() { - if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) { - mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget(); - } - } - - private void requirePreferenceManager() { - if (this.mPreferenceManager == null) { - throw new RuntimeException("This should be called after super.onCreate."); - } - } - - public void addPreferencesFromIntent(Intent intent) { - requirePreferenceManager(); - PreferenceScreen screen = inflateFromIntent(intent, getPreferenceScreen()); - setPreferenceScreen(screen); - } - - public void addPreferencesFromResource(int resId) { - requirePreferenceManager(); - PreferenceScreen screen = inflateFromResource(getActivity(), resId, getPreferenceScreen()); - setPreferenceScreen(screen); - } - - public Preference findPreference(CharSequence key) { - if (mPreferenceManager == null) { - return null; - } - return mPreferenceManager.findPreference(key); - } - - public ListView getListView() { - ensureList(); - return mList; - } - - public PreferenceManager getPreferenceManager() { - return mPreferenceManager; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - getListView().setScrollBarStyle(0); - if (mHavePrefs) { - bindPreferences(); - } - mInitDone = true; - if (savedInstanceState != null) { - Bundle localBundle = savedInstanceState.getBundle(PREFERENCES_TAG); - if (localBundle != null) { - PreferenceScreen screen = getPreferenceScreen(); - if (screen != null) { - screen.restoreHierarchyState(localBundle); - } - } - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - dispatchActivityResult(requestCode, resultCode, data); - } - - @Override - public void onCreate(Bundle paramBundle) { - super.onCreate(paramBundle); - mPreferenceManager = createPreferenceManager(); - - int res = this.getArguments().getInt(Constants.INTENT_EXTRA_FRAGMENT_TYPE, 0); - if(res != 0) { - addPreferencesFromResource(res); - } - } - - @Override - public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) { - return paramLayoutInflater.inflate(R.layout.preferences, paramViewGroup, false); - } - - @Override - public void onDestroy() { - super.onDestroy(); - dispatchActivityDestroy(); - } - - @Override - public void onDestroyView() { - mList = null; - mHandler.removeCallbacks(mRequestFocus); - mHandler.removeMessages(MSG_BIND_PREFERENCES); - super.onDestroyView(); - } - - @Override - public void onSaveInstanceState(Bundle bundle) { - super.onSaveInstanceState(bundle); - PreferenceScreen screen = getPreferenceScreen(); - if (screen != null) { - Bundle localBundle = new Bundle(); - screen.saveHierarchyState(localBundle); - bundle.putBundle(PREFERENCES_TAG, localBundle); - } - } - - @Override - public void onStop() { - super.onStop(); - dispatchActivityStop(); - } - - /** Access methods with visibility private **/ - - private PreferenceManager createPreferenceManager() { - try { - Constructor c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class); - c.setAccessible(true); - return c.newInstance(this.getActivity(), FIRST_REQUEST_CODE); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private PreferenceScreen getPreferenceScreen() { - try { - Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen"); - m.setAccessible(true); - return (PreferenceScreen) m.invoke(mPreferenceManager); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private void setPreferenceScreen(PreferenceScreen preferenceScreen) { - try { - Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class); - m.setAccessible(true); - boolean result = (Boolean) m.invoke(mPreferenceManager, preferenceScreen); - if (result && preferenceScreen != null) { - mHavePrefs = true; - if (mInitDone) { - postBindPreferences(); - } - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private void dispatchActivityResult(int requestCode, int resultCode, Intent data) { - try { - Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class); - m.setAccessible(true); - m.invoke(mPreferenceManager, requestCode, resultCode, data); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private void dispatchActivityDestroy() { - try { - Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy"); - m.setAccessible(true); - m.invoke(mPreferenceManager); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private void dispatchActivityStop() { - try { - Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop"); - m.setAccessible(true); - m.invoke(mPreferenceManager); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - - private void setFragment(PreferenceFragment preferenceFragment) { - try { - Method m = PreferenceManager.class.getDeclaredMethod("setFragment", PreferenceFragment.class); - m.setAccessible(true); - m.invoke(mPreferenceManager, preferenceFragment); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public PreferenceScreen inflateFromResource(Context context, int resId, PreferenceScreen rootPreferences) { - PreferenceScreen preferenceScreen ; - try { - Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class); - m.setAccessible(true); - preferenceScreen = (PreferenceScreen) m.invoke(mPreferenceManager, context, resId, rootPreferences); - } catch (Exception e) { - throw new RuntimeException(e); - } - return preferenceScreen; - } - - public PreferenceScreen inflateFromIntent(Intent queryIntent, PreferenceScreen rootPreferences) { - PreferenceScreen preferenceScreen ; - try { - Method m = PreferenceManager.class.getDeclaredMethod("inflateFromIntent", Intent.class, PreferenceScreen.class); - m.setAccessible(true); - preferenceScreen = (PreferenceScreen) m.invoke(mPreferenceManager, queryIntent, rootPreferences); - } catch (Exception e) { - throw new RuntimeException(e); - } - return preferenceScreen; - } -} diff --git a/src/github/daneren2005/dsub/fragments/SearchFragment.java b/src/github/daneren2005/dsub/fragments/SearchFragment.java deleted file mode 100644 index 0ab08776..00000000 --- a/src/github/daneren2005/dsub/fragments/SearchFragment.java +++ /dev/null @@ -1,368 +0,0 @@ -package github.daneren2005.dsub.fragments; - -import java.util.ArrayList; -import java.util.List; -import java.util.Arrays; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.widget.SwipeRefreshLayout; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.View; -import android.view.MenuItem; -import android.widget.AdapterView; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.net.Uri; -import android.view.ViewGroup; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.SearchCritera; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.adapter.ArtistAdapter; -import github.daneren2005.dsub.util.BackgroundTask; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.adapter.EntryAdapter; -import github.daneren2005.dsub.adapter.MergeAdapter; -import github.daneren2005.dsub.util.TabBackgroundTask; -import github.daneren2005.dsub.util.Util; - -public class SearchFragment extends SubsonicFragment { - private static final String TAG = SearchFragment.class.getSimpleName(); - - private static final int DEFAULT_ARTISTS = 3; - private static final int DEFAULT_ALBUMS = 5; - private static final int DEFAULT_SONGS = 10; - - private static final int MAX_ARTISTS = 10; - private static final int MAX_ALBUMS = 20; - private static final int MAX_SONGS = 25; - private ListView list; - - private View artistsHeading; - private View albumsHeading; - private View songsHeading; - private View moreArtistsButton; - private View moreAlbumsButton; - private View moreSongsButton; - private SearchResult searchResult; - private MergeAdapter mergeAdapter; - private ArtistAdapter artistAdapter; - private ListAdapter moreArtistsAdapter; - private EntryAdapter albumAdapter; - private ListAdapter moreAlbumsAdapter; - private ListAdapter moreSongsAdapter; - private EntryAdapter songAdapter; - private boolean skipSearch = false; - private String currentQuery; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if(savedInstanceState != null) { - searchResult = (SearchResult) savedInstanceState.getSerializable(Constants.FRAGMENT_LIST); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable(Constants.FRAGMENT_LIST, searchResult); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false); - setTitle(R.string.search_title); - - View buttons = inflater.inflate(R.layout.search_buttons, null); - - artistsHeading = buttons.findViewById(R.id.search_artists); - albumsHeading = buttons.findViewById(R.id.search_albums); - songsHeading = buttons.findViewById(R.id.search_songs); - - moreArtistsButton = buttons.findViewById(R.id.search_more_artists); - moreAlbumsButton = buttons.findViewById(R.id.search_more_albums); - moreSongsButton = buttons.findViewById(R.id.search_more_songs); - - refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); - refreshLayout.setEnabled(false); - - list = (ListView) rootView.findViewById(R.id.fragment_list); - - list.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (view == moreArtistsButton) { - expandArtists(); - } else if (view == moreAlbumsButton) { - expandAlbums(); - } else if (view == moreSongsButton) { - expandSongs(); - } else { - Object item = parent.getItemAtPosition(position); - if (item instanceof Artist) { - onArtistSelected((Artist) item, false); - } else if (item instanceof MusicDirectory.Entry) { - MusicDirectory.Entry entry = (MusicDirectory.Entry) item; - if (entry.isDirectory()) { - onAlbumSelected(entry, false); - } else if (entry.isVideo()) { - onVideoSelected(entry); - } else { - onSongSelected(entry, false, true, true, false); - } - - } - } - } - }); - registerForContextMenu(list); - context.onNewIntent(context.getIntent()); - - if(searchResult != null) { - skipSearch = true; - populateList(); - } - - return rootView; - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - menuInflater.inflate(R.menu.search, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_search: - context.startSearch(currentQuery, false, null, false); - return true; - } - - return super.onOptionsItemSelected(item); - - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object selectedItem = list.getItemAtPosition(info.position); - onCreateContextMenu(menu, view, menuInfo, selectedItem); - if(selectedItem instanceof MusicDirectory.Entry && !((MusicDirectory.Entry) selectedItem).isVideo() && !Util.isOffline(context)) { - menu.removeItem(R.id.song_menu_remove_playlist); - } - - recreateContextMenu(menu); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Object selectedItem = list.getItemAtPosition(info.position); - - if(onContextItemSelected(menuItem, selectedItem)) { - return true; - } - - return true; - } - - @Override - public void setPrimaryFragment(boolean primary) { - super.setPrimaryFragment(primary); - } - - @Override - public void refresh(boolean refresh) { - context.onNewIntent(context.getIntent()); - } - - public void search(final String query, final boolean autoplay) { - if(skipSearch) { - skipSearch = false; - return; - } - currentQuery = query; - - mergeAdapter = new MergeAdapter(); - list.setAdapter(mergeAdapter); - - BackgroundTask task = new TabBackgroundTask(this) { - @Override - protected SearchResult doInBackground() throws Throwable { - SearchCritera criteria = new SearchCritera(query, MAX_ARTISTS, MAX_ALBUMS, MAX_SONGS); - MusicService service = MusicServiceFactory.getMusicService(context); - return service.search(criteria, context, this); - } - - @Override - protected void done(SearchResult result) { - searchResult = result; - populateList(); - if (autoplay) { - autoplay(query); - } - - } - }; - task.execute(); - } - - public void populateList() { - mergeAdapter = new MergeAdapter(); - - if (searchResult != null) { - List artists = searchResult.getArtists(); - if (!artists.isEmpty()) { - mergeAdapter.addView(artistsHeading); - List displayedArtists = new ArrayList(artists.subList(0, Math.min(DEFAULT_ARTISTS, artists.size()))); - artistAdapter = new ArtistAdapter(context, displayedArtists); - mergeAdapter.addAdapter(artistAdapter); - if (artists.size() > DEFAULT_ARTISTS) { - moreArtistsAdapter = mergeAdapter.addView(moreArtistsButton, true); - } - } - - List albums = searchResult.getAlbums(); - if (!albums.isEmpty()) { - mergeAdapter.addView(albumsHeading); - List displayedAlbums = new ArrayList(albums.subList(0, Math.min(DEFAULT_ALBUMS, albums.size()))); - albumAdapter = new EntryAdapter(context, getImageLoader(), displayedAlbums, false); - mergeAdapter.addAdapter(albumAdapter); - if (albums.size() > DEFAULT_ALBUMS) { - moreAlbumsAdapter = mergeAdapter.addView(moreAlbumsButton, true); - } - } - - List songs = searchResult.getSongs(); - if (!songs.isEmpty()) { - mergeAdapter.addView(songsHeading); - List displayedSongs = new ArrayList(songs.subList(0, Math.min(DEFAULT_SONGS, songs.size()))); - songAdapter = new EntryAdapter(context, getImageLoader(), displayedSongs, false); - mergeAdapter.addAdapter(songAdapter); - if (songs.size() > DEFAULT_SONGS) { - moreSongsAdapter = mergeAdapter.addView(moreSongsButton, true); - } - } - - boolean empty = searchResult.getArtists().isEmpty() && searchResult.getAlbums().isEmpty() && searchResult.getSongs().isEmpty(); - if(empty) { - setEmpty(true); - } - } - - list.setAdapter(mergeAdapter); - } - - private void expandArtists() { - artistAdapter.clear(); - for (Artist artist : searchResult.getArtists()) { - artistAdapter.add(artist); - } - artistAdapter.notifyDataSetChanged(); - mergeAdapter.removeAdapter(moreArtistsAdapter); - mergeAdapter.notifyDataSetChanged(); - } - - private void expandAlbums() { - albumAdapter.clear(); - for (MusicDirectory.Entry album : searchResult.getAlbums()) { - albumAdapter.add(album); - } - albumAdapter.notifyDataSetChanged(); - mergeAdapter.removeAdapter(moreAlbumsAdapter); - mergeAdapter.notifyDataSetChanged(); - } - - private void expandSongs() { - songAdapter.clear(); - for (MusicDirectory.Entry song : searchResult.getSongs()) { - songAdapter.add(song); - } - songAdapter.notifyDataSetChanged(); - mergeAdapter.removeAdapter(moreSongsAdapter); - mergeAdapter.notifyDataSetChanged(); - } - - private void onArtistSelected(Artist artist, boolean autoplay) { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); - if(autoplay) { - args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); - } - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - fragment.setArguments(args); - - replaceFragment(fragment); - } - - private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay) { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, album.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, album.getTitle()); - if(autoplay) { - args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); - } - fragment.setArguments(args); - - replaceFragment(fragment); - } - - private void onSongSelected(MusicDirectory.Entry song, boolean save, boolean append, boolean autoplay, boolean playNext) { - DownloadService downloadService = getDownloadService(); - if (downloadService != null) { - if (!append) { - downloadService.clear(); - } - downloadService.download(Arrays.asList(song), save, false, playNext, false); - if (autoplay) { - downloadService.play(downloadService.size() - 1); - } - - Util.toast(context, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1)); - } - } - - private void onVideoSelected(MusicDirectory.Entry entry) { - int maxBitrate = Util.getMaxVideoBitrate(context); - - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(MusicServiceFactory.getMusicService(context).getVideoUrl(maxBitrate, context, entry.getId()))); - startActivity(intent); - } - - private void autoplay(String query) { - Artist artist = searchResult.getArtists().isEmpty() ? null : searchResult.getArtists().get(0); - MusicDirectory.Entry album = searchResult.getAlbums().isEmpty() ? null : searchResult.getAlbums().get(0); - MusicDirectory.Entry song = searchResult.getSongs().isEmpty() ? null : searchResult.getSongs().get(0); - - if(artist != null && query.equals(artist.getName())) { - onArtistSelected(artist, true); - } else if(album != null && query.equals(album.getTitle())) { - onAlbumSelected(album, true); - } else if(song != null) { - onSongSelected(song, false, false, true, false); - } else if(album != null) { - onAlbumSelected(album, true); - } - } -} diff --git a/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java b/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java deleted file mode 100644 index 8bf8a8ec..00000000 --- a/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java +++ /dev/null @@ -1,333 +0,0 @@ -package github.daneren2005.dsub.fragments; - -import android.annotation.TargetApi; -import android.os.Build; -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.LinearLayout; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.MusicFolder; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.ArtistAdapter; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -public class SelectArtistFragment extends SelectListFragment { - private static final String TAG = SelectArtistFragment.class.getSimpleName(); - private static final int MENU_GROUP_MUSIC_FOLDER = 10; - - private View folderButtonParent; - private View folderButton; - private TextView folderName; - private List musicFolders = null; - private List entries; - private String groupId; - private String groupName; - - public SelectArtistFragment() { - super(); - } - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - - if(bundle != null) { - musicFolders = (List) bundle.getSerializable(Constants.FRAGMENT_LIST2); - } - artist = true; - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable(Constants.FRAGMENT_LIST2, (Serializable) musicFolders); - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - Bundle args = getArguments(); - if(args != null) { - groupId = args.getString(Constants.INTENT_EXTRA_NAME_ID); - groupName = args.getString(Constants.INTENT_EXTRA_NAME_NAME); - - if(groupName != null) { - setTitle(groupName); - context.invalidateOptionsMenu(); - } - } - - folderButton = null; - super.onCreateView(inflater, container, bundle); - - if("4.4.2".equals(Build.VERSION.RELEASE)) { - listView.setFastScrollAlwaysVisible(true); - } - - if(objects != null && currentTask == null) { - if (Util.isOffline(context) || Util.isTagBrowsing(context) || groupId != null) { - folderButton.setVisibility(View.GONE); - } - setMusicFolders(); - } - - return rootView; - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object entry = listView.getItemAtPosition(info.position); - - if (entry instanceof Artist) { - onCreateContextMenu(menu, view, menuInfo, entry); - } else if (info.position == 0) { - String musicFolderId = Util.getSelectedMusicFolderId(context); - MenuItem menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, -1, 0, R.string.select_artist_all_folders); - if (musicFolderId == null) { - menuItem.setChecked(true); - } - if (musicFolders != null) { - for (int i = 0; i < musicFolders.size(); i++) { - MusicFolder musicFolder = musicFolders.get(i); - menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, i, i + 1, musicFolder.getName()); - if (musicFolder.getId().equals(musicFolderId)) { - menuItem.setChecked(true); - } - } - } - menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true); - } - - recreateContextMenu(menu); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Artist artist = (Artist) listView.getItemAtPosition(info.position); - - if (artist != null) { - return onContextItemSelected(menuItem, artist); - } else if (info.position == 0) { - MusicFolder selectedFolder = menuItem.getItemId() == -1 ? null : musicFolders.get(menuItem.getItemId()); - String musicFolderId = selectedFolder == null ? null : selectedFolder.getId(); - String musicFolderName = selectedFolder == null ? context.getString(R.string.select_artist_all_folders) - : selectedFolder.getName(); - Util.setSelectedMusicFolderId(context, musicFolderId); - folderName.setText(musicFolderName); - context.invalidate(); - } - - return true; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (view == folderButtonParent) { - selectFolder(); - } else { - Artist artist = (Artist) parent.getItemAtPosition(position); - - SubsonicFragment fragment; - if((Util.isFirstLevelArtist(context) || Util.isOffline(context) || Util.isTagBrowsing(context)) || "root".equals(artist.getId()) || groupId != null) { - fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); - if ("root".equals(artist.getId())) { - args.putSerializable(Constants.FRAGMENT_LIST, (Serializable) entries); - } - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - fragment.setArguments(args); - } else { - fragment = new SelectArtistFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); - fragment.setArguments(args); - } - - replaceFragment(fragment); - } - } - - @Override - public void onFinishRefresh() { - setMusicFolders(); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - super.onCreateOptionsMenu(menu, menuInflater); - - if(Util.isOffline(context) || Util.isTagBrowsing(context) || groupId != null) { - menu.removeItem(R.id.menu_first_level_artist); - } else { - if (Util.isFirstLevelArtist(context)) { - menu.findItem(R.id.menu_first_level_artist).setChecked(true); - } - } - } - - @Override - public int getOptionsMenu() { - return R.menu.select_artist; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(super.onOptionsItemSelected(item)) { - return true; - } - - switch (item.getItemId()) { - case R.id.menu_first_level_artist: - toggleFirstLevelArtist(); - break; - } - - return false; - } - - @Override - public ArrayAdapter getAdapter(List objects) { - createMusicFolderButton(); - return new ArtistAdapter(context, objects); - } - - @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - List artists; - if(groupId == null) { - if (!Util.isOffline(context) && !Util.isTagBrowsing(context)) { - musicFolders = musicService.getMusicFolders(refresh, context, listener); - - // Hide folders option if there is only one - if (musicFolders.size() == 1) { - musicFolders = null; - Util.setSelectedMusicFolderId(context, null); - } - } - String musicFolderId = Util.getSelectedMusicFolderId(context); - - Indexes indexes = musicService.getIndexes(musicFolderId, refresh, context, listener); - artists = new ArrayList(indexes.getShortcuts().size() + indexes.getArtists().size()); - artists.addAll(indexes.getShortcuts()); - artists.addAll(indexes.getArtists()); - entries = indexes.getEntries(); - } else { - artists = new ArrayList(); - MusicDirectory dir = musicService.getMusicDirectory(groupId, groupName, refresh, context, listener); - for(MusicDirectory.Entry entry: dir.getChildren(true, false)) { - Artist artist = new Artist(); - artist.setId(entry.getId()); - artist.setName(entry.getTitle()); - artist.setStarred(entry.isStarred()); - artists.add(artist); - } - - entries = new ArrayList(); - entries.addAll(dir.getChildren(false, true)); - if(!entries.isEmpty()) { - Artist root = new Artist(); - root.setId("root"); - root.setName("Root"); - root.setIndex("#"); - artists.add(root); - } - } - - return artists; - } - - @Override - public int getTitleResource() { - return groupId == null ? R.string.button_bar_browse : 0; - } - - private void createMusicFolderButton() { - if(folderButton == null) { - folderButtonParent = context.getLayoutInflater().inflate(R.layout.select_artist_header, listView, false); - folderName = (TextView) folderButtonParent.findViewById(R.id.select_artist_folder_2); - listView.addHeaderView(folderButtonParent); - folderButton = folderButtonParent.findViewById(R.id.select_artist_folder); - } - - if (Util.isOffline(context) || Util.isTagBrowsing(context) || musicFolders == null) { - folderButton.setVisibility(View.GONE); - } else { - folderButton.setVisibility(View.VISIBLE); - } - } - - @Override - public void setEmpty(boolean empty) { - super.setEmpty(empty); - - if(empty && !Util.isOffline(context)) { - createMusicFolderButton(); - setMusicFolders(); - - objects.clear(); - listView.setAdapter(new ArtistAdapter(context, objects)); - listView.setVisibility(View.VISIBLE); - - View view = rootView.findViewById(R.id.tab_progress); - LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams(); - params.height = 0; - params.weight = 5; - view.setLayoutParams(params); - } - } - - private void setMusicFolders() { - // Display selected music folder - if (musicFolders != null) { - String musicFolderId = Util.getSelectedMusicFolderId(context); - if (musicFolderId == null) { - folderName.setText(R.string.select_artist_all_folders); - } else { - for (MusicFolder musicFolder : musicFolders) { - if (musicFolder.getId().equals(musicFolderId)) { - folderName.setText(musicFolder.getName()); - break; - } - } - } - } - } - - private void selectFolder() { - folderButton.showContextMenu(); - } - - private void toggleFirstLevelArtist() { - Util.toggleFirstLevelArtist(context); - context.invalidateOptionsMenu(); - } -} diff --git a/src/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java b/src/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java deleted file mode 100644 index c71d99f6..00000000 --- a/src/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus -*/ -package github.daneren2005.dsub.fragments; - -import android.view.ContextMenu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.DownloadActivity; -import github.daneren2005.dsub.domain.Bookmark; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.BookmarkAdapter; - -import java.util.Arrays; -import java.util.List; - -public class SelectBookmarkFragment extends SelectListFragment { - private static final String TAG = SelectBookmarkFragment.class.getSimpleName(); - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - MenuInflater inflater = context.getMenuInflater(); - inflater.inflate(R.menu.select_bookmark_context, menu); - - hideMenuItems(menu, (AdapterView.AdapterContextMenuInfo) menuInfo); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - MusicDirectory.Entry bookmark = objects.get(info.position); - - switch(menuItem.getItemId()) { - case R.id.bookmark_menu_info: - displayBookmarkInfo(bookmark); - return true; - case R.id.bookmark_menu_delete: - deleteBookmark(bookmark, adapter); - return true; - } - - if(onContextItemSelected(menuItem, bookmark)) { - return true; - } - - return true; - } - - @Override - public int getOptionsMenu() { - return R.menu.abstract_top_menu; - } - - @Override - public ArrayAdapter getAdapter(List bookmarks) { - return new BookmarkAdapter(context, bookmarks); - } - - @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - return musicService.getBookmarks(refresh, context, listener).getChildren(); - } - - @Override - public int getTitleResource() { - return R.string.button_bar_bookmarks; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - final DownloadService downloadService = getDownloadService(); - if(downloadService == null) { - return; - } - - final MusicDirectory.Entry bookmark = (MusicDirectory.Entry) parent.getItemAtPosition(position); - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - downloadService.clear(); - downloadService.download(Arrays.asList(bookmark), false, true, false, false, 0, bookmark.getBookmark().getPosition()); - return null; - } - - @Override - protected void done(Void result) { - Util.startActivityWithoutTransition(context, DownloadActivity.class); - } - }.execute(); - } - - private void displayBookmarkInfo(final MusicDirectory.Entry entry) { - Bookmark bookmark = entry.getBookmark(); - String comment = bookmark.getComment(); - if(comment == null) { - comment = ""; - } - - String msg = context.getResources().getString(R.string.bookmark_details, - entry.getTitle(), Util.formatDuration(bookmark.getPosition() / 1000), - Util.formatDate(bookmark.getCreated()), Util.formatDate(bookmark.getChanged()), comment); - - Util.info(context, R.string.bookmark_details_title, msg, false); - } -} diff --git a/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java deleted file mode 100644 index cfb3af69..00000000 --- a/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java +++ /dev/null @@ -1,1597 +0,0 @@ -package github.daneren2005.dsub.fragments; - -import android.annotation.TargetApi; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.support.v4.widget.SwipeRefreshLayout; -import android.text.Html; -import android.text.SpannableString; -import android.text.Spanned; -import android.text.method.LinkMovementMethod; -import android.util.Log; -import android.view.ContextMenu; -import android.view.Display; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.BaseAdapter; -import android.widget.GridView; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.RatingBar; -import android.widget.RelativeLayout; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.ArtistInfo; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.domain.Share; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.adapter.AlbumGridAdapter; -import github.daneren2005.dsub.adapter.EntryAdapter; - -import java.io.Serializable; -import java.util.Iterator; -import java.util.List; - -import github.daneren2005.dsub.activity.DownloadActivity; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.service.OfflineException; -import github.daneren2005.dsub.service.ServerTooOldException; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.LoadingTask; -import github.daneren2005.dsub.util.Pair; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.TabBackgroundTask; -import github.daneren2005.dsub.util.UserUtil; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.AlbumListAdapter; -import github.daneren2005.dsub.view.HeaderGridView; -import github.daneren2005.dsub.view.MyLeadingMarginSpan2; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - -import static github.daneren2005.dsub.domain.MusicDirectory.Entry; - -public class SelectDirectoryFragment extends SubsonicFragment implements AdapterView.OnItemClickListener { - private static final String TAG = SelectDirectoryFragment.class.getSimpleName(); - - private GridView albumList; - private ListView entryList; - private Boolean licenseValid; - private EntryAdapter entryAdapter; - private List albums; - private List entries; - private boolean albumContext = false; - private boolean addAlbumHeader = false; - private LoadTask currentTask; - private ArtistInfo artistInfo; - private String artistInfoDelayed; - - String id; - String name; - Entry directory; - String playlistId; - String playlistName; - boolean playlistOwner; - String podcastId; - String podcastName; - String podcastDescription; - String albumListType; - String albumListExtra; - int albumListSize; - boolean refreshListing = false; - boolean showAll = false; - boolean restoredInstance = false; - boolean lookupParent = false; - boolean largeAlbums = false; - boolean topTracks = false; - String lookupEntry; - - public SelectDirectoryFragment() { - super(); - } - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - if(bundle != null) { - entries = (List) bundle.getSerializable(Constants.FRAGMENT_LIST); - albums = (List) bundle.getSerializable(Constants.FRAGMENT_LIST2); - artistInfo = (ArtistInfo) bundle.getSerializable(Constants.FRAGMENT_EXTRA); - restoredInstance = true; - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putSerializable(Constants.FRAGMENT_LIST, (Serializable) entries); - outState.putSerializable(Constants.FRAGMENT_LIST2, (Serializable) albums); - outState.putSerializable(Constants.FRAGMENT_EXTRA, (Serializable) artistInfo); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - Bundle args = getArguments(); - if(args != null) { - id = args.getString(Constants.INTENT_EXTRA_NAME_ID); - name = args.getString(Constants.INTENT_EXTRA_NAME_NAME); - directory = (Entry) args.getSerializable(Constants.INTENT_EXTRA_NAME_DIRECTORY); - playlistId = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID); - playlistName = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME); - playlistOwner = args.getBoolean(Constants.INTENT_EXTRA_NAME_PLAYLIST_OWNER, false); - podcastId = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_ID); - podcastName = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_NAME); - podcastDescription = args.getString(Constants.INTENT_EXTRA_NAME_PODCAST_DESCRIPTION); - Object shareObj = args.getSerializable(Constants.INTENT_EXTRA_NAME_SHARE); - share = (shareObj != null) ? (Share) shareObj : null; - albumListType = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE); - albumListExtra = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA); - albumListSize = args.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0); - refreshListing = args.getBoolean(Constants.INTENT_EXTRA_REFRESH_LISTINGS); - artist = args.getBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, false); - lookupEntry = args.getString(Constants.INTENT_EXTRA_SEARCH_SONG); - topTracks = args.getBoolean(Constants.INTENT_EXTRA_TOP_TRACKS); - showAll = args.getBoolean(Constants.INTENT_EXTRA_SHOW_ALL); - - String childId = args.getString(Constants.INTENT_EXTRA_NAME_CHILD_ID); - if(childId != null) { - id = childId; - lookupParent = true; - } - if(entries == null) { - entries = (List) args.getSerializable(Constants.FRAGMENT_LIST); - albums = (List) args.getSerializable(Constants.FRAGMENT_LIST2); - - if(albums == null) { - albums = new ArrayList(); - } - } - } - - rootView = inflater.inflate(R.layout.select_album, container, false); - - refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); - refreshLayout.setOnRefreshListener(this); - - entryList = (ListView) rootView.findViewById(R.id.select_album_entries); - entryList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - entryList.setOnItemClickListener(this); - setupScrollList(entryList); - - if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_LARGE_ALBUM_ART, true)) { - largeAlbums = true; - } - - if(albumListType == null || "starred".equals(albumListType) || !largeAlbums) { - albumList = (GridView) inflater.inflate(R.layout.unscrollable_grid_view, entryList, false); - addAlbumHeader = true; - } else { - ViewGroup rootGroup = (ViewGroup) rootView.findViewById(R.id.select_album_layout); - albumList = (GridView) inflater.inflate(R.layout.grid_view, rootGroup, false); - rootGroup.removeView(entryList); - rootGroup.addView(albumList); - - setupScrollList(albumList); - } - registerForContextMenu(entryList); - setupAlbumList(); - - if(entries == null) { - if(primaryFragment || secondaryFragment) { - load(false); - } else { - invalidated = true; - } - } else { - licenseValid = true; - finishLoading(); - } - - if(name != null) { - setTitle(name); - } - - return rootView; - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - if(licenseValid == null) { - menuInflater.inflate(R.menu.empty, menu); - } else if(albumListType != null && !"starred".equals(albumListType)) { - menuInflater.inflate(R.menu.select_album_list, menu); - } else if(artist && !showAll) { - menuInflater.inflate(R.menu.select_album, menu); - - if(!ServerInfo.isMadsonic(context)) { - menu.removeItem(R.id.menu_top_tracks); - } - if(!ServerInfo.checkServerVersion(context, "1.11") || (id != null && "root".equals(id))) { - menu.removeItem(R.id.menu_radio); - menu.removeItem(R.id.menu_similar_artists); - } else if(ServerInfo.isMadsonic(context)) { - menu.removeItem(R.id.menu_similar_artists); - } - } else { - if(podcastId == null) { - if(Util.isOffline(context)) { - menuInflater.inflate(R.menu.select_song_offline, menu); - } - else { - menuInflater.inflate(R.menu.select_song, menu); - - if(playlistId == null || !playlistOwner) { - menu.removeItem(R.id.menu_remove_playlist); - } - } - - SharedPreferences prefs = Util.getPreferences(context); - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_PLAY_NEXT, true)) { - menu.setGroupVisible(R.id.hide_play_next, false); - } - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_PLAY_LAST, true)) { - menu.setGroupVisible(R.id.hide_play_last, false); - } - } else { - if(Util.isOffline(context)) { - menuInflater.inflate(R.menu.select_podcast_episode_offline, menu); - } - else { - menuInflater.inflate(R.menu.select_podcast_episode, menu); - - if(!UserUtil.canPodcast()) { - menu.removeItem(R.id.menu_download_all); - } - } - } - } - - if("starred".equals(albumListType)) { - menuInflater.inflate(R.menu.unstar, menu); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_play_now: - playNow(false, false); - return true; - case R.id.menu_play_last: - playNow(false, true); - return true; - case R.id.menu_play_next: - playNow(false, true, true); - return true; - case R.id.menu_shuffle: - playNow(true, false); - return true; - case R.id.menu_download: - downloadBackground(false); - selectAll(false, false); - return true; - case R.id.menu_cache: - downloadBackground(true); - selectAll(false, false); - return true; - case R.id.menu_delete: - delete(); - selectAll(false, false); - return true; - case R.id.menu_add_playlist: - if(getSelectedSongs().isEmpty()) { - selectAll(true, false); - } - addToPlaylist(getSelectedSongs()); - return true; - case R.id.menu_remove_playlist: - removeFromPlaylist(playlistId, playlistName, getSelectedIndexes()); - return true; - case R.id.menu_download_all: - downloadAllPodcastEpisodes(); - return true; - case R.id.menu_show_all: - setShowAll(); - return true; - case R.id.menu_unstar: - unstarSelected(); - return true; - case R.id.menu_top_tracks: - showTopTracks(); - return true; - case R.id.menu_similar_artists: - showSimilarArtists(id); - return true; - case R.id.menu_radio: - startArtistRadio(id); - return true; - } - - return super.onOptionsItemSelected(item); - - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - - Entry entry; - if(view.getId() == R.id.select_album_entries) { - if(info.position == 0) { - return; - } - entry = (Entry) entryList.getItemAtPosition(info.position); - // When List has Grid embedded in header, this is called against the header as well - if(entry != null) { - albumContext = false; - } - } else { - entry = (Entry) albumList.getItemAtPosition(info.position); - albumContext = true; - } - - // Don't try to display a context menu if error here - if(entry == null) { - return; - } - - onCreateContextMenu(menu, view, menuInfo, entry); - if(!entry.isVideo() && !Util.isOffline(context) && (playlistId == null || !playlistOwner) && (podcastId == null || Util.isOffline(context) && podcastId != null)) { - menu.removeItem(R.id.song_menu_remove_playlist); - } - // Remove show artists if parent is not set and if not on a album list - if((albumListType == null || (entry.getParent() == null && entry.getArtistId() == null)) && !Util.isOffline(context)) { - menu.removeItem(R.id.album_menu_show_artist); - } - if(podcastId != null && !Util.isOffline(context)) { - if(UserUtil.canPodcast()) { - String status = ((PodcastEpisode)entry).getStatus(); - if("completed".equals(status)) { - menu.removeItem(R.id.song_menu_server_download); - } - } else { - menu.removeItem(R.id.song_menu_server_download); - menu.removeItem(R.id.song_menu_server_delete); - } - } - - recreateContextMenu(menu); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Object selectedItem; - int headers = entryList.getHeaderViewsCount(); - if(albumContext) { - selectedItem = albumList.getItemAtPosition(info.position); - } else { - if(info.position == 0) { - return false; - } - selectedItem = entries.get(info.position - headers); - } - - if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PLAY_NOW_AFTER, false) && menuItem.getItemId() == R.id.song_menu_play_now) { - List songs = new ArrayList(); - Iterator it = entries.listIterator(info.position - headers); - while(it.hasNext()) { - songs.add((Entry) it.next()); - } - - playNow(songs); - return true; - } - - if(onContextItemSelected(menuItem, selectedItem)) { - return true; - } - - switch (menuItem.getItemId()) { - case R.id.song_menu_remove_playlist: - removeFromPlaylist(playlistId, playlistName, Arrays.asList(info.position - headers)); - break; - case R.id.song_menu_server_download: - downloadPodcastEpisode((PodcastEpisode)selectedItem); - break; - case R.id.song_menu_server_delete: - deletePodcastEpisode((PodcastEpisode)selectedItem); - break; - } - - return true; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (position >= 0) { - Entry entry = (Entry) parent.getItemAtPosition(position); - if (entry.isDirectory()) { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle()); - args.putSerializable(Constants.INTENT_EXTRA_NAME_DIRECTORY, entry); - if ("newest".equals(albumListType)) { - args.putBoolean(Constants.INTENT_EXTRA_REFRESH_LISTINGS, true); - } - if(entry.getArtist() == null && entry.getParent() == null) { - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - } - fragment.setArguments(args); - - replaceFragment(fragment, true); - } else if (entry.isVideo()) { - playVideo(entry); - } else if(entry instanceof PodcastEpisode) { - String status = ((PodcastEpisode)entry).getStatus(); - if("error".equals(status)) { - Util.toast(context, R.string.select_podcasts_error); - return; - } else if(!"completed".equals(status)) { - Util.toast(context, R.string.select_podcasts_skipped); - return; - } - - playNow(Arrays.asList(entry)); - } - } - } - - @Override - protected void refresh(boolean refresh) { - if(!"root".equals(id)) { - load(refresh); - } - } - - private void load(boolean refresh) { - if(refreshListing) { - refresh = true; - } - - if(currentTask != null) { - currentTask.cancel(); - } - - entryList.setVisibility(View.INVISIBLE); - if (playlistId != null) { - getPlaylist(playlistId, playlistName, refresh); - } else if(podcastId != null) { - getPodcast(podcastId, podcastName, refresh); - } else if (share != null) { - if(showAll) { - getRecursiveMusicDirectory(share.getId(), share.getName(), refresh); - } else { - getShare(share, refresh); - } - } else if (albumListType != null) { - getAlbumList(albumListType, albumListSize); - } else { - if(showAll) { - getRecursiveMusicDirectory(id, name, refresh); - } else if(topTracks) { - getTopTracks(id, name, refresh); - } else { - getMusicDirectory(id, name, refresh); - } - } - } - - private void getMusicDirectory(final String id, final String name, final boolean refresh) { - setTitle(name); - - new LoadTask(refresh) { - @Override - protected MusicDirectory load(MusicService service) throws Exception { - MusicDirectory dir = getMusicDirectory(id, name, refresh, service, this); - - if(lookupParent && dir.getParent() != null) { - dir = getMusicDirectory(dir.getParent(), name, refresh, service, this); - - // Update the fragment pointers so other stuff works correctly - SelectDirectoryFragment.this.id = dir.getId(); - SelectDirectoryFragment.this.name = dir.getName(); - } else if(id != null && directory == null && dir.getParent() != null && !artist) { - // View Album, try to lookup parent to get a complete entry to use for starring - MusicDirectory parentDir = getMusicDirectory(dir.getParent(), name, refresh, true, service, this); - for(Entry child: parentDir.getChildren()) { - if(id.equals(child.getId())) { - directory = child; - break; - } - } - } - - return dir; - } - - @Override - protected void done(Pair result) { - SelectDirectoryFragment.this.name = result.getFirst().getName(); - setTitle(SelectDirectoryFragment.this.name); - super.done(result); - } - }.execute(); - } - - private void getRecursiveMusicDirectory(final String id, final String name, final boolean refresh) { - setTitle(name); - - new LoadTask(refresh) { - @Override - protected MusicDirectory load(MusicService service) throws Exception { - MusicDirectory root; - if(share == null) { - root = getMusicDirectory(id, name, refresh, service, this); - } else { - root = share.getMusicDirectory(); - } - List songs = new ArrayList(); - getSongsRecursively(root, songs); - root.replaceChildren(songs); - return root; - } - - private void getSongsRecursively(MusicDirectory parent, List songs) throws Exception { - songs.addAll(parent.getChildren(false, true)); - for (Entry dir : parent.getChildren(true, false)) { - MusicService musicService = MusicServiceFactory.getMusicService(context); - - MusicDirectory musicDirectory; - if(Util.isTagBrowsing(context) && !Util.isOffline(context)) { - musicDirectory = musicService.getAlbum(dir.getId(), dir.getTitle(), false, context, this); - } else { - musicDirectory = musicService.getMusicDirectory(dir.getId(), dir.getTitle(), false, context, this); - } - getSongsRecursively(musicDirectory, songs); - } - } - - @Override - protected void done(Pair result) { - SelectDirectoryFragment.this.name = result.getFirst().getName(); - setTitle(SelectDirectoryFragment.this.name); - super.done(result); - } - }.execute(); - } - - private void getPlaylist(final String playlistId, final String playlistName, final boolean refresh) { - setTitle(playlistName); - - new LoadTask(refresh) { - @Override - protected MusicDirectory load(MusicService service) throws Exception { - return service.getPlaylist(refresh, playlistId, playlistName, context, this); - } - }.execute(); - } - - private void getPodcast(final String podcastId, final String podcastName, final boolean refresh) { - setTitle(podcastName); - - new LoadTask(refresh) { - @Override - protected MusicDirectory load(MusicService service) throws Exception { - return service.getPodcastEpisodes(refresh, podcastId, context, this); - } - }.execute(); - } - - private void getShare(final Share share, final boolean refresh) { - setTitle(share.getName()); - - new LoadTask(refresh) { - @Override - protected MusicDirectory load(MusicService service) throws Exception { - return share.getMusicDirectory(); - } - }.execute(); - } - - private void getTopTracks(final String id, final String name, final boolean refresh) { - setTitle(name); - - new LoadTask(refresh) { - @Override - protected MusicDirectory load(MusicService service) throws Exception { - return service.getTopTrackSongs(name, 20, context, this); - } - }.execute(); - } - - private void getAlbumList(final String albumListType, final int size) { - if ("newest".equals(albumListType)) { - setTitle(R.string.main_albums_newest); - } else if ("random".equals(albumListType)) { - setTitle(R.string.main_albums_random); - } else if ("highest".equals(albumListType)) { - setTitle(R.string.main_albums_highest); - } else if ("recent".equals(albumListType)) { - setTitle(R.string.main_albums_recent); - } else if ("frequent".equals(albumListType)) { - setTitle(R.string.main_albums_frequent); - } else if ("starred".equals(albumListType)) { - setTitle(R.string.main_albums_starred); - } else if("genres".equals(albumListType) || "years".equals(albumListType)) { - setTitle(albumListExtra); - } else if("alphabeticalByName".equals(albumListType)) { - setTitle(R.string.main_albums_alphabetical); - } - - new LoadTask(true) { - @Override - protected MusicDirectory load(MusicService service) throws Exception { - MusicDirectory result; - if ("starred".equals(albumListType)) { - result = service.getStarredList(context, this); - } else if(("genres".equals(albumListType) && ServerInfo.checkServerVersion(context, "1.10.0")) || "years".equals(albumListType)) { - result = service.getAlbumList(albumListType, albumListExtra, size, 0, context, this); - if(result.getChildrenSize() == 0 && "genres".equals(albumListType)) { - SelectDirectoryFragment.this.albumListType = "genres-songs"; - result = service.getSongsByGenre(albumListExtra, size, 0, context, this); - } - } else if("genres".equals(albumListType) || "genres-songs".equals(albumListType)) { - result = service.getSongsByGenre(albumListExtra, size, 0, context, this); - } else { - result = service.getAlbumList(albumListType, size, 0, context, this); - } - return result; - } - }.execute(); - } - - private abstract class LoadTask extends TabBackgroundTask> { - private boolean refresh; - - public LoadTask(boolean refresh) { - super(SelectDirectoryFragment.this); - this.refresh = refresh; - - currentTask = this; - } - - protected abstract MusicDirectory load(MusicService service) throws Exception; - - @Override - protected Pair doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - MusicDirectory dir = load(musicService); - licenseValid = musicService.isLicenseValid(context, this); - - albums = dir.getChildren(true, false); - if(largeAlbums) { - entries = dir.getChildren(false, true); - } else { - entries = dir.getChildren(); - } - - // This isn't really an artist if no albums on it! - if(albums.size() == 0) { - artist = false; - } - - // If artist, we want to load the artist info to use later - if(artist && ServerInfo.hasArtistInfo(context) && !Util.isOffline(context)) { - try { - String artistId; - if(id.indexOf(';') == -1) { - artistId = id; - } else { - artistId = id.substring(0, id.indexOf(';')); - } - - artistInfo = musicService.getArtistInfo(artistId, refresh, false, context, this); - - if(artistInfo == null) { - artistInfoDelayed = artistId; - } - } catch(Exception e) { - Log.w(TAG, "Failed to get Artist Info even though it should be supported"); - } - } - - return new Pair(dir, licenseValid); - } - - @Override - protected void done(Pair result) { - finishLoading(); - currentTask = null; - } - } - - private void finishLoading() { - // Show header if not album list type and not root and not artist - // For Subsonic 5.1+ display a header for artists with getArtistInfo data if it exists - View header = null; - if(albumListType == null && !"root".equals(id) && (!artist || artistInfo != null || artistInfoDelayed != null)) { - header = createHeader(); - - if(header != null && artistInfoDelayed != null) { - final View finalHeader = header.findViewById(R.id.select_album_header); - final View headerProgress = header.findViewById(R.id.header_progress); - - finalHeader.setVisibility(View.INVISIBLE); - headerProgress.setVisibility(View.VISIBLE); - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - artistInfo = musicService.getArtistInfo(artistInfoDelayed, false, true, context, this); - - return null; - } - - @Override - protected void done(Void result) { - /*if(albumList instanceof HeaderGridView) { - HeaderGridView headerGridView = (HeaderGridView) albumList; - headerGridView.invalidateRowHeight(); - ((BaseAdapter) headerGridView.getAdapter()).notifyDataSetChanged(); - }*/ - - setupCoverArt(finalHeader); - setupTextDisplay(finalHeader); - setupButtonEvents(finalHeader); - - finalHeader.setVisibility(View.VISIBLE); - headerProgress.setVisibility(View.GONE); - } - }.execute(); - } - - // Only add header to entry list if we aren't going recreate album grid as root anyways - if(header != null && entryList != null && (!addAlbumHeader || entries.size() > 0)) { - entryList.addHeaderView(header, null, false); - header = null; - } - } - - // Needs to be added here, GB crashes if you to try to remove the header view before adapter is set - if(addAlbumHeader) { - if(entries.size() > 0 || playlistId != null || podcastId != null) { - entryList.addHeaderView(albumList); - } else { - ViewGroup rootGroup = (ViewGroup) rootView.findViewById(R.id.select_album_layout); - albumList = (GridView) context.getLayoutInflater().inflate(R.layout.grid_view, rootGroup, false); - rootGroup.removeView(entryList); - rootGroup.addView(albumList); - - setupScrollList(albumList); - setupAlbumList(); - - // This should only not be null for a artist with only albums - if(header != null) { - HeaderGridView headerGridView = (HeaderGridView) albumList; - headerGridView.addHeaderView(header); - } - } - addAlbumHeader = false; - } - - boolean validData = !entries.isEmpty() || !albums.isEmpty(); - if(!validData) { - setEmpty(true); - } - // Always going to have entries in entryAdapter - entryAdapter = new EntryAdapter(context, getImageLoader(), entries, (podcastId == null)); - ListAdapter listAdapter = entryAdapter; - // Song-only genre needs to always be entry list + infinite adapter - if("genres-songs".equals(albumListType)) { - ViewGroup rootGroup = (ViewGroup) rootView.findViewById(R.id.select_album_layout); - if(rootGroup.findViewById(R.id.gridview) != null && largeAlbums) { - rootGroup.removeView(albumList); - rootGroup.addView(entryList); - } - - listAdapter = new AlbumListAdapter(context, entryAdapter, albumListType, albumListExtra, albumListSize); - } else if(albumListType == null || "starred".equals(albumListType)) { - // Only set standard album adapter if not album list and largeAlbums is true - if(largeAlbums) { - albumList.setAdapter(new AlbumGridAdapter(context, getImageLoader(), albums, !artist)); - } - } else { - // If album list, use infinite adapters for either depending on whether or not largeAlbums is true - if(largeAlbums) { - albumList.setAdapter(new AlbumListAdapter(context, new AlbumGridAdapter(context, getImageLoader(), albums, true), albumListType, albumListExtra, albumListSize)); - } else { - listAdapter = new AlbumListAdapter(context, entryAdapter, albumListType, albumListExtra, albumListSize); - } - } - entryList.setAdapter(listAdapter); - if(validData) { - entryList.setVisibility(View.VISIBLE); - } - context.supportInvalidateOptionsMenu(); - - if(lookupEntry != null) { - for(int i = 0; i < entries.size(); i++) { - if(lookupEntry.equals(entries.get(i).getTitle())) { - entryList.setSelection(i + entryList.getHeaderViewsCount()); - lookupEntry = null; - break; - } - } - } - - Bundle args = getArguments(); - boolean playAll = args.getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false); - if (playAll && !restoredInstance) { - playAll(args.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, false), false); - } - } - - private void setupAlbumList() { - albumList.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Entry entry = (Entry) parent.getItemAtPosition(position); - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle()); - args.putSerializable(Constants.INTENT_EXTRA_NAME_DIRECTORY, entry); - if ("newest".equals(albumListType)) { - args.putBoolean(Constants.INTENT_EXTRA_REFRESH_LISTINGS, true); - } - if(entry.getArtist() == null && entry.getParent() == null) { - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - } - fragment.setArguments(args); - - replaceFragment(fragment, true); - } - }); - - registerForContextMenu(entryList); - registerForContextMenu(albumList); - } - - private void playNow(final boolean shuffle, final boolean append) { - playNow(shuffle, append, false); - } - private void playNow(final boolean shuffle, final boolean append, final boolean playNext) { - if(getSelectedSongs().size() > 0) { - download(append, false, !append, playNext, shuffle); - selectAll(false, false); - } - else { - playAll(shuffle, append); - } - } - private void playAll(final boolean shuffle, final boolean append) { - boolean hasSubFolders = false; - for (int i = 0; i < entryList.getCount(); i++) { - Entry entry = (Entry) entryList.getItemAtPosition(i); - if (entry != null && entry.isDirectory()) { - hasSubFolders = true; - break; - } - } - if(albums.size() > 0) { - hasSubFolders = true; - } - - if (hasSubFolders && (id != null || share != null || "starred".equals(albumListType))) { - downloadRecursively(id, false, append, !append, shuffle, false); - } else if(hasSubFolders && albumListType != null) { - downloadRecursively(albums, shuffle, append); - } else { - selectAll(true, false); - download(append, false, !append, false, shuffle); - selectAll(false, false); - } - } - - private void selectAll(boolean selected, boolean toast) { - int count = entryList.getCount(); - int selectedCount = 0; - for (int i = 0; i < count; i++) { - Entry entry = (Entry) entryList.getItemAtPosition(i); - if (entry != null && !entry.isDirectory() && !entry.isVideo()) { - entryList.setItemChecked(i, selected); - selectedCount++; - } - } - - // Display toast: N tracks selected / N tracks unselected - if (toast) { - int toastResId = selected ? R.string.select_album_n_selected - : R.string.select_album_n_unselected; - Util.toast(context, context.getString(toastResId, selectedCount)); - } - } - - private List getSelectedSongs() { - List songs = new ArrayList(10); - int count = entryList.getCount(); - for (int i = 0; i < count; i++) { - if (entryList.isItemChecked(i)) { - Entry entry = (Entry) entryList.getItemAtPosition(i); - // Don't try to add directories or 1-starred songs - if(!entry.isDirectory() && entry.getRating() != 1) { - songs.add(entry); - } - } - } - return songs; - } - - private List getSelectedIndexes() { - List indexes = new ArrayList(); - - int count = entryList.getCount(); - int headers = entryList.getHeaderViewsCount(); - for (int i = 0; i < count; i++) { - if (entryList.isItemChecked(i)) { - indexes.add(i - headers); - } - } - - return indexes; - } - - private void download(final boolean append, final boolean save, final boolean autoplay, final boolean playNext, final boolean shuffle) { - if (getDownloadService() == null) { - return; - } - - final List songs = getSelectedSongs(); - warnIfStorageUnavailable(); - - // Conditions for using play now button - if(!append && !save && autoplay && !playNext && !shuffle) { - // Call playNow which goes through and tries to use bookmark information - playNow(songs, playlistName, playlistId); - return; - } - - LoadingTask onValid = new LoadingTask(context) { - @Override - protected Void doInBackground() throws Throwable { - if (!append) { - getDownloadService().clear(); - } - - getDownloadService().download(songs, save, autoplay, playNext, shuffle); - if (playlistName != null) { - getDownloadService().setSuggestedPlaylistName(playlistName, playlistId); - } else { - getDownloadService().setSuggestedPlaylistName(null, null); - } - return null; - } - - @Override - protected void done(Void result) { - if (autoplay) { - Util.startActivityWithoutTransition(context, DownloadActivity.class); - } else if (save) { - Util.toast(context, - context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size())); - } else if (append) { - Util.toast(context, - context.getResources().getQuantityString(R.plurals.select_album_n_songs_added, songs.size(), songs.size())); - } - } - }; - - checkLicenseAndTrialPeriod(onValid); - } - private void downloadBackground(final boolean save) { - if(playlistId != null) { - selectAll(true, false); - } - - List songs = getSelectedSongs(); - if(songs.isEmpty()) { - // Get both songs and albums - downloadRecursively(id, save, false, false, false, true); - } else { - downloadBackground(save, songs); - } - } - private void downloadBackground(final boolean save, final List songs) { - if (getDownloadService() == null) { - return; - } - - warnIfStorageUnavailable(); - LoadingTask onValid = new LoadingTask(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().downloadBackground(songs, save); - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size())); - } - }; - - checkLicenseAndTrialPeriod(onValid); - } - - private void delete() { - List songs = getSelectedSongs(); - if(songs.isEmpty()) { - selectAll(true, false); - songs = getSelectedSongs(); - - // Also delete all directories - for(Entry album: albums) { - deleteRecursively(album); - } - } - if (getDownloadService() != null) { - getDownloadService().delete(songs); - } - } - - public void removeFromPlaylist(final String id, final String name, final List indexes) { - new LoadingTask(context, true) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.removeFromPlaylist(id, indexes, context, null); - return null; - } - - @Override - protected void done(Void result) { - for(int i = indexes.size() - 1; i >= 0; i--) { - entryList.setItemChecked(indexes.get(i) + 1, false); - entryAdapter.removeAt(indexes.get(i)); - } - entryAdapter.notifyDataSetChanged(); - Util.toast(context, context.getResources().getString(R.string.removed_playlist, indexes.size(), name)); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.updated_playlist_error, name) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - public void downloadAllPodcastEpisodes() { - new LoadingTask(context, true) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - - for(int i = 0; i < entries.size(); i++) { - PodcastEpisode episode = (PodcastEpisode) entries.get(i); - if("skipped".equals(episode.getStatus())) { - musicService.downloadPodcastEpisode(episode.getEpisodeId(), context, null); - } - } - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, context.getResources().getString(R.string.select_podcasts_downloading, podcastName)); - } - - @Override - protected void error(Throwable error) { - Util.toast(context, getErrorMessage(error), false); - } - }.execute(); - } - - public void downloadPodcastEpisode(final PodcastEpisode episode) { - new LoadingTask(context, true) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.downloadPodcastEpisode(episode.getEpisodeId(), context, null); - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, context.getResources().getString(R.string.select_podcasts_downloading, episode.getTitle())); - } - - @Override - protected void error(Throwable error) { - Util.toast(context, getErrorMessage(error), false); - } - }.execute(); - } - - public void deletePodcastEpisode(final PodcastEpisode episode) { - Util.confirmDialog(context, R.string.common_delete, episode.getTitle(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new LoadingTask(context, true) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.deletePodcastEpisode(episode.getEpisodeId(), episode.getParent(), null, context); - if (getDownloadService() != null) { - List episodeList = new ArrayList(1); - episodeList.add(episode); - getDownloadService().delete(episodeList); - } - return null; - } - - @Override - protected void done(Void result) { - entries.remove(episode); - entryAdapter.notifyDataSetChanged(); - } - - @Override - protected void error(Throwable error) { - Log.w(TAG, "Failed to delete podcast episode", error); - Util.toast(context, getErrorMessage(error), false); - } - }.execute(); - } - }); - } - - public void unstarSelected() { - List selected = getSelectedSongs(); - if(selected.size() == 0) { - selected = entries; - } - if(selected.size() == 0) { - return; - } - final List unstar = new ArrayList(); - unstar.addAll(selected); - - new LoadingTask(context, true) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - List entries = new ArrayList(); - List artists = new ArrayList(); - List albums = new ArrayList(); - for(Entry entry: unstar) { - if(entry.isDirectory()) { - if(entry.isAlbum()) { - albums.add(entry); - } else { - artists.add(entry); - } - } else { - entries.add(entry); - } - } - musicService.setStarred(entries, artists, albums, false, this, context); - - for(Entry entry: unstar) { - new EntryInstanceUpdater(entry) { - @Override - public void update(Entry found) { - found.setStarred(false); - } - }.execute(); - } - - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, context.getResources().getString(R.string.starring_content_unstarred, Integer.toString(unstar.size()))); - - for(Entry entry: unstar) { - entries.remove(entry); - } - entryAdapter.notifyDataSetChanged(); - selectAll(false, false); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.starring_content_error, Integer.toString(unstar.size())) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - private void checkLicenseAndTrialPeriod(LoadingTask onValid) { - if (licenseValid) { - onValid.execute(); - return; - } - - int trialDaysLeft = Util.getRemainingTrialDays(context); - Log.i(TAG, trialDaysLeft + " trial days left."); - - if (trialDaysLeft == 0) { - showDonationDialog(trialDaysLeft, null); - } else if (trialDaysLeft < Constants.FREE_TRIAL_DAYS / 2) { - showDonationDialog(trialDaysLeft, onValid); - } else { - Util.toast(context, context.getResources().getString(R.string.select_album_not_licensed, trialDaysLeft)); - onValid.execute(); - } - } - - private void showDonationDialog(int trialDaysLeft, final LoadingTask onValid) { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setIcon(android.R.drawable.ic_dialog_info); - - if (trialDaysLeft == 0) { - builder.setTitle(R.string.select_album_donate_dialog_0_trial_days_left); - } else { - builder.setTitle(context.getResources().getQuantityString(R.plurals.select_album_donate_dialog_n_trial_days_left, - trialDaysLeft, trialDaysLeft)); - } - - builder.setMessage(R.string.select_album_donate_dialog_message); - - builder.setPositiveButton(R.string.select_album_donate_dialog_now, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(Constants.DONATION_URL))); - } - }); - - builder.setNegativeButton(R.string.select_album_donate_dialog_later, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.dismiss(); - if (onValid != null) { - onValid.execute(); - } - } - }); - - builder.create().show(); - } - - private void showTopTracks() { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(getArguments()); - args.putBoolean(Constants.INTENT_EXTRA_TOP_TRACKS, true); - fragment.setArguments(args); - - replaceFragment(fragment, true); - } - - private void setShowAll() { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(getArguments()); - args.putBoolean(Constants.INTENT_EXTRA_SHOW_ALL, true); - fragment.setArguments(args); - - replaceFragment(fragment, true); - } - - private void showSimilarArtists(String artistId) { - SubsonicFragment fragment = new SimilarArtistFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ARTIST, artistId); - fragment.setArguments(args); - - replaceFragment(fragment, true); - } - - private void startArtistRadio(final String artistId) { - new LoadingTask(context) { - @Override - protected Void doInBackground() throws Throwable { - DownloadService downloadService = getDownloadService(); - downloadService.setArtistRadio(artistId); - if(downloadService.size() == 0) { - Log.e(TAG, "Failed to create artist radio"); - throw new Exception("Failed to create artist radio"); - } - return null; - } - - @Override - protected void done(Void result) { - Util.startActivityWithoutTransition(context, DownloadActivity.class); - } - }.execute(); - } - - private View createHeader() { - View header = entryList.findViewById(R.id.select_album_header_wrapper); - boolean add = false; - if(header == null) { - header = LayoutInflater.from(context).inflate(R.layout.select_album_header, entryList, false); - add = true; - } - - setupCoverArt(header); - setupTextDisplay(header); - - if(add) { - setupButtonEvents(header); - } - - if(add) { - return header; - } else { - return null; - } - } - - private void setupCoverArt(View header) { - final ImageLoader imageLoader = getImageLoader(); - View coverArtView = header.findViewById(R.id.select_album_art); - - // Try a few times to get a random cover art - if(artistInfo != null) { - final String url = artistInfo.getImageUrl(); - coverArtView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (url == null) { - return; - } - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - ImageView fullScreenView = new ImageView(context); - imageLoader.loadImage(fullScreenView, url, true); - builder.setCancelable(true); - - AlertDialog imageDialog = builder.create(); - // Set view here with unecessary 0's to remove top/bottom border - imageDialog.setView(fullScreenView, 0, 0, 0, 0); - imageDialog.show(); - } - }); - imageLoader.loadImage(coverArtView, url, false); - } else if(entries.size() > 0) { - Entry coverArt = null; - for (int i = 0; (i < 3) && (coverArt == null || coverArt.getCoverArt() == null); i++) { - coverArt = entries.get(random.nextInt(entries.size())); - } - - final Entry albumRep = coverArt; - coverArtView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (albumRep.getCoverArt() == null) { - return; - } - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - ImageView fullScreenView = new ImageView(context); - imageLoader.loadImage(fullScreenView, albumRep, true, true); - builder.setCancelable(true); - - AlertDialog imageDialog = builder.create(); - // Set view here with unecessary 0's to remove top/bottom border - imageDialog.setView(fullScreenView, 0, 0, 0, 0); - imageDialog.show(); - } - }); - imageLoader.loadImage(coverArtView, albumRep, false, true); - } - } - private void setupTextDisplay(final View header) { - final TextView titleView = (TextView) header.findViewById(R.id.select_album_title); - if(playlistName != null) { - titleView.setText(playlistName); - } else if(podcastName != null) { - titleView.setText(podcastName); - titleView.setPadding(0, 6, 4, 8); - } else if(name != null) { - titleView.setText(name); - - if(artistInfo != null) { - titleView.setPadding(0, 6, 4, 8); - } - } else if(share != null) { - titleView.setVisibility(View.GONE); - } - - int songCount = 0; - - Set artists = new HashSet(); - Set years = new HashSet(); - Integer totalDuration = 0; - for (Entry entry : entries) { - if (!entry.isDirectory()) { - songCount++; - if (entry.getArtist() != null) { - artists.add(entry.getArtist()); - } - if(entry.getYear() != null) { - years.add(entry.getYear()); - } - Integer duration = entry.getDuration(); - if(duration != null) { - totalDuration += duration; - } - } - } - - final TextView artistView = (TextView) header.findViewById(R.id.select_album_artist); - if(podcastDescription != null || artistInfo != null) { - artistView.setVisibility(View.VISIBLE); - String text = podcastDescription != null ? podcastDescription : artistInfo.getBiography(); - Spanned spanned = null; - if(text != null) { - spanned = Html.fromHtml(text); - } - artistView.setText(spanned); - artistView.setSingleLine(false); - final int minLines = context.getResources().getInteger(R.integer.TextDescriptionLength); - artistView.setLines(minLines); - artistView.setTextAppearance(context, android.R.style.TextAppearance_Small); - - final Spanned spannedText = spanned; - artistView.setOnClickListener(new View.OnClickListener() { - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - @Override - public void onClick(View v) { - if(artistView.getMaxLines() == minLines) { - // Use LeadingMarginSpan2 to try to make text flow around image - Display display = context.getWindowManager().getDefaultDisplay(); - ImageView coverArtView = (ImageView) header.findViewById(R.id.select_album_art); - coverArtView.measure(display.getWidth(), display.getHeight()); - - int height, width; - ViewGroup.MarginLayoutParams vlp = (ViewGroup.MarginLayoutParams) coverArtView.getLayoutParams(); - if(coverArtView.getDrawable() != null) { - height = coverArtView.getMeasuredHeight() + coverArtView.getPaddingBottom(); - width = coverArtView.getWidth() + coverArtView.getPaddingRight(); - } else { - height = coverArtView.getHeight(); - width = coverArtView.getWidth() + coverArtView.getPaddingRight(); - } - float textLineHeight = artistView.getPaint().getTextSize(); - int lines = (int) Math.ceil(height / textLineHeight); - - SpannableString ss = new SpannableString(spannedText); - ss.setSpan(new MyLeadingMarginSpan2(lines, width), 0, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - - View linearLayout = header.findViewById(R.id.select_album_text_layout); - RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) linearLayout.getLayoutParams(); - int[]rules = params.getRules(); - rules[RelativeLayout.RIGHT_OF] = 0; - params.leftMargin = vlp.rightMargin; - - artistView.setText(ss); - artistView.setMaxLines(100); - - vlp = (ViewGroup.MarginLayoutParams) titleView.getLayoutParams(); - vlp.leftMargin = width; - } else { - artistView.setMaxLines(minLines); - } - - if(albumList instanceof HeaderGridView) { - HeaderGridView headerGridView = (HeaderGridView) albumList; - ((BaseAdapter) headerGridView.getAdapter()).notifyDataSetChanged(); - } - } - }); - artistView.setMovementMethod(LinkMovementMethod.getInstance()); - } else if(topTracks) { - artistView.setText(R.string.menu_top_tracks); - artistView.setVisibility(View.VISIBLE); - } else if(showAll) { - artistView.setText(R.string.menu_show_all); - artistView.setVisibility(View.VISIBLE); - } else if (artists.size() == 1) { - String artistText = artists.iterator().next(); - if(years.size() == 1) { - artistText += " - " + years.iterator().next(); - } - artistView.setText(artistText); - artistView.setVisibility(View.VISIBLE); - } else { - artistView.setVisibility(View.GONE); - } - - TextView songCountView = (TextView) header.findViewById(R.id.select_album_song_count); - TextView songLengthView = (TextView) header.findViewById(R.id.select_album_song_length); - if(podcastDescription != null || artistInfo != null) { - songCountView.setVisibility(View.GONE); - songLengthView.setVisibility(View.GONE); - } else { - String s = context.getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount); - songCountView.setText(s.toUpperCase()); - songLengthView.setText(Util.formatDuration(totalDuration)); - } - } - private void setupButtonEvents(View header) { - ImageView shareButton = (ImageView) header.findViewById(R.id.select_album_share); - if(share != null || podcastId != null || !Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_MENU_SHARED, true) || Util.isOffline(context) || !UserUtil.canShare() || artistInfo != null) { - shareButton.setVisibility(View.GONE); - } else { - shareButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - createShare(SelectDirectoryFragment.this.entries); - } - }); - } - - final ImageButton starButton = (ImageButton) header.findViewById(R.id.select_album_star); - if(directory != null && Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_MENU_STAR, true) && artistInfo == null) { - starButton.setImageResource(directory.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); - starButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - toggleStarred(directory, new OnStarChange() { - @Override - void starChange(boolean starred) { - starButton.setImageResource(directory.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); - } - }); - } - }); - } else { - starButton.setVisibility(View.GONE); - } - - View ratingBarWrapper = header.findViewById(R.id.select_album_rate_wrapper); - final RatingBar ratingBar = (RatingBar) header.findViewById(R.id.select_album_rate); - if(directory != null && Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_MENU_RATING, true) && !Util.isOffline(context) && artistInfo == null) { - ratingBar.setRating(directory.getRating()); - ratingBarWrapper.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - setRating(directory, new OnRatingChange() { - @Override - void ratingChange(int rating) { - ratingBar.setRating(directory.getRating()); - } - }); - } - }); - } else { - ratingBar.setVisibility(View.GONE); - } - } -} diff --git a/src/github/daneren2005/dsub/fragments/SelectGenreFragment.java b/src/github/daneren2005/dsub/fragments/SelectGenreFragment.java deleted file mode 100644 index 4068dca2..00000000 --- a/src/github/daneren2005/dsub/fragments/SelectGenreFragment.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.fragments; - -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.adapter.GenreAdapter; - -import java.util.List; - -public class SelectGenreFragment extends SelectListFragment { - private static final String TAG = SelectGenreFragment.class.getSimpleName(); - - @Override - public int getOptionsMenu() { - return R.menu.empty; - } - - @Override - public ArrayAdapter getAdapter(List objs) { - return new GenreAdapter(context, objs); - } - - @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - return musicService.getGenres(refresh, context, listener); - } - - @Override - public int getTitleResource() { - return R.string.main_albums_genres; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Genre genre = (Genre) parent.getItemAtPosition(position); - - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, "genres"); - args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); - args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); - args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, genre.getName()); - fragment.setArguments(args); - - replaceFragment(fragment); - } -} diff --git a/src/github/daneren2005/dsub/fragments/SelectListFragment.java b/src/github/daneren2005/dsub/fragments/SelectListFragment.java deleted file mode 100644 index 749ef842..00000000 --- a/src/github/daneren2005/dsub/fragments/SelectListFragment.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.fragments; - -import android.os.Bundle; -import android.support.v4.widget.SwipeRefreshLayout; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.ListView; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.BackgroundTask; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.TabBackgroundTask; - -public abstract class SelectListFragment extends SubsonicFragment implements AdapterView.OnItemClickListener { - private static final String TAG = SelectListFragment.class.getSimpleName(); - protected ListView listView; - protected ArrayAdapter adapter; - protected BackgroundTask> currentTask; - protected List objects; - protected boolean serialize = true; - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - - if(bundle != null && serialize) { - objects = (List) bundle.getSerializable(Constants.FRAGMENT_LIST); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if(serialize) { - outState.putSerializable(Constants.FRAGMENT_LIST, (Serializable) objects); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false); - - refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); - refreshLayout.setOnRefreshListener(this); - - listView = (ListView)rootView.findViewById(R.id.fragment_list); - listView.setOnItemClickListener(this); - setupScrollList(listView); - registerForContextMenu(listView); - - if(objects == null) { - refresh(false); - } else { - listView.setAdapter(adapter = getAdapter(objects)); - } - - return rootView; - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - if(!primaryFragment) { - return; - } - - menuInflater.inflate(getOptionsMenu(), menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - return super.onOptionsItemSelected(item); - } - - @Override - protected void refresh(final boolean refresh) { - int titleRes = getTitleResource(); - if(titleRes != 0) { - setTitle(getTitleResource()); - } - listView.setVisibility(View.GONE); - - // Cancel current running task before starting another one - if(currentTask != null) { - currentTask.cancel(); - } - - currentTask = new TabBackgroundTask>(this) { - @Override - protected List doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - - objects = new ArrayList(); - - try { - objects = getObjects(musicService, refresh, this); - } catch (Exception x) { - Log.e(TAG, "Failed to load", x); - } - - return objects; - } - - @Override - protected void done(List result) { - if (result != null && !result.isEmpty()) { - // Toggle fast scroll to get around issue when length of list changes - listView.setFastScrollEnabled(false); - listView.setAdapter(adapter = getAdapter(result)); - listView.setFastScrollEnabled(true); - - onFinishRefresh(); - listView.setVisibility(View.VISIBLE); - } else { - setEmpty(true); - } - - currentTask = null; - } - }; - currentTask.execute(); - } - - public abstract int getOptionsMenu(); - public abstract ArrayAdapter getAdapter(List objs); - public abstract List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception; - public abstract int getTitleResource(); - - public void onFinishRefresh() { - - } -} diff --git a/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java b/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java deleted file mode 100644 index af372076..00000000 --- a/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java +++ /dev/null @@ -1,303 +0,0 @@ -package github.daneren2005.dsub.fragments; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.v4.app.FragmentTransaction; -import android.view.ContextMenu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.CheckBox; -import android.widget.EditText; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.service.OfflineException; -import github.daneren2005.dsub.service.ServerTooOldException; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.util.CacheCleaner; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.LoadingTask; -import github.daneren2005.dsub.util.UserUtil; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.PlaylistAdapter; - -import java.util.List; - -public class SelectPlaylistFragment extends SelectListFragment { - private static final String TAG = SelectPlaylistFragment.class.getSimpleName(); - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - MenuInflater inflater = context.getMenuInflater(); - if (Util.isOffline(context)) { - inflater.inflate(R.menu.select_playlist_context_offline, menu); - } - else { - inflater.inflate(R.menu.select_playlist_context, menu); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Playlist playlist = (Playlist) listView.getItemAtPosition(info.position); - if(SyncUtil.isSyncedPlaylist(context, playlist.getId())) { - menu.removeItem(R.id.playlist_menu_sync); - } else { - menu.removeItem(R.id.playlist_menu_stop_sync); - } - - if(!ServerInfo.checkServerVersion(context, "1.8")) { - menu.removeItem(R.id.playlist_update_info); - } else if(playlist.getPublic() != null && playlist.getPublic() == true && playlist.getId().indexOf(".m3u") == -1 && !UserUtil.getCurrentUsername(context).equals(playlist.getOwner())) { - menu.removeItem(R.id.playlist_update_info); - menu.removeItem(R.id.playlist_menu_delete); - } - } - - recreateContextMenu(menu); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Playlist playlist = (Playlist) listView.getItemAtPosition(info.position); - - SubsonicFragment fragment; - Bundle args; - FragmentTransaction trans; - switch (menuItem.getItemId()) { - case R.id.playlist_menu_download: - downloadPlaylist(playlist.getId(), playlist.getName(), false, true, false, false, true); - break; - case R.id.playlist_menu_sync: - syncPlaylist(playlist); - break; - case R.id.playlist_menu_stop_sync: - stopSyncPlaylist(playlist); - break; - case R.id.playlist_menu_play_now: - fragment = new SelectDirectoryFragment(); - args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); - args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); - fragment.setArguments(args); - - replaceFragment(fragment); - break; - case R.id.playlist_menu_play_shuffled: - fragment = new SelectDirectoryFragment(); - args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); - args.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); - args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); - fragment.setArguments(args); - - replaceFragment(fragment); - break; - case R.id.playlist_menu_delete: - deletePlaylist(playlist); - break; - case R.id.playlist_info: - displayPlaylistInfo(playlist); - break; - case R.id.playlist_update_info: - updatePlaylistInfo(playlist); - break; - default: - return false; - } - return true; - } - - @Override - public int getOptionsMenu() { - return R.menu.abstract_top_menu; - } - - @Override - public ArrayAdapter getAdapter(List playlists) { - return new PlaylistAdapter(context, playlists); - } - - @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - List playlists = musicService.getPlaylists(refresh, context, listener); - if(!Util.isOffline(context) && refresh) { - new CacheCleaner(context, getDownloadService()).cleanPlaylists(playlists); - } - return playlists; - } - - @Override - public int getTitleResource() { - return R.string.playlist_label; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Playlist playlist = (Playlist) parent.getItemAtPosition(position); - - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); - if(ServerInfo.checkServerVersion(context, "1.8") && (playlist.getOwner() != null && playlist.getOwner().equals(UserUtil.getCurrentUsername(context)) || playlist.getId().indexOf(".m3u") != -1)) { - args.putBoolean(Constants.INTENT_EXTRA_NAME_PLAYLIST_OWNER, true); - } - fragment.setArguments(args); - - replaceFragment(fragment); - } - - private void deletePlaylist(final Playlist playlist) { - Util.confirmDialog(context, R.string.common_delete, playlist.getName(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new LoadingTask(context, false) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.deletePlaylist(playlist.getId(), context, null); - SyncUtil.removeSyncedPlaylist(context, playlist.getId()); - return null; - } - - @Override - protected void done(Void result) { - adapter.remove(playlist); - adapter.notifyDataSetChanged(); - Util.toast(context, context.getResources().getString(R.string.menu_deleted_playlist, playlist.getName())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.menu_deleted_playlist_error, playlist.getName()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - }); - } - - private void displayPlaylistInfo(final Playlist playlist) { - String message = "Owner: " + playlist.getOwner() + "\nComments: " + - ((playlist.getComment() == null) ? "" : playlist.getComment()) + - "\nSong Count: " + playlist.getSongCount() + - ((playlist.getPublic() == null) ? "" : ("\nPublic: " + playlist.getPublic())) + - "\nCreation Date: " + playlist.getCreated().replace('T', ' '); - Util.info(context, playlist.getName(), message); - } - - private void updatePlaylistInfo(final Playlist playlist) { - View dialogView = context.getLayoutInflater().inflate(R.layout.update_playlist, null); - final EditText nameBox = (EditText)dialogView.findViewById(R.id.get_playlist_name); - final EditText commentBox = (EditText)dialogView.findViewById(R.id.get_playlist_comment); - final CheckBox publicBox = (CheckBox)dialogView.findViewById(R.id.get_playlist_public); - - nameBox.setText(playlist.getName()); - commentBox.setText(playlist.getComment()); - Boolean pub = playlist.getPublic(); - if(pub == null) { - publicBox.setEnabled(false); - } else { - publicBox.setChecked(pub); - } - - new AlertDialog.Builder(context) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(R.string.playlist_update_info) - .setView(dialogView) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new LoadingTask(context, false) { - @Override - protected Void doInBackground() throws Throwable { - String name = nameBox.getText().toString(); - String comment = commentBox.getText().toString(); - boolean isPublic = publicBox.isChecked(); - - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.updatePlaylist(playlist.getId(), name, comment, isPublic, context, null); - - playlist.setName(name); - playlist.setComment(comment); - playlist.setPublic(isPublic); - - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, context.getResources().getString(R.string.playlist_updated_info, playlist.getName())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.playlist_updated_info_error, playlist.getName()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - }) - .setNegativeButton(R.string.common_cancel, null) - .show(); - } - - private void syncPlaylist(Playlist playlist) { - SyncUtil.addSyncedPlaylist(context, playlist.getId()); - downloadPlaylist(playlist.getId(), playlist.getName(), true, true, false, false, true); - } - - private void stopSyncPlaylist(final Playlist playlist) { - SyncUtil.removeSyncedPlaylist(context, playlist.getId()); - - new LoadingTask(context, false) { - @Override - protected Void doInBackground() throws Throwable { - // Unpin all of the songs in playlist - MusicService musicService = MusicServiceFactory.getMusicService(context); - MusicDirectory root = musicService.getPlaylist(true, playlist.getId(), playlist.getName(), context, this); - for(MusicDirectory.Entry entry: root.getChildren()) { - DownloadFile file = new DownloadFile(context, entry, false); - file.unpin(); - } - - return null; - } - - @Override - protected void done(Void result) { - - } - }.execute(); - } -} diff --git a/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java b/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java deleted file mode 100644 index 09307476..00000000 --- a/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.fragments; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.service.OfflineException; -import github.daneren2005.dsub.service.ServerTooOldException; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.LoadingTask; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.UserUtil; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.PodcastChannelAdapter; - -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author Scott - */ -public class SelectPodcastsFragment extends SelectListFragment { - private static final String TAG = SelectPodcastsFragment.class.getSimpleName(); - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(super.onOptionsItemSelected(item)) { - return true; - } - - switch (item.getItemId()) { - case R.id.menu_check: - refreshPodcasts(); - break; - case R.id.menu_add_podcast: - addNewPodcast(); - break; - } - - return false; - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - android.view.MenuInflater inflater = context.getMenuInflater(); - if(!Util.isOffline(context) && UserUtil.canPodcast()) { - inflater.inflate(R.menu.select_podcasts_context, menu); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - PodcastChannel podcast = (PodcastChannel) listView.getItemAtPosition(info.position); - if(SyncUtil.isSyncedPodcast(context, podcast.getId())) { - menu.removeItem(R.id.podcast_menu_sync); - } else { - menu.removeItem(R.id.podcast_menu_stop_sync); - } - } else { - inflater.inflate(R.menu.select_podcasts_context_offline, menu); - } - - recreateContextMenu(menu); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - PodcastChannel channel = (PodcastChannel) listView.getItemAtPosition(info.position); - - switch (menuItem.getItemId()) { - case R.id.podcast_menu_sync: - syncPodcast(channel); - break; - case R.id.podcast_menu_stop_sync: - stopSyncPodcast(channel); - break; - case R.id.podcast_channel_info: - displayPodcastInfo(channel); - break; - case R.id.podcast_channel_delete: - deletePodcast(channel); - break; - } - - return true; - } - - @Override - public int getOptionsMenu() { - return (UserUtil.canPodcast() && !Util.isOffline(context)) ? R.menu.select_podcasts : R.menu.abstract_top_menu; - } - - @Override - public ArrayAdapter getAdapter(List channels) { - return new PodcastChannelAdapter(context, channels); - } - - @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - return musicService.getPodcastChannels(refresh, context, listener); - } - - @Override - public int getTitleResource() { - return R.string.button_bar_podcasts; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - PodcastChannel channel = (PodcastChannel) parent.getItemAtPosition(position); - - if("error".equals(channel.getStatus())) { - Util.toast(context, context.getResources().getString(R.string.select_podcasts_invalid_podcast_channel, channel.getErrorMessage() == null ? "error" : channel.getErrorMessage())); - } else if("downloading".equals(channel.getStatus())) { - Util.toast(context, R.string.select_podcasts_initializing); - } else { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_ID, channel.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_NAME, channel.getName()); - args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_DESCRIPTION, channel.getDescription()); - fragment.setArguments(args); - - replaceFragment(fragment); - } - } - - public void refreshPodcasts() { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.refreshPodcasts(context, null); - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, R.string.select_podcasts_refreshing); - } - - @Override - protected void error(Throwable error) { - Util.toast(context, getErrorMessage(error), false); - } - }.execute(); - } - - private void addNewPodcast() { - View dialogView = context.getLayoutInflater().inflate(R.layout.create_podcast, null); - final TextView urlBox = (TextView) dialogView.findViewById(R.id.create_podcast_url); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.menu_add_podcast) - .setView(dialogView) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - addNewPodcast(urlBox.getText().toString()); - } - }) - .setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }) - .setCancelable(true); - - AlertDialog dialog = builder.create(); - dialog.show(); - } - private void addNewPodcast(final String url) { - new LoadingTask(context, false) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.createPodcastChannel(url, context, null); - return null; - } - - @Override - protected void done(Void result) { - refresh(); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.select_podcasts_created_error) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - private void displayPodcastInfo(final PodcastChannel channel) { - String message = ((channel.getName()) == null ? "" : "Title: " + channel.getName()) + - "\nURL: " + channel.getUrl() + - "\nStatus: " + channel.getStatus() + - ((channel.getErrorMessage()) == null ? "" : "\nError Message: " + channel.getErrorMessage()) + - ((channel.getDescription()) == null ? "" : "\n\nDescription: " + channel.getDescription()); - - Util.info(context, channel.getName(), message); - } - - private void deletePodcast(final PodcastChannel channel) { - Util.confirmDialog(context, R.string.common_delete, channel.getName(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new LoadingTask(context, false) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.deletePodcastChannel(channel.getId(), context, null); - stopSyncPodcast(channel); - return null; - } - - @Override - protected void done(Void result) { - adapter.remove(channel); - adapter.notifyDataSetChanged(); - Util.toast(context, context.getResources().getString(R.string.select_podcasts_deleted, channel.getName())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.select_podcasts_deleted_error, channel.getName()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - }); - } - - private void syncPodcast(final PodcastChannel podcast) { - new LoadingTask(context, false) { - @Override - protected MusicDirectory doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - return musicService.getPodcastEpisodes(true, podcast.getId(), context, this); - } - - @Override - protected void done(MusicDirectory result) { - List existingEpisodes = new ArrayList(); - for(MusicDirectory.Entry entry: result.getChildren()) { - String id = entry.getId(); - if(id != null) { - existingEpisodes.add(entry.getId()); - } - } - - SyncUtil.addSyncedPodcast(context, podcast.getId(), existingEpisodes); - } - }.execute(); - } - - private void stopSyncPodcast(PodcastChannel podcast) { - SyncUtil.removeSyncedPodcast(context, podcast.getId()); - } -} diff --git a/src/github/daneren2005/dsub/fragments/SelectShareFragment.java b/src/github/daneren2005/dsub/fragments/SelectShareFragment.java deleted file mode 100644 index d15f170d..00000000 --- a/src/github/daneren2005/dsub/fragments/SelectShareFragment.java +++ /dev/null @@ -1,216 +0,0 @@ -package github.daneren2005.dsub.fragments; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.DatePicker; -import android.widget.EditText; - -import java.util.Date; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Share; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.service.OfflineException; -import github.daneren2005.dsub.service.ServerTooOldException; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.LoadingTask; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.ShareAdapter; - -/** - * Created by Scott on 12/28/13. - */ -public class SelectShareFragment extends SelectListFragment { - private static final String TAG = SelectShareFragment.class.getSimpleName(); - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - android.view.MenuInflater inflater = context.getMenuInflater(); - inflater.inflate(R.menu.select_share_context, menu); - recreateContextMenu(menu); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Share share = (Share) listView.getItemAtPosition(info.position); - - switch (menuItem.getItemId()) { - case R.id.share_menu_share: - shareExternal(share); - break; - case R.id.share_menu_info: - displayShareInfo(share); - break; - case R.id.share_menu_delete: - deleteShare(share); - break; - case R.id.share_update_info: - updateShareInfo(share); - break; - } - - return true; - } - - @Override - public int getOptionsMenu() { - return R.menu.abstract_top_menu; - } - - @Override - public ArrayAdapter getAdapter(List objs) { - return new ShareAdapter(context, objs); - } - - @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - return musicService.getShares(context, listener); - } - - @Override - public int getTitleResource() { - return R.string.button_bar_shares; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Share share = (Share) parent.getItemAtPosition(position); - - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putSerializable(Constants.INTENT_EXTRA_NAME_SHARE, share); - fragment.setArguments(args); - - replaceFragment(fragment); - } - - private void displayShareInfo(final Share share) { - String message = context.getResources().getString(R.string.share_info, - share.getUsername(), (share.getDescription() != null) ? share.getDescription() : "", share.getUrl(), - Util.formatDate(share.getCreated()), Util.formatDate(share.getLastVisited()), Util.formatDate(share.getExpires()), share.getVisitCount()); - Util.info(context, share.getName(), message); - } - - private void updateShareInfo(final Share share) { - View dialogView = context.getLayoutInflater().inflate(R.layout.update_share, null); - final EditText nameBox = (EditText)dialogView.findViewById(R.id.get_share_name); - final DatePicker expireBox = (DatePicker)dialogView.findViewById(R.id.get_share_expire); - final CheckBox noExpiresBox = (CheckBox)dialogView.findViewById(R.id.get_share_no_expire); - - nameBox.setText(share.getDescription()); - Date expires = share.getExpires(); - if(expires != null) { - expireBox.updateDate(expires.getYear() + 1900, expires.getMonth(), expires.getDate()); - } - - boolean noExpires = share.getExpires() == null; - if(noExpires) { - expireBox.setEnabled(false); - noExpiresBox.setChecked(true); - } - - noExpiresBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - expireBox.setEnabled(!isChecked); - } - }); - - new AlertDialog.Builder(context) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(R.string.playlist_update_info) - .setView(dialogView) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new LoadingTask(context, false) { - @Override - protected Void doInBackground() throws Throwable { - Long expiresIn = 0L; - if (!noExpiresBox.isChecked()) { - Date expires = new Date(expireBox.getYear() - 1900, expireBox.getMonth(), expireBox.getDayOfMonth()); - expiresIn = expires.getTime(); - } - - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.updateShare(share.getId(), nameBox.getText().toString(), expiresIn, context, null); - return null; - } - - @Override - protected void done(Void result) { - refresh(); - Util.toast(context, context.getResources().getString(R.string.share_updated_info, share.getName())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.share_updated_info_error, share.getName()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - }) - .setNegativeButton(R.string.common_cancel, null) - .show(); - } - - private void deleteShare(final Share share) { - Util.confirmDialog(context, R.string.common_delete, share.getName(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new LoadingTask(context, false) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.deleteShare(share.getId(), context, null); - return null; - } - - @Override - protected void done(Void result) { - adapter.remove(share); - adapter.notifyDataSetChanged(); - Util.toast(context, context.getResources().getString(R.string.share_deleted, share.getName())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.share_deleted_error, share.getName()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - }); - } -} diff --git a/src/github/daneren2005/dsub/fragments/SelectVideoFragment.java b/src/github/daneren2005/dsub/fragments/SelectVideoFragment.java deleted file mode 100644 index b4d34ff9..00000000 --- a/src/github/daneren2005/dsub/fragments/SelectVideoFragment.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2015 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.fragments; - -import android.view.ContextMenu; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; - -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.adapter.EntryAdapter; - -public class SelectVideoFragment extends SelectListFragment { - @Override - public int getOptionsMenu() { - return R.menu.empty; - } - - @Override - public ArrayAdapter getAdapter(List objs) { - return new EntryAdapter(context, null, objs, false); - } - - @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - MusicDirectory dir = musicService.getVideos(refresh, context, listener); - return dir.getChildren(); - } - - @Override - public int getTitleResource() { - return R.string.main_videos; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - MusicDirectory.Entry entry = (MusicDirectory.Entry) parent.getItemAtPosition(position); - playVideo(entry); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object entry = listView.getItemAtPosition(info.position); - - onCreateContextMenu(menu, view, menuInfo, entry); - recreateContextMenu(menu); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if (menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Object entry = listView.getItemAtPosition(info.position); - - return onContextItemSelected(menuItem, entry); - } -} diff --git a/src/github/daneren2005/dsub/fragments/SelectYearFragment.java b/src/github/daneren2005/dsub/fragments/SelectYearFragment.java deleted file mode 100644 index 03d62307..00000000 --- a/src/github/daneren2005/dsub/fragments/SelectYearFragment.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus -*/ -package github.daneren2005.dsub.fragments; - -import android.os.Bundle; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; - -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ProgressListener; - -/** - * Created by Scott on 12/23/13. - */ -public class SelectYearFragment extends SelectListFragment { - - @Override - public int getOptionsMenu() { - return R.menu.empty; - } - - @Override - public ArrayAdapter getAdapter(List objs) { - return new ArrayAdapter(context, android.R.layout.simple_list_item_1, objs); - } - - @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - List decades = new ArrayList(); - for(int i = 2010; i >= 1920; i -= 10) { - decades.add(i); - } - - return decades; - } - - @Override - public int getTitleResource() { - return R.string.main_albums_year; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Integer decade = (Integer) parent.getItemAtPosition(position); - - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, "years"); - args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); - args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); - args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, Integer.toString(decade)); - fragment.setArguments(args); - - replaceFragment(fragment); - } -} diff --git a/src/github/daneren2005/dsub/fragments/SettingsFragment.java b/src/github/daneren2005/dsub/fragments/SettingsFragment.java deleted file mode 100644 index 3be21a67..00000000 --- a/src/github/daneren2005/dsub/fragments/SettingsFragment.java +++ /dev/null @@ -1,724 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.fragments; - -import android.accounts.Account; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.EditTextPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceCategory; -import android.preference.PreferenceScreen; -import android.text.InputType; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.EditText; - -import java.io.File; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.net.URL; -import java.text.DecimalFormat; -import java.util.LinkedHashMap; -import java.util.Map; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.HeadphoneListenerService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.LoadingTask; -import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.view.ErrorDialog; - -public class SettingsFragment extends PreferenceCompatFragment implements SharedPreferences.OnSharedPreferenceChangeListener { - private final static String TAG = SettingsFragment.class.getSimpleName(); - private final Map serverSettings = new LinkedHashMap(); - private boolean testingConnection; - private ListPreference theme; - private ListPreference maxBitrateWifi; - private ListPreference maxBitrateMobile; - private ListPreference maxVideoBitrateWifi; - private ListPreference maxVideoBitrateMobile; - private ListPreference networkTimeout; - private EditTextPreference cacheLocation; - private ListPreference preloadCountWifi; - private ListPreference preloadCountMobile; - private ListPreference tempLoss; - private ListPreference pauseDisconnect; - private Preference addServerPreference; - private PreferenceCategory serversCategory; - private ListPreference videoPlayer; - private ListPreference syncInterval; - private CheckBoxPreference syncEnabled; - private CheckBoxPreference syncWifi; - private CheckBoxPreference syncNotification; - private CheckBoxPreference syncStarred; - private CheckBoxPreference syncMostRecent; - private CheckBoxPreference replayGain; - private ListPreference replayGainType; - private Preference replayGainBump; - private Preference replayGainUntagged; - private String internalSSID; - private String internalSSIDDisplay; - private EditTextPreference cacheSize; - private ListPreference openToTab; - - private int serverCount = 3; - private SharedPreferences settings; - private DecimalFormat megabyteFromat; - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - View root = super.onCreateView(inflater, container, bundle); - - this.setTitle(getResources().getString(R.string.settings_title)); - initSettings(); - - return root; - } - - @Override - public void onDestroy() { - super.onDestroy(); - - SharedPreferences prefs = Util.getPreferences(context); - prefs.unregisterOnSharedPreferenceChangeListener(this); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - // Random error I have no idea how to reproduce - if(sharedPreferences == null) { - return; - } - - update(); - - if (Constants.PREFERENCES_KEY_HIDE_MEDIA.equals(key)) { - setHideMedia(sharedPreferences.getBoolean(key, false)); - } - else if (Constants.PREFERENCES_KEY_MEDIA_BUTTONS.equals(key)) { - setMediaButtonsEnabled(sharedPreferences.getBoolean(key, true)); - } - else if (Constants.PREFERENCES_KEY_CACHE_LOCATION.equals(key)) { - setCacheLocation(sharedPreferences.getString(key, "")); - } - else if (Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION.equals(key)){ - DownloadService downloadService = DownloadService.getInstance(); - downloadService.setSleepTimerDuration(Integer.parseInt(sharedPreferences.getString(key, "60"))); - } - else if(Constants.PREFERENCES_KEY_SYNC_MOST_RECENT.equals(key)) { - SyncUtil.removeMostRecentSyncFiles(context); - } else if(Constants.PREFERENCES_KEY_REPLAY_GAIN.equals(key) || Constants.PREFERENCES_KEY_REPLAY_GAIN_BUMP.equals(key) || Constants.PREFERENCES_KEY_REPLAY_GAIN_UNTAGGED.equals(key)) { - DownloadService downloadService = DownloadService.getInstance(); - if(downloadService != null) { - downloadService.reapplyVolume(); - } - } else if(Constants.PREFERENCES_KEY_START_ON_HEADPHONES.equals(key)) { - Intent serviceIntent = new Intent(); - serviceIntent.setClassName(context.getPackageName(), HeadphoneListenerService.class.getName()); - - if(sharedPreferences.getBoolean(key, false)) { - context.startService(serviceIntent); - } else { - context.stopService(serviceIntent); - } - } - - scheduleBackup(); - } - - private void initSettings() { - internalSSID = Util.getSSID(context); - if(internalSSID == null) { - internalSSID = ""; - } - internalSSIDDisplay = context.getResources().getString(R.string.settings_server_local_network_ssid_hint, internalSSID); - - theme = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_THEME); - maxBitrateWifi = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI); - maxBitrateMobile = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE); - maxVideoBitrateWifi = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_MAX_VIDEO_BITRATE_WIFI); - maxVideoBitrateMobile = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_MAX_VIDEO_BITRATE_MOBILE); - networkTimeout = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_NETWORK_TIMEOUT); - cacheLocation = (EditTextPreference) this.findPreference(Constants.PREFERENCES_KEY_CACHE_LOCATION); - preloadCountWifi = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT_WIFI); - preloadCountMobile = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT_MOBILE); - tempLoss = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_TEMP_LOSS); - pauseDisconnect = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_PAUSE_DISCONNECT); - serversCategory = (PreferenceCategory) this.findPreference(Constants.PREFERENCES_KEY_SERVER_KEY); - addServerPreference = this.findPreference(Constants.PREFERENCES_KEY_SERVER_ADD); - videoPlayer = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_VIDEO_PLAYER); - syncInterval = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_INTERVAL); - syncEnabled = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_ENABLED); - syncWifi = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_WIFI); - syncNotification = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_NOTIFICATION); - syncStarred = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_STARRED); - syncMostRecent = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_MOST_RECENT); - replayGain = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_REPLAY_GAIN); - replayGainType = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_REPLAY_GAIN_TYPE); - replayGainBump = this.findPreference(Constants.PREFERENCES_KEY_REPLAY_GAIN_BUMP); - replayGainUntagged = this.findPreference(Constants.PREFERENCES_KEY_REPLAY_GAIN_UNTAGGED); - cacheSize = (EditTextPreference) this.findPreference(Constants.PREFERENCES_KEY_CACHE_SIZE); - openToTab = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_OPEN_TO_TAB); - - settings = Util.getPreferences(context); - serverCount = settings.getInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 1); - - this.findPreference("clearCache").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - Util.confirmDialog(context, R.string.common_delete, R.string.common_confirm_message_cache, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new LoadingTask(context, false) { - @Override - protected Void doInBackground() throws Throwable { - FileUtil.deleteMusicDirectory(context); - FileUtil.deleteSerializedCache(context); - FileUtil.deleteArtworkCache(context); - FileUtil.deleteAvatarCache(context); - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, R.string.settings_cache_clear_complete); - } - - @Override - protected void error(Throwable error) { - Util.toast(context, getErrorMessage(error), false); - } - }.execute(); - } - }); - return false; - } - }); - - addServerPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - serverCount++; - String instance = String.valueOf(serverCount); - serversCategory.addPreference(addServer(serverCount)); - - SharedPreferences.Editor editor = settings.edit(); - editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, serverCount); - // Reset set folder ID - editor.putString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + instance, null); - editor.commit(); - - serverSettings.put(instance, new ServerSettings(instance)); - - return true; - } - }); - - this.findPreference(Constants.PREFERENCES_KEY_SYNC_ENABLED).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - Boolean syncEnabled = (Boolean) newValue; - - Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE); - ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, syncEnabled); - ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PODCAST_AUTHORITY, syncEnabled); - - return true; - } - }); - syncInterval.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - Integer syncInterval = Integer.parseInt(((String) newValue)); - - Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE); - ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, new Bundle(), 60L * syncInterval); - ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PODCAST_AUTHORITY, new Bundle(), 60L * syncInterval); - - return true; - } - }); - - serversCategory.setOrderingAsAdded(false); - for (int i = 1; i <= serverCount; i++) { - String instance = String.valueOf(i); - serversCategory.addPreference(addServer(i)); - serverSettings.put(instance, new ServerSettings(instance)); - } - - SharedPreferences prefs = Util.getPreferences(context); - prefs.registerOnSharedPreferenceChangeListener(this); - - update(); - } - - private void scheduleBackup() { - try { - Class managerClass = Class.forName("android.app.backup.BackupManager"); - Constructor managerConstructor = managerClass.getConstructor(Context.class); - Object manager = managerConstructor.newInstance(context); - Method m = managerClass.getMethod("dataChanged"); - m.invoke(manager); - } catch(ClassNotFoundException e) { - Log.e(TAG, "No backup manager found"); - } catch(Throwable t) { - Log.e(TAG, "Scheduling backup failed " + t); - t.printStackTrace(); - } - } - - private void update() { - if (testingConnection) { - return; - } - - theme.setSummary(theme.getEntry()); - maxBitrateWifi.setSummary(maxBitrateWifi.getEntry()); - maxBitrateMobile.setSummary(maxBitrateMobile.getEntry()); - maxVideoBitrateWifi.setSummary(maxVideoBitrateWifi.getEntry()); - maxVideoBitrateMobile.setSummary(maxVideoBitrateMobile.getEntry()); - networkTimeout.setSummary(networkTimeout.getEntry()); - cacheLocation.setSummary(cacheLocation.getText()); - preloadCountWifi.setSummary(preloadCountWifi.getEntry()); - preloadCountMobile.setSummary(preloadCountMobile.getEntry()); - tempLoss.setSummary(tempLoss.getEntry()); - pauseDisconnect.setSummary(pauseDisconnect.getEntry()); - videoPlayer.setSummary(videoPlayer.getEntry()); - syncInterval.setSummary(syncInterval.getEntry()); - openToTab.setSummary(openToTab.getEntry()); - try { - if(megabyteFromat == null) { - megabyteFromat = new DecimalFormat(getResources().getString(R.string.util_bytes_format_megabyte)); - } - - cacheSize.setSummary(megabyteFromat.format((double) Integer.parseInt(cacheSize.getText())).replace(".00", "")); - } catch(Exception e) { - Log.e(TAG, "Failed to format cache size", e); - cacheSize.setSummary(cacheSize.getText()); - } - if(syncEnabled.isChecked()) { - if(!syncInterval.isEnabled()) { - syncInterval.setEnabled(true); - syncWifi.setEnabled(true); - syncNotification.setEnabled(true); - syncStarred.setEnabled(true); - syncMostRecent.setEnabled(true); - } - } else { - if(syncInterval.isEnabled()) { - syncInterval.setEnabled(false); - syncWifi.setEnabled(false); - syncNotification.setEnabled(false); - syncStarred.setEnabled(false); - syncMostRecent.setEnabled(false); - } - } - if(replayGain.isChecked()) { - replayGainType.setEnabled(true); - replayGainBump.setEnabled(true); - replayGainUntagged.setEnabled(true); - } else { - replayGainType.setEnabled(false); - replayGainBump.setEnabled(false); - replayGainUntagged.setEnabled(false); - } - replayGainType.setSummary(replayGainType.getEntry()); - - for (ServerSettings ss : serverSettings.values()) { - ss.update(); - } - } - - private PreferenceScreen addServer(final int instance) { - final PreferenceScreen screen = this.getPreferenceManager().createPreferenceScreen(context); - screen.setTitle(R.string.settings_server_unused); - screen.setKey(Constants.PREFERENCES_KEY_SERVER_KEY + instance); - - final EditTextPreference serverNamePreference = new EditTextPreference(context); - serverNamePreference.setKey(Constants.PREFERENCES_KEY_SERVER_NAME + instance); - serverNamePreference.setDefaultValue(getResources().getString(R.string.settings_server_unused)); - serverNamePreference.setTitle(R.string.settings_server_name); - serverNamePreference.setDialogTitle(R.string.settings_server_name); - - if (serverNamePreference.getText() == null) { - serverNamePreference.setText(getResources().getString(R.string.settings_server_unused)); - } - - serverNamePreference.setSummary(serverNamePreference.getText()); - - final EditTextPreference serverUrlPreference = new EditTextPreference(context); - serverUrlPreference.setKey(Constants.PREFERENCES_KEY_SERVER_URL + instance); - serverUrlPreference.getEditText().setInputType(InputType.TYPE_TEXT_VARIATION_URI); - serverUrlPreference.setDefaultValue("http://yourhost"); - serverUrlPreference.setTitle(R.string.settings_server_address); - serverUrlPreference.setDialogTitle(R.string.settings_server_address); - - if (serverUrlPreference.getText() == null) { - serverUrlPreference.setText("http://yourhost"); - } - - serverUrlPreference.setSummary(serverUrlPreference.getText()); - screen.setSummary(serverUrlPreference.getText()); - - final EditTextPreference serverLocalNetworkSSIDPreference = new EditTextPreference(context) { - @Override - protected void onAddEditTextToDialogView(View dialogView, final EditText editText) { - super.onAddEditTextToDialogView(dialogView, editText); - ViewGroup root = (ViewGroup) ((ViewGroup) dialogView).getChildAt(0); - - Button defaultButton = new Button(getContext()); - defaultButton.setText(internalSSIDDisplay); - defaultButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - editText.setText(internalSSID); - } - }); - root.addView(defaultButton); - } - }; - serverLocalNetworkSSIDPreference.setKey(Constants.PREFERENCES_KEY_SERVER_LOCAL_NETWORK_SSID + instance); - serverLocalNetworkSSIDPreference.setTitle(R.string.settings_server_local_network_ssid); - serverLocalNetworkSSIDPreference.setDialogTitle(R.string.settings_server_local_network_ssid); - - final EditTextPreference serverInternalUrlPreference = new EditTextPreference(context); - serverInternalUrlPreference.setKey(Constants.PREFERENCES_KEY_SERVER_INTERNAL_URL + instance); - serverInternalUrlPreference.getEditText().setInputType(InputType.TYPE_TEXT_VARIATION_URI); - serverInternalUrlPreference.setDefaultValue(""); - serverInternalUrlPreference.setTitle(R.string.settings_server_internal_address); - serverInternalUrlPreference.setDialogTitle(R.string.settings_server_internal_address); - serverInternalUrlPreference.setSummary(serverInternalUrlPreference.getText()); - - final EditTextPreference serverUsernamePreference = new EditTextPreference(context); - serverUsernamePreference.setKey(Constants.PREFERENCES_KEY_USERNAME + instance); - serverUsernamePreference.setTitle(R.string.settings_server_username); - serverUsernamePreference.setDialogTitle(R.string.settings_server_username); - - final EditTextPreference serverPasswordPreference = new EditTextPreference(context); - serverPasswordPreference.setKey(Constants.PREFERENCES_KEY_PASSWORD + instance); - serverPasswordPreference.getEditText().setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); - serverPasswordPreference.setSummary("***"); - serverPasswordPreference.setTitle(R.string.settings_server_password); - - final CheckBoxPreference serverTagPreference = new CheckBoxPreference(context); - serverTagPreference.setKey(Constants.PREFERENCES_KEY_BROWSE_TAGS + instance); - serverTagPreference.setChecked(Util.isTagBrowsing(context, instance)); - serverTagPreference.setSummary(R.string.settings_browse_by_tags_summary); - serverTagPreference.setTitle(R.string.settings_browse_by_tags); - serverPasswordPreference.setDialogTitle(R.string.settings_server_password); - - final CheckBoxPreference serverSyncPreference = new CheckBoxPreference(context); - serverSyncPreference.setKey(Constants.PREFERENCES_KEY_SERVER_SYNC + instance); - serverSyncPreference.setChecked(Util.isSyncEnabled(context, instance)); - serverSyncPreference.setSummary(R.string.settings_server_sync_summary); - serverSyncPreference.setTitle(R.string.settings_server_sync); - - final Preference serverOpenBrowser = new Preference(context); - serverOpenBrowser.setKey(Constants.PREFERENCES_KEY_OPEN_BROWSER); - serverOpenBrowser.setPersistent(false); - serverOpenBrowser.setTitle(R.string.settings_server_open_browser); - serverOpenBrowser.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - openInBrowser(instance); - return true; - } - }); - - Preference serverRemoveServerPreference = new Preference(context); - serverRemoveServerPreference.setKey(Constants.PREFERENCES_KEY_SERVER_REMOVE + instance); - serverRemoveServerPreference.setPersistent(false); - serverRemoveServerPreference.setTitle(R.string.settings_servers_remove); - - serverRemoveServerPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - Util.confirmDialog(context, R.string.common_delete, screen.getTitle().toString(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // Reset values to null so when we ask for them again they are new - serverNamePreference.setText(null); - serverUrlPreference.setText(null); - serverUsernamePreference.setText(null); - serverPasswordPreference.setText(null); - - int activeServer = Util.getActiveServer(context); - for (int i = instance; i <= serverCount; i++) { - Util.removeInstanceName(context, i, activeServer); - } - - serverCount--; - SharedPreferences.Editor editor = settings.edit(); - editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, serverCount); - editor.commit(); - - serversCategory.removePreference(screen); - screen.getDialog().dismiss(); - } - }); - - return true; - } - }); - - Preference serverTestConnectionPreference = new Preference(context); - serverTestConnectionPreference.setKey(Constants.PREFERENCES_KEY_TEST_CONNECTION + instance); - serverTestConnectionPreference.setPersistent(false); - serverTestConnectionPreference.setTitle(R.string.settings_test_connection_title); - serverTestConnectionPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - testConnection(instance); - return false; - } - }); - - screen.addPreference(serverNamePreference); - screen.addPreference(serverUrlPreference); - screen.addPreference(serverInternalUrlPreference); - screen.addPreference(serverLocalNetworkSSIDPreference); - screen.addPreference(serverUsernamePreference); - screen.addPreference(serverPasswordPreference); - screen.addPreference(serverTagPreference); - screen.addPreference(serverSyncPreference); - screen.addPreference(serverTestConnectionPreference); - screen.addPreference(serverOpenBrowser); - screen.addPreference(serverRemoveServerPreference); - - screen.setOrder(instance); - - return screen; - } - - private void setHideMedia(boolean hide) { - File nomediaDir = new File(FileUtil.getSubsonicDirectory(context), ".nomedia"); - File musicNoMedia = new File(FileUtil.getMusicDirectory(context), ".nomedia"); - if (hide && !nomediaDir.exists()) { - try { - if (!nomediaDir.createNewFile()) { - Log.w(TAG, "Failed to create " + nomediaDir); - } - } catch(Exception e) { - Log.w(TAG, "Failed to create " + nomediaDir, e); - } - - try { - if(!musicNoMedia.createNewFile()) { - Log.w(TAG, "Failed to create " + musicNoMedia); - } - } catch(Exception e) { - Log.w(TAG, "Failed to create " + musicNoMedia, e); - } - } else if (nomediaDir.exists()) { - if (!nomediaDir.delete()) { - Log.w(TAG, "Failed to delete " + nomediaDir); - } - if(!musicNoMedia.delete()) { - Log.w(TAG, "Failed to delete " + musicNoMedia); - } - } - Util.toast(context, R.string.settings_hide_media_toast, false); - } - - private void setMediaButtonsEnabled(boolean enabled) { - if (enabled) { - Util.registerMediaButtonEventReceiver(context); - } else { - Util.unregisterMediaButtonEventReceiver(context); - } - } - - private void setCacheLocation(String path) { - File dir = new File(path); - if (!FileUtil.verifyCanWrite(dir)) { - Util.toast(context, R.string.settings_cache_location_error, false); - - // Reset it to the default. - String defaultPath = FileUtil.getDefaultMusicDirectory(context).getPath(); - if (!defaultPath.equals(path)) { - SharedPreferences prefs = Util.getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, defaultPath); - editor.commit(); - cacheLocation.setSummary(defaultPath); - cacheLocation.setText(defaultPath); - } - - // Clear download queue. - DownloadService downloadService = DownloadService.getInstance(); - downloadService.clear(); - } - } - - private void testConnection(final int instance) { - LoadingTask task = new LoadingTask(context) { - private int previousInstance; - - @Override - protected Boolean doInBackground() throws Throwable { - updateProgress(R.string.settings_testing_connection); - - previousInstance = Util.getActiveServer(context); - testingConnection = true; - MusicService musicService = MusicServiceFactory.getMusicService(context); - try { - musicService.setInstance(instance); - musicService.ping(context, this); - return musicService.isLicenseValid(context, null); - } finally { - musicService.setInstance(null); - testingConnection = false; - } - } - - @Override - protected void done(Boolean licenseValid) { - if (licenseValid) { - Util.toast(context, R.string.settings_testing_ok); - } else { - Util.toast(context, R.string.settings_testing_unlicensed); - } - } - - @Override - public void cancel() { - super.cancel(); - Util.setActiveServer(context, previousInstance); - } - - @Override - protected void error(Throwable error) { - Log.w(TAG, error.toString(), error); - new ErrorDialog(context, getResources().getString(R.string.settings_connection_failure) + - " " + getErrorMessage(error), false); - } - }; - task.execute(); - } - - private void openInBrowser(final int instance) { - SharedPreferences prefs = Util.getPreferences(context); - String url = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null); - if(url == null) { - new ErrorDialog(context, R.string.settings_invalid_url, false); - return; - } - Uri uriServer = Uri.parse(url); - - Intent browserIntent = new Intent(Intent.ACTION_VIEW, uriServer); - startActivity(browserIntent); - } - - private class ServerSettings { - private EditTextPreference serverName; - private EditTextPreference serverUrl; - private EditTextPreference serverLocalNetworkSSID; - private EditTextPreference serverInternalUrl; - private EditTextPreference username; - private PreferenceScreen screen; - - private ServerSettings(String instance) { - screen = (PreferenceScreen) SettingsFragment.this.findPreference("server" + instance); - serverName = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_SERVER_NAME + instance); - serverUrl = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_SERVER_URL + instance); - serverLocalNetworkSSID = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_SERVER_LOCAL_NETWORK_SSID + instance); - serverInternalUrl = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_SERVER_INTERNAL_URL + instance); - username = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_USERNAME + instance); - - serverUrl.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object value) { - try { - String url = (String) value; - new URL(url); - if (url.contains(" ") || url.contains("@") || url.contains("_")) { - throw new Exception(); - } - } catch (Exception x) { - new ErrorDialog(context, R.string.settings_invalid_url, false); - return false; - } - return true; - } - }); - serverInternalUrl.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object value) { - try { - String url = (String) value; - // Allow blank internal IP address - if("".equals(url) || url == null) { - return true; - } - - new URL(url); - if (url.contains(" ") || url.contains("@") || url.contains("_")) { - throw new Exception(); - } - } catch (Exception x) { - new ErrorDialog(context, R.string.settings_invalid_url, false); - return false; - } - return true; - } - }); - - username.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object value) { - String username = (String) value; - if (username == null || !username.equals(username.trim())) { - new ErrorDialog(context, R.string.settings_invalid_username, false); - return false; - } - return true; - } - }); - } - - public void update() { - serverName.setSummary(serverName.getText()); - serverUrl.setSummary(serverUrl.getText()); - serverLocalNetworkSSID.setSummary(serverLocalNetworkSSID.getText()); - serverInternalUrl.setSummary(serverInternalUrl.getText()); - username.setSummary(username.getText()); - screen.setSummary(serverUrl.getText()); - screen.setTitle(serverName.getText()); - } - } -} diff --git a/src/github/daneren2005/dsub/fragments/SimilarArtistFragment.java b/src/github/daneren2005/dsub/fragments/SimilarArtistFragment.java deleted file mode 100644 index 79e759cc..00000000 --- a/src/github/daneren2005/dsub/fragments/SimilarArtistFragment.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.fragments; - -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.ArtistInfo; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.ArtistAdapter; - -import java.net.URLEncoder; -import java.util.LinkedList; -import java.util.List; - -public class SimilarArtistFragment extends SelectListFragment { - private static final String TAG = SimilarArtistFragment.class.getSimpleName(); - private ArtistInfo info; - private String artistId; - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - artist = true; - - artistId = getArguments().getString(Constants.INTENT_EXTRA_NAME_ARTIST); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_play_now: - playAll(false); - return true; - case R.id.menu_shuffle: - playAll(true); - return true; - case R.id.menu_show_missing: - showMissingArtists(); - break; - } - - return super.onOptionsItemSelected(item); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object entry = listView.getItemAtPosition(info.position); - onCreateContextMenu(menu, view, menuInfo, entry); - - recreateContextMenu(menu); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Artist artist = (Artist) listView.getItemAtPosition(info.position); - return onContextItemSelected(menuItem, artist); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Artist artist = (Artist) parent.getItemAtPosition(position); - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - fragment.setArguments(args); - - replaceFragment(fragment); - } - - @Override - public int getOptionsMenu() { - return R.menu.similar_artists; - } - - @Override - public ArrayAdapter getAdapter(List objects) { - return new ArtistAdapter(context, objects); - } - - @Override - public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - info = musicService.getArtistInfo(artistId, refresh, true, context, listener); - return info.getSimilarArtists(); - } - - @Override - public int getTitleResource() { - return R.string.menu_similar_artists; - } - - private void showMissingArtists() { - StringBuilder b = new StringBuilder(); - - for(String name: info.getMissingArtists()) { - b.append("

" + name + "

"); - } - - Util.showHTMLDialog(context, R.string.menu_similar_artists, b.toString()); - } - - private void playAll(final boolean shuffle) { - new RecursiveLoader(context) { - @Override - protected Boolean doInBackground() throws Throwable { - musicService = MusicServiceFactory.getMusicService(context); - - MusicDirectory root = new MusicDirectory(); - for(Artist artist: objects) { - if(Util.isTagBrowsing(context) && !Util.isOffline(context)) { - root.addChildren(musicService.getArtist(artist.getId(), artist.getName(), false, context, this).getChildren()); - } else { - root.addChildren(musicService.getMusicDirectory(artist.getId(), artist.getName(), false, context, this).getChildren()); - } - } - - if(shuffle) { - root.shuffleChildren(); - } - - songs = new LinkedList(); - getSongsRecursively(root, songs); - - DownloadService downloadService = getDownloadService(); - if (!songs.isEmpty() && downloadService != null) { - downloadService.clear(); - downloadService.download(songs, false, true, false, false); - } - - return true; - } - }.execute(); - } -} diff --git a/src/github/daneren2005/dsub/fragments/SubsonicFragment.java b/src/github/daneren2005/dsub/fragments/SubsonicFragment.java deleted file mode 100644 index b6b67a7b..00000000 --- a/src/github/daneren2005/dsub/fragments/SubsonicFragment.java +++ /dev/null @@ -1,1817 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.fragments; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.media.MediaMetadataRetriever; -import android.net.Uri; -import android.os.Bundle; -import android.os.StatFs; -import android.support.v4.app.Fragment; -import android.support.v4.widget.SwipeRefreshLayout; -import android.util.Log; -import android.view.ContextMenu; -import android.view.GestureDetector; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.RatingBar; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.DownloadActivity; -import github.daneren2005.dsub.activity.SubsonicActivity; -import github.daneren2005.dsub.activity.SubsonicFragmentActivity; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.Bookmark; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.domain.Share; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MediaStoreService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.service.OfflineException; -import github.daneren2005.dsub.service.ServerTooOldException; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.LoadingTask; -import github.daneren2005.dsub.util.UserUtil; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.view.AlbumCell; -import github.daneren2005.dsub.view.AlbumView; -import github.daneren2005.dsub.view.ArtistEntryView; -import github.daneren2005.dsub.view.ArtistView; -import github.daneren2005.dsub.view.PlaylistSongView; -import github.daneren2005.dsub.view.SongView; -import github.daneren2005.dsub.view.UpdateView; - -import java.io.File; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; - -import static github.daneren2005.dsub.domain.MusicDirectory.Entry; - -public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener { - private static final String TAG = SubsonicFragment.class.getSimpleName(); - private static int TAG_INC = 10; - private int tag; - - protected SubsonicActivity context; - protected CharSequence title = null; - protected CharSequence subtitle = null; - protected View rootView; - protected boolean primaryFragment = false; - protected boolean secondaryFragment = false; - protected boolean invalidated = false; - protected static Random random = new Random(); - protected GestureDetector gestureScanner; - protected Share share; - protected boolean artist = false; - protected boolean artistOverride = false; - protected SwipeRefreshLayout refreshLayout; - protected boolean firstRun; - - public SubsonicFragment() { - super(); - tag = TAG_INC++; - } - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - - if(bundle != null) { - String name = bundle.getString(Constants.FRAGMENT_NAME); - if(name != null) { - title = name; - } - } - firstRun = true; - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if(title != null) { - outState.putString(Constants.FRAGMENT_NAME, title.toString()); - } - } - - @Override - public void onResume() { - super.onResume(); - if(firstRun) { - firstRun = false; - } else { - UpdateView.triggerUpdate(); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - context = (SubsonicActivity)activity; - } - - public void setContext(SubsonicActivity context) { - this.context = context; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_shuffle: - onShuffleRequested(); - return true; - case R.id.menu_search: - context.onSearchRequested(); - return true; - case R.id.menu_exit: - exit(); - return true; - case R.id.menu_refresh: - refresh(); - return true; - } - - return false; - } - - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo, Object selected) { - MenuInflater inflater = context.getMenuInflater(); - - if(selected instanceof Entry) { - Entry entry = (Entry) selected; - if(entry instanceof PodcastEpisode && !entry.isVideo()) { - if(Util.isOffline(context)) { - inflater.inflate(R.menu.select_podcast_episode_context_offline, menu); - } - else { - inflater.inflate(R.menu.select_podcast_episode_context, menu); - - if(entry.getBookmark() == null) { - menu.removeItem(R.id.bookmark_menu_delete); - } - } - } - else if (entry.isDirectory()) { - if(Util.isOffline(context)) { - inflater.inflate(R.menu.select_album_context_offline, menu); - } - else { - inflater.inflate(R.menu.select_album_context, menu); - - if(Util.isTagBrowsing(context)) { - menu.removeItem(R.id.menu_rate); - } - } - menu.findItem(entry.isDirectory() ? R.id.album_menu_star : R.id.song_menu_star).setTitle(entry.isStarred() ? R.string.common_unstar : R.string.common_star); - } else if(!entry.isVideo()) { - if(Util.isOffline(context)) { - inflater.inflate(R.menu.select_song_context_offline, menu); - } - else { - inflater.inflate(R.menu.select_song_context, menu); - - if(entry.getBookmark() == null) { - menu.removeItem(R.id.bookmark_menu_delete); - } - } - menu.findItem(entry.isDirectory() ? R.id.album_menu_star : R.id.song_menu_star).setTitle(entry.isStarred() ? R.string.common_unstar : R.string.common_star); - } else { - if(Util.isOffline(context)) { - inflater.inflate(R.menu.select_video_context_offline, menu); - } - else { - inflater.inflate(R.menu.select_video_context, menu); - } - } - } else if(selected instanceof Artist) { - Artist artist = (Artist) selected; - if(Util.isOffline(context)) { - inflater.inflate(R.menu.select_artist_context_offline, menu); - } - else { - inflater.inflate(R.menu.select_artist_context, menu); - - menu.findItem(R.id.artist_menu_star).setTitle(artist.isStarred() ? R.string.common_unstar : R.string.common_star); - } - } - - hideMenuItems(menu, (AdapterView.AdapterContextMenuInfo) menuInfo); - } - - protected void hideMenuItems(ContextMenu menu, AdapterView.AdapterContextMenuInfo info) { - if(!ServerInfo.checkServerVersion(context, "1.8")) { - menu.setGroupVisible(R.id.server_1_8, false); - menu.setGroupVisible(R.id.hide_star, false); - } - if(!ServerInfo.checkServerVersion(context, "1.9")) { - menu.setGroupVisible(R.id.server_1_9, false); - } - if(!ServerInfo.checkServerVersion(context, "1.10.1")) { - menu.setGroupVisible(R.id.server_1_10, false); - } - - SharedPreferences prefs = Util.getPreferences(context); - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_PLAY_NEXT, true)) { - menu.setGroupVisible(R.id.hide_play_next, false); - } - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_PLAY_LAST, true)) { - menu.setGroupVisible(R.id.hide_play_last, false); - } - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_STAR, true)) { - menu.setGroupVisible(R.id.hide_star, false); - } - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_SHARED, true) || !UserUtil.canShare()) { - menu.setGroupVisible(R.id.hide_share, false); - } - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_RATING, true)) { - menu.setGroupVisible(R.id.hide_rating, false); - } - - if(!Util.isOffline(context)) { - // If we are looking at a standard song view, get downloadFile to cache what options to show - if(info.targetView instanceof SongView) { - SongView songView = (SongView) info.targetView; - DownloadFile downloadFile = songView.getDownloadFile(); - - try { - if(downloadFile != null) { - if(downloadFile.isWorkDone()) { - // Remove permanent cache menu if already perma cached - if(downloadFile.isSaved()) { - menu.removeItem(R.id.song_menu_pin); - } - - // Remove cache option no matter what if already downloaded - menu.removeItem(R.id.song_menu_download); - } else { - // Remove delete option if nothing to delete - menu.removeItem(R.id.song_menu_delete); - } - } - } catch(Exception e) { - Log.w(TAG, "Failed to lookup downloadFile info", e); - } - } - // Apply similar logic to album views - else if(info.targetView instanceof AlbumCell || info.targetView instanceof AlbumView - || info.targetView instanceof ArtistView || info.targetView instanceof ArtistEntryView) { - File folder = null; - int id = 0; - if(info.targetView instanceof AlbumCell) { - folder = ((AlbumCell) info.targetView).getFile(); - id = R.id.album_menu_delete; - } else if(info.targetView instanceof AlbumView) { - folder = ((AlbumView) info.targetView).getFile(); - id = R.id.album_menu_delete; - } else if(info.targetView instanceof ArtistView) { - folder = ((ArtistView) info.targetView).getFile(); - id = R.id.artist_menu_delete; - } else if(info.targetView instanceof ArtistEntryView) { - folder = ((ArtistEntryView) info.targetView).getFile(); - id = R.id.artist_menu_delete; - } - - try { - if(folder != null && !folder.exists()) { - menu.removeItem(id); - } - } catch(Exception e) { - Log.w(TAG, "Failed to lookup album directory info", e); - } - } - } - } - - protected void recreateContextMenu(ContextMenu menu) { - List menuItems = new ArrayList(); - for(int i = 0; i < menu.size(); i++) { - MenuItem item = menu.getItem(i); - if(item.isVisible()) { - menuItems.add(item); - } - } - menu.clear(); - for(int i = 0; i < menuItems.size(); i++) { - MenuItem item = menuItems.get(i); - menu.add(tag, item.getItemId(), Menu.NONE, item.getTitle()); - } - } - - public boolean onContextItemSelected(MenuItem menuItem, Object selectedItem) { - Artist artist = selectedItem instanceof Artist ? (Artist) selectedItem : null; - Entry entry = selectedItem instanceof Entry ? (Entry) selectedItem : null; - List songs = new ArrayList(1); - songs.add(entry); - - switch (menuItem.getItemId()) { - case R.id.artist_menu_play_now: - downloadRecursively(artist.getId(), false, false, true, false, false); - break; - case R.id.artist_menu_play_shuffled: - downloadRecursively(artist.getId(), false, false, true, true, false); - break; - case R.id.artist_menu_play_next: - downloadRecursively(artist.getId(), false, true, false, false, false, true); - break; - case R.id.artist_menu_play_last: - downloadRecursively(artist.getId(), false, true, false, false, false); - break; - case R.id.artist_menu_download: - downloadRecursively(artist.getId(), false, true, false, false, true); - break; - case R.id.artist_menu_pin: - downloadRecursively(artist.getId(), true, true, false, false, true); - break; - case R.id.artist_menu_delete: - deleteRecursively(artist); - break; - case R.id.artist_menu_star: - toggleStarred(artist); - break; - case R.id.album_menu_play_now: - artistOverride = true; - downloadRecursively(entry.getId(), false, false, true, false, false); - break; - case R.id.album_menu_play_shuffled: - artistOverride = true; - downloadRecursively(entry.getId(), false, false, true, true, false); - break; - case R.id.album_menu_play_next: - artistOverride = true; - downloadRecursively(entry.getId(), false, true, false, false, false, true); - break; - case R.id.album_menu_play_last: - artistOverride = true; - downloadRecursively(entry.getId(), false, true, false, false, false); - break; - case R.id.album_menu_download: - artistOverride = true; - downloadRecursively(entry.getId(), false, true, false, false, true); - break; - case R.id.album_menu_pin: - artistOverride = true; - downloadRecursively(entry.getId(), true, true, false, false, true); - break; - case R.id.album_menu_star: - toggleStarred(entry); - break; - case R.id.album_menu_delete: - deleteRecursively(entry); - break; - case R.id.album_menu_info: - displaySongInfo(entry); - break; - case R.id.album_menu_show_artist: - showAlbumArtist((Entry) selectedItem); - break; - case R.id.album_menu_share: - createShare(songs); - break; - case R.id.song_menu_play_now: - playNow(songs); - break; - case R.id.song_menu_play_next: - getDownloadService().download(songs, false, false, true, false); - break; - case R.id.song_menu_play_last: - getDownloadService().download(songs, false, false, false, false); - break; - case R.id.song_menu_download: - getDownloadService().downloadBackground(songs, false); - break; - case R.id.song_menu_pin: - getDownloadService().downloadBackground(songs, true); - break; - case R.id.song_menu_delete: - getDownloadService().delete(songs); - break; - case R.id.song_menu_add_playlist: - addToPlaylist(songs); - break; - case R.id.song_menu_star: - toggleStarred(entry); - break; - case R.id.song_menu_play_external: - playExternalPlayer(entry); - break; - case R.id.song_menu_info: - displaySongInfo(entry); - break; - case R.id.song_menu_stream_external: - streamExternalPlayer(entry); - break; - case R.id.song_menu_share: - createShare(songs); - break; - case R.id.song_menu_show_album: - showAlbum((Entry) selectedItem); - break; - case R.id.song_menu_show_artist: - showArtist((Entry) selectedItem); - break; - case R.id.bookmark_menu_delete: - deleteBookmark(entry, null); - break; - case R.id.menu_rate: - setRating(entry); - break; - default: - return false; - } - - return true; - } - - public void replaceFragment(SubsonicFragment fragment) { - replaceFragment(fragment, true); - } - public void replaceFragment(SubsonicFragment fragment, boolean replaceCurrent) { - context.replaceFragment(fragment, fragment.getSupportTag(), secondaryFragment && replaceCurrent); - } - - public int getRootId() { - return rootView.getId(); - } - - public void setSupportTag(int tag) { this.tag = tag; } - public void setSupportTag(String tag) { this.tag = Integer.parseInt(tag); } - public int getSupportTag() { - return tag; - } - - public void setPrimaryFragment(boolean primary) { - primaryFragment = primary; - if(primary) { - if(context != null && title != null) { - context.setTitle(title); - context.setSubtitle(subtitle); - } - if(invalidated) { - invalidated = false; - refresh(false); - } - } - } - public void setPrimaryFragment(boolean primary, boolean secondary) { - setPrimaryFragment(primary); - secondaryFragment = secondary; - } - public void setSecondaryFragment(boolean secondary) { - secondaryFragment = secondary; - } - - public void invalidate() { - if(primaryFragment) { - refresh(true); - } else { - invalidated = true; - } - } - - public DownloadService getDownloadService() { - return context != null ? context.getDownloadService() : null; - } - - protected void refresh() { - refresh(true); - } - protected void refresh(boolean refresh) { - - } - - @Override - public void onRefresh() { - refreshLayout.setRefreshing(false); - refresh(); - } - - protected void exit() { - if(((Object) context).getClass() != SubsonicFragmentActivity.class) { - Intent intent = new Intent(context, SubsonicFragmentActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true); - Util.startActivityWithoutTransition(context, intent); - } else { - context.stopService(new Intent(context, DownloadService.class)); - context.finish(); - } - } - - public void setProgressVisible(boolean visible) { - View view = rootView.findViewById(R.id.tab_progress); - if (view != null) { - view.setVisibility(visible ? View.VISIBLE : View.GONE); - - if(visible) { - View progress = rootView.findViewById(R.id.tab_progress_spinner); - progress.setVisibility(View.VISIBLE); - } - } - } - - public void updateProgress(String message) { - TextView view = (TextView) rootView.findViewById(R.id.tab_progress_message); - if (view != null) { - view.setText(message); - } - } - - public void setEmpty(boolean empty) { - View view = rootView.findViewById(R.id.tab_progress); - if(empty) { - view.setVisibility(View.VISIBLE); - - View progress = view.findViewById(R.id.tab_progress_spinner); - progress.setVisibility(View.GONE); - - TextView text = (TextView) view.findViewById(R.id.tab_progress_message); - text.setText(R.string.common_empty); - } else { - view.setVisibility(View.GONE); - } - } - - protected synchronized ImageLoader getImageLoader() { - return context.getImageLoader(); - } - public synchronized static ImageLoader getStaticImageLoader(Context context) { - return SubsonicActivity.getStaticImageLoader(context); - } - - public void setTitle(CharSequence title) { - this.title = title; - context.setTitle(title); - } - public void setTitle(int title) { - this.title = context.getResources().getString(title); - context.setTitle(this.title); - } - public void setSubtitle(CharSequence title) { - this.subtitle = title; - context.setSubtitle(title); - } - public CharSequence getTitle() { - return this.title; - } - - protected void setupScrollList(final AbsListView listView) { - if(!context.isTouchscreen()) { - refreshLayout.setEnabled(false); - } else { - listView.setOnScrollListener(new AbsListView.OnScrollListener() { - @Override - public void onScrollStateChanged(AbsListView view, int scrollState) { - } - - @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - int topRowVerticalPosition = (listView.getChildCount() == 0) ? 0 : listView.getChildAt(0).getTop(); - refreshLayout.setEnabled(topRowVerticalPosition >= 0 && listView.getFirstVisiblePosition() == 0); - } - }); - - refreshLayout.setColorScheme( - R.color.holo_blue_light, - R.color.holo_orange_light, - R.color.holo_green_light, - R.color.holo_red_light); - } - } - - protected void warnIfStorageUnavailable() { - if (!Util.isExternalStoragePresent()) { - Util.toast(context, R.string.select_album_no_sdcard); - } - - try { - StatFs stat = new StatFs(FileUtil.getMusicDirectory(context).getPath()); - long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize(); - if (bytesAvailableFs < 50000000L) { - Util.toast(context, context.getResources().getString(R.string.select_album_no_room, Util.formatBytes(bytesAvailableFs))); - } - } catch(Exception e) { - Log.w(TAG, "Error while checking storage space for music directory", e); - } - } - - protected void onShuffleRequested() { - if(Util.isOffline(context)) { - Intent intent = new Intent(context, DownloadActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); - Util.startActivityWithoutTransition(context, intent); - return; - } - - View dialogView = context.getLayoutInflater().inflate(R.layout.shuffle_dialog, null); - final EditText startYearBox = (EditText)dialogView.findViewById(R.id.start_year); - final EditText endYearBox = (EditText)dialogView.findViewById(R.id.end_year); - final EditText genreBox = (EditText)dialogView.findViewById(R.id.genre); - final Button genreCombo = (Button)dialogView.findViewById(R.id.genre_combo); - - final SharedPreferences prefs = Util.getPreferences(context); - final String oldStartYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, ""); - final String oldEndYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, ""); - final String oldGenre = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, ""); - - boolean _useCombo = false; - if(ServerInfo.checkServerVersion(context, "1.9.0")) { - genreBox.setVisibility(View.GONE); - genreCombo.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - new LoadingTask>(context, true) { - @Override - protected List doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - return musicService.getGenres(false, context, this); - } - - @Override - protected void done(final List genres) { - List names = new ArrayList(); - String blank = context.getResources().getString(R.string.select_genre_blank); - names.add(blank); - for(Genre genre: genres) { - names.add(genre.getName()); - } - final List finalNames = names; - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.shuffle_pick_genre) - .setItems(names.toArray(new CharSequence[names.size()]), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if(which == 0) { - genreCombo.setText(""); - } else { - genreCombo.setText(finalNames.get(which)); - } - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - }); - _useCombo = true; - } else { - genreCombo.setVisibility(View.GONE); - } - final boolean useCombo = _useCombo; - - startYearBox.setText(oldStartYear); - endYearBox.setText(oldEndYear); - genreBox.setText(oldGenre); - genreCombo.setText(oldGenre); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.shuffle_title) - .setView(dialogView) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - Intent intent = new Intent(context, DownloadActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); - String genre; - if(useCombo) { - genre = genreCombo.getText().toString(); - } else { - genre = genreBox.getText().toString(); - } - String startYear = startYearBox.getText().toString(); - String endYear = endYearBox.getText().toString(); - - SharedPreferences.Editor editor = prefs.edit(); - editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYear); - editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYear); - editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre); - editor.commit(); - - Util.startActivityWithoutTransition(context, intent); - } - }) - .setNegativeButton(R.string.common_cancel, null); - AlertDialog dialog = builder.create(); - dialog.show(); - } - - public void toggleStarred(Entry entry) { - toggleStarred(entry, null); - } - public void toggleStarred(final Entry entry, final OnStarChange onStarChange) { - final boolean starred = !entry.isStarred(); - entry.setStarred(starred); - if(onStarChange != null) { - onStarChange.starChange(starred); - } - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - if(entry.isDirectory() && Util.isTagBrowsing(context) && !Util.isOffline(context)) { - if(entry.isAlbum()) { - musicService.setStarred(null, null, Arrays.asList(entry), starred, null, context); - } else { - musicService.setStarred(null, Arrays.asList(entry), null, starred, null, context); - } - } else { - musicService.setStarred(Arrays.asList(entry), null, null, starred, null, context); - } - - new EntryInstanceUpdater(entry) { - @Override - public void update(Entry found) { - found.setStarred(starred); - } - }.execute(); - - return null; - } - - @Override - protected void done(Void result) { - // UpdateView - Util.toast(context, context.getResources().getString(starred ? R.string.starring_content_starred : R.string.starring_content_unstarred, entry.getTitle())); - } - - @Override - protected void error(Throwable error) { - Log.w(TAG, "Failed to star", error); - entry.setStarred(!starred); - if(onStarChange != null) { - onStarChange.starChange(!starred); - } - - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.starring_content_error, entry.getTitle()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - public void toggleStarred(final Artist entry) { - final boolean starred = !entry.isStarred(); - entry.setStarred(starred); - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - if(Util.isTagBrowsing(context) && !Util.isOffline(context)) { - musicService.setStarred(null, Arrays.asList(new Entry(entry)), null, starred, null, context); - } else { - musicService.setStarred(Arrays.asList(new Entry(entry)), null, null, starred, null, context); - } - return null; - } - - @Override - protected void done(Void result) { - // UpdateView - Util.toast(context, context.getResources().getString(starred ? R.string.starring_content_starred : R.string.starring_content_unstarred, entry.getName())); - } - - @Override - protected void error(Throwable error) { - Log.w(TAG, "Failed to star", error); - entry.setStarred(!starred); - - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.starring_content_error, entry.getName()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - protected void downloadRecursively(final String id, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) { - downloadRecursively(id, "", true, save, append, autoplay, shuffle, background); - } - protected void downloadRecursively(final String id, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background, final boolean playNext) { - downloadRecursively(id, "", true, save, append, autoplay, shuffle, background, playNext); - } - protected void downloadPlaylist(final String id, final String name, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) { - downloadRecursively(id, name, false, save, append, autoplay, shuffle, background); - } - protected void downloadRecursively(final String id, final String name, final boolean isDirectory, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) { - downloadRecursively(id, name, isDirectory, save, append, autoplay, shuffle, background, false); - } - protected void downloadRecursively(final String id, final String name, final boolean isDirectory, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background, final boolean playNext) { - new RecursiveLoader(context) { - @Override - protected Boolean doInBackground() throws Throwable { - musicService = MusicServiceFactory.getMusicService(context); - MusicDirectory root; - if(share != null) { - root = share.getMusicDirectory(); - } - else if(isDirectory) { - if(id != null) { - root = getMusicDirectory(id, name, false, musicService, this); - } else { - root = musicService.getStarredList(context, this); - } - } - else { - root = musicService.getPlaylist(true, id, name, context, this); - } - - if(shuffle) { - Collections.shuffle(root.getChildren()); - } - - songs = new LinkedList(); - getSongsRecursively(root, songs); - - DownloadService downloadService = getDownloadService(); - boolean transition = false; - if (!songs.isEmpty() && downloadService != null) { - // Conditions for a standard play now operation - if(!append && !save && autoplay && !playNext && !shuffle && !background) { - playNowOverride = true; - return false; - } - - if (!append && !background) { - downloadService.clear(); - } - if(!background) { - downloadService.download(songs, save, autoplay, playNext, false); - if(!append) { - transition = true; - } - } - else { - downloadService.downloadBackground(songs, save); - } - } - artistOverride = false; - - return transition; - } - }.execute(); - } - - protected void downloadRecursively(final List albums, final boolean shuffle, final boolean append) { - new RecursiveLoader(context) { - @Override - protected Boolean doInBackground() throws Throwable { - musicService = MusicServiceFactory.getMusicService(context); - - if(shuffle) { - Collections.shuffle(albums); - } - - songs = new LinkedList(); - MusicDirectory root = new MusicDirectory(); - root.addChildren(albums); - getSongsRecursively(root, songs); - - DownloadService downloadService = getDownloadService(); - boolean transition = false; - if (!songs.isEmpty() && downloadService != null) { - // Conditions for a standard play now operation - if(!append && !shuffle) { - playNowOverride = true; - return false; - } - - if (!append) { - downloadService.clear(); - } - - downloadService.download(songs, false, true, false, false); - if(!append) { - transition = true; - } - } - artistOverride = false; - - return transition; - } - }.execute(); - } - - protected MusicDirectory getMusicDirectory(String id, String name, boolean refresh, MusicService service, ProgressListener listener) throws Exception { - return getMusicDirectory(id, name, refresh, false, service, listener); - } - protected MusicDirectory getMusicDirectory(String id, String name, boolean refresh, boolean forceArtist, MusicService service, ProgressListener listener) throws Exception { - if(Util.isTagBrowsing(context) && !Util.isOffline(context)) { - if(artist && !artistOverride || forceArtist) { - return service.getArtist(id, name, refresh, context, listener); - } else { - return service.getAlbum(id, name, refresh, context, listener); - } - } else { - return service.getMusicDirectory(id, name, refresh, context, listener); - } - } - - protected void addToPlaylist(final List songs) { - if(songs.isEmpty()) { - Util.toast(context, "No songs selected"); - return; - } - - new LoadingTask>(context, true) { - @Override - protected List doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - List playlists = new ArrayList(); - playlists.addAll(musicService.getPlaylists(false, context, this)); - - // Iterate through and remove all non owned public playlists - Iterator it = playlists.iterator(); - while(it.hasNext()) { - Playlist playlist = it.next(); - if(playlist.getPublic() == true && playlist.getId().indexOf(".m3u") == -1 && !UserUtil.getCurrentUsername(context).equals(playlist.getOwner())) { - it.remove(); - } - } - - return playlists; - } - - @Override - protected void done(final List playlists) { - // Create adapter to show playlists - Playlist createNew = new Playlist("-1", context.getResources().getString(R.string.playlist_create_new)); - playlists.add(0, createNew); - ArrayAdapter playlistAdapter = new ArrayAdapter(context, R.layout.basic_count_item, playlists) { - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Playlist playlist = getItem(position); - - // Create new if not getting a convert view to use - PlaylistSongView view; - if(convertView instanceof PlaylistSongView) { - view = (PlaylistSongView) convertView; - } else { - view = new PlaylistSongView(context); - } - - view.setObject(playlist, songs); - - return view; - } - }; - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.playlist_add_to) - .setAdapter(playlistAdapter, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (which > 0) { - addToPlaylist(playlists.get(which), songs); - } else { - createNewPlaylist(songs, false); - } - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - private void addToPlaylist(final Playlist playlist, final List songs) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.addToPlaylist(playlist.getId(), songs, context, null); - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, context.getResources().getString(R.string.updated_playlist, songs.size(), playlist.getName())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.updated_playlist_error, playlist.getName()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - protected void createNewPlaylist(final List songs, final boolean getSuggestion) { - View layout = context.getLayoutInflater().inflate(R.layout.save_playlist, null); - final EditText playlistNameView = (EditText) layout.findViewById(R.id.save_playlist_name); - final CheckBox overwriteCheckBox = (CheckBox) layout.findViewById(R.id.save_playlist_overwrite); - if(getSuggestion) { - String playlistName = (getDownloadService() != null) ? getDownloadService().getSuggestedPlaylistName() : null; - if (playlistName != null) { - playlistNameView.setText(playlistName); - try { - if(ServerInfo.checkServerVersion(context, "1.8.0") && Integer.parseInt(getDownloadService().getSuggestedPlaylistId()) != -1) { - overwriteCheckBox.setChecked(true); - overwriteCheckBox.setVisibility(View.VISIBLE); - } - } catch(Exception e) { - Log.d(TAG, "Playlist id isn't a integer, probably MusicCabinet"); - } - } else { - DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - playlistNameView.setText(dateFormat.format(new Date())); - } - } else { - DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); - playlistNameView.setText(dateFormat.format(new Date())); - } - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.download_playlist_title) - .setMessage(R.string.download_playlist_name) - .setView(layout) - .setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - String playlistName = String.valueOf(playlistNameView.getText()); - if(overwriteCheckBox.isChecked()) { - overwritePlaylist(songs, playlistName, getDownloadService().getSuggestedPlaylistId()); - } else { - createNewPlaylist(songs, playlistName); - - if(getSuggestion) { - DownloadService downloadService = getDownloadService(); - if(downloadService != null) { - downloadService.setSuggestedPlaylistName(playlistName, null); - } - } - } - } - }) - .setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }) - .setCancelable(true); - - AlertDialog dialog = builder.create(); - dialog.show(); - } - private void createNewPlaylist(final List songs, final String name) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.createPlaylist(null, name, songs, context, null); - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, R.string.download_playlist_done); - } - - @Override - protected void error(Throwable error) { - String msg = context.getResources().getString(R.string.download_playlist_error) + " " + getErrorMessage(error); - Util.toast(context, msg); - } - }.execute(); - } - private void overwritePlaylist(final List songs, final String name, final String id) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - MusicDirectory playlist = musicService.getPlaylist(true, id, name, context, null); - List toDelete = playlist.getChildren(); - musicService.overwritePlaylist(id, name, toDelete.size(), songs, context, null); - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, R.string.download_playlist_done); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.download_playlist_error) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - public void displaySongInfo(final Entry song) { - Integer duration = null; - Integer bitrate = null; - String format = null; - long size = 0; - if(!song.isDirectory()) { - try { - DownloadFile downloadFile = new DownloadFile(context, song, false); - File file = downloadFile.getCompleteFile(); - if(file.exists()) { - MediaMetadataRetriever metadata = new MediaMetadataRetriever(); - metadata.setDataSource(file.getAbsolutePath()); - - String tmp = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); - duration = Integer.parseInt((tmp != null) ? tmp : "0") / 1000; - format = FileUtil.getExtension(file.getName()); - size = file.length(); - - // If no duration try to read bitrate tag - if(duration == null) { - tmp = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE); - bitrate = Integer.parseInt((tmp != null) ? tmp : "0") / 1000; - } else { - // Otherwise do a calculation for it - // Divide by 1000 so in kbps - bitrate = (int) (size / duration) / 1000 * 8; - } - - if(Util.isOffline(context)) { - song.setGenre(metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE)); - String year = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR); - song.setYear(Integer.parseInt((year != null) ? year : "0")); - } - } - } catch(Exception e) { - Log.i(TAG, "Device doesn't properly support MediaMetadataRetreiver"); - } - } - - String msg = ""; - if(song instanceof PodcastEpisode) { - msg += "Podcast: " + song.getArtist() + "\nStatus: " + ((PodcastEpisode)song).getStatus(); - } else if(!song.isVideo()) { - if(song.getArtist() != null && !"".equals(song.getArtist())) { - msg += "Artist: " + song.getArtist(); - } - if(song.getAlbum() != null && !"".equals(song.getAlbum())) { - msg += "\nAlbum: " + song.getAlbum(); - } - } - if(song.getTrack() != null && song.getTrack() != 0) { - msg += "\nTrack: " + song.getTrack(); - } - if(song.getGenre() != null && !"".equals(song.getGenre())) { - msg += "\nGenre: " + song.getGenre(); - } - if(song.getYear() != null && song.getYear() != 0) { - msg += "\nYear: " + song.getYear(); - } - if(!Util.isOffline(context) && song.getSuffix() != null) { - msg += "\nServer Format: " + song.getSuffix(); - if(song.getBitRate() != null && song.getBitRate() != 0) { - msg += "\nServer Bitrate: " + song.getBitRate() + " kbps"; - } - } - if(format != null && !"".equals(format)) { - msg += "\nCached Format: " + format; - } - if(bitrate != null && bitrate != 0) { - msg += "\nCached Bitrate: " + bitrate + " kbps"; - } - if(size != 0) { - msg += "\nSize: " + Util.formatLocalizedBytes(size, context); - } - if(song.getDuration() != null && song.getDuration() != 0) { - msg += "\nLength: " + Util.formatDuration(song.getDuration()); - } - if(song.getBookmark() != null) { - msg += "\nBookmark Position: " + Util.formatDuration(song.getBookmark().getPosition() / 1000); - } - if(song.getRating() != 0) { - msg += "\nRating: " + song.getRating() + " stars"; - } - if(song instanceof PodcastEpisode) { - msg += "\n\nDescription: " + song.getAlbum(); - } - - Util.info(context, song.getTitle(), msg); - } - - protected void playVideo(Entry entry) { - if(entryExists(entry)) { - playExternalPlayer(entry); - } else { - streamExternalPlayer(entry); - } - } - - protected void playWebView(Entry entry) { - int maxBitrate = Util.getMaxVideoBitrate(context); - - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(MusicServiceFactory.getMusicService(context).getVideoUrl(maxBitrate, context, entry.getId()))); - - startActivity(intent); - } - protected void playExternalPlayer(Entry entry) { - if(!entryExists(entry)) { - Util.toast(context, R.string.download_need_download); - } else { - DownloadFile check = new DownloadFile(context, entry, false); - File file = check.getCompleteFile(); - - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(Uri.fromFile(file), "video/*"); - intent.putExtra(Intent.EXTRA_TITLE, entry.getTitle()); - - List intents = context.getPackageManager() - .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); - if(intents != null && intents.size() > 0) { - startActivity(intent); - }else { - Util.toast(context, R.string.download_no_streaming_player); - } - } - } - protected void streamExternalPlayer(Entry entry) { - String videoPlayerType = Util.getVideoPlayerType(context); - if("flash".equals(videoPlayerType)) { - playWebView(entry); - } else if("hls".equals(videoPlayerType)) { - streamExternalPlayer(entry, "hls"); - } else if("raw".equals(videoPlayerType)) { - streamExternalPlayer(entry, "raw"); - } else { - streamExternalPlayer(entry, entry.getTranscodedSuffix()); - } - } - protected void streamExternalPlayer(Entry entry, String format) { - try { - int maxBitrate = Util.getMaxVideoBitrate(context); - - Intent intent = new Intent(Intent.ACTION_VIEW); - if("hls".equals(format)) { - intent.setDataAndType(Uri.parse(MusicServiceFactory.getMusicService(context).getHlsUrl(entry.getId(), maxBitrate, context)), "application/x-mpegURL"); - } else { - intent.setDataAndType(Uri.parse(MusicServiceFactory.getMusicService(context).getVideoStreamUrl(format, maxBitrate, context, entry.getId())), "video/*"); - } - intent.putExtra("title", entry.getTitle()); - - List intents = context.getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); - if(intents != null && intents.size() > 0) { - startActivity(intent); - } else { - Util.toast(context, R.string.download_no_streaming_player); - } - } catch(Exception error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = error.getMessage(); - } else { - msg = context.getResources().getString(R.string.download_no_streaming_player) + " " + error.getMessage(); - } - - Util.toast(context, msg, false); - } - } - - protected boolean entryExists(Entry entry) { - DownloadFile check = new DownloadFile(context, entry, false); - return check.isCompleteFileAvailable(); - } - - public void deleteRecursively(Artist artist) { - deleteRecursively(FileUtil.getArtistDirectory(context, artist)); - } - - public void deleteRecursively(Entry album) { - deleteRecursively(FileUtil.getAlbumDirectory(context, album)); - - } - public void deleteRecursively(final File dir) { - if(dir == null) { - return; - } - - new LoadingTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MediaStoreService mediaStore = new MediaStoreService(context); - FileUtil.recursiveDelete(dir, mediaStore); - return null; - } - - @Override - protected void done(Void result) { - if(Util.isOffline(context)) { - refresh(); - } else { - UpdateView.triggerUpdate(); - } - } - }.execute(); - } - - public void showAlbumArtist(Entry entry) { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - if(Util.isTagBrowsing(context)) { - args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getArtistId()); - } else { - args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getParent()); - } - args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getArtist()); - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - fragment.setArguments(args); - - replaceFragment(fragment, true); - } - public void showArtist(Entry entry) { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - if(Util.isTagBrowsing(context)) { - args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getArtistId()); - } else { - if(entry.getGrandParent() == null) { - args.putString(Constants.INTENT_EXTRA_NAME_CHILD_ID, entry.getParent()); - } else { - args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getGrandParent()); - } - } - args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getArtist()); - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - fragment.setArguments(args); - - replaceFragment(fragment, true); - } - public void showAlbum(Entry entry) { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - if(Util.isTagBrowsing(context)) { - args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getAlbumId()); - } else { - args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getParent()); - } - args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getAlbum()); - fragment.setArguments(args); - - replaceFragment(fragment, true); - } - - public void createShare(final List entries) { - new LoadingTask>(context, true) { - @Override - protected List doInBackground() throws Throwable { - List ids = new ArrayList(entries.size()); - for(Entry entry: entries) { - ids.add(entry.getId()); - } - - MusicService musicService = MusicServiceFactory.getMusicService(context); - return musicService.createShare(ids, null, 0L, context, this); - } - - @Override - protected void done(final List shares) { - if(shares.size() > 0) { - Share share = shares.get(0); - shareExternal(share); - } else { - Util.toast(context, context.getResources().getString(R.string.playlist_error), false); - } - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - public void shareExternal(Share share) { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("text/plain"); - intent.putExtra(Intent.EXTRA_TEXT, share.getUrl()); - context.startActivity(Intent.createChooser(intent, context.getResources().getString(R.string.share_via))); - } - - public GestureDetector getGestureDetector() { - return gestureScanner; - } - - protected void playBookmark(List songs, Entry song) { - playBookmark(songs, song, null, null); - } - protected void playBookmark(final List songs, final Entry song, final String playlistName, final String playlistId) { - final Integer position = song.getBookmark().getPosition(); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.bookmark_resume_title) - .setMessage(getResources().getString(R.string.bookmark_resume, song.getTitle(), Util.formatDuration(position / 1000))) - .setPositiveButton(R.string.bookmark_action_resume, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - playNow(songs, song, position); - } - }) - .setNegativeButton(R.string.bookmark_action_start_over, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - final Bookmark oldBookmark = song.getBookmark(); - song.setBookmark(null); - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.deleteBookmark(song, context, null); - - return null; - } - - @Override - protected void error(Throwable error) { - song.setBookmark(oldBookmark); - - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.bookmark_deleted_error, song.getTitle()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - - playNow(songs, 0); - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - } - - protected void playNow(List entries) { - playNow(entries, null, null); - } - protected void playNow(List entries, String playlistName, String playlistId) { - Entry bookmark = null; - for(Entry entry: entries) { - if(entry.getBookmark() != null) { - bookmark = entry; - break; - } - } - - // If no bookmark found, just play from start - if(bookmark == null) { - playNow(entries, 0, playlistName, playlistId); - } else { - // If bookmark found, then give user choice to start from there or to start over - playBookmark(entries, bookmark, playlistName, playlistId); - } - } - protected void playNow(List entries, int position) { - playNow(entries, position, null, null); - } - protected void playNow(List entries, int position, String playlistName, String playlistId) { - Entry selected = entries.isEmpty() ? null : entries.get(0); - playNow(entries, selected, position, playlistName, playlistId); - } - protected void playNow(List entries, Entry song, int position) { - playNow(entries, song, position, null, null); - } - protected void playNow(final List entries, final Entry song, final int position, final String playlistName, final String playlistId) { - new LoadingTask(context) { - @Override - protected Void doInBackground() throws Throwable { - DownloadService downloadService = getDownloadService(); - if(downloadService == null) { - return null; - } - - downloadService.clear(); - downloadService.download(entries, false, true, true, false, entries.indexOf(song), position); - downloadService.setSuggestedPlaylistName(playlistName, playlistId); - - return null; - } - - @Override - protected void done(Void result) { - Util.startActivityWithoutTransition(context, DownloadActivity.class); - } - }.execute(); - } - - protected void deleteBookmark(final MusicDirectory.Entry entry, final ArrayAdapter adapter) { - Util.confirmDialog(context, R.string.bookmark_delete_title, entry.getTitle(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - final Bookmark oldBookmark = entry.getBookmark(); - entry.setBookmark(null); - - new LoadingTask(context, false) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.deleteBookmark(entry, context, null); - - new EntryInstanceUpdater(entry) { - @Override - public void update(Entry found) { - found.setBookmark(null); - } - }.execute(); - - return null; - } - - @Override - protected void done(Void result) { - if (adapter != null) { - adapter.remove(entry); - adapter.notifyDataSetChanged(); - } - Util.toast(context, context.getResources().getString(R.string.bookmark_deleted, entry.getTitle())); - } - - @Override - protected void error(Throwable error) { - entry.setBookmark(oldBookmark); - - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.bookmark_deleted_error, entry.getTitle()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - }); - } - - protected void setRating(Entry entry) { - setRating(entry, null); - } - protected void setRating(final Entry entry, final OnRatingChange onRatingChange) { - View layout = context.getLayoutInflater().inflate(R.layout.rating, null); - final RatingBar ratingBar = (RatingBar) layout.findViewById(R.id.rating_bar); - ratingBar.setRating((float) entry.getRating()); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(context.getResources().getString(R.string.rating_title, entry.getTitle())) - .setView(layout) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - int rating = (int) ratingBar.getRating(); - setRating(entry, rating, onRatingChange); - } - }) - .setNegativeButton(R.string.common_cancel, null); - - AlertDialog dialog = builder.create(); - dialog.show(); - } - - protected void setRating(Entry entry, int rating) { - setRating(entry, rating, null); - } - protected void setRating(final Entry entry, final int rating, final OnRatingChange onRatingChange) { - final int oldRating = entry.getRating(); - entry.setRating(rating); - - if(onRatingChange != null) { - onRatingChange.ratingChange(rating); - } - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.setRating(entry, rating, context, null); - - new EntryInstanceUpdater(entry) { - @Override - public void update(Entry found) { - found.setRating(rating); - } - }.execute(); - return null; - } - - @Override - protected void done(Void result) { - Util.toast(context, context.getResources().getString(rating > 0 ? R.string.rating_set_rating : R.string.rating_remove_rating, entry.getTitle())); - } - - @Override - protected void error(Throwable error) { - entry.setRating(oldRating); - if(onRatingChange != null) { - onRatingChange.ratingChange(oldRating); - } - - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(rating > 0 ? R.string.rating_set_rating_failed : R.string.rating_remove_rating_failed, entry.getTitle()) + " " + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - - protected abstract class EntryInstanceUpdater { - private Entry entry; - - public EntryInstanceUpdater(Entry entry) { - this.entry = entry; - } - - public abstract void update(Entry found); - - public void execute() { - DownloadService downloadService = getDownloadService(); - if(downloadService != null && !entry.isDirectory()) { - boolean serializeChanges = false; - List downloadFiles = downloadService.getDownloads(); - for(DownloadFile file: downloadFiles) { - Entry check = file.getSong(); - if(entry.getId().equals(check.getId())) { - update(entry); - serializeChanges = true; - } - } - - if(serializeChanges) { - downloadService.serializeQueue(); - } - } - - Entry find = UpdateView.findEntry(entry); - if(find != null) { - update(find); - } - } - } - - public abstract class OnRatingChange { - abstract void ratingChange(int rating); - } - public abstract class OnStarChange { - abstract void starChange(boolean starred); - } - - public abstract class RecursiveLoader extends LoadingTask { - protected MusicService musicService; - protected static final int MAX_SONGS = 500; - protected boolean playNowOverride = false; - protected List songs; - - public RecursiveLoader(Activity context) { - super(context); - } - - protected void getSongsRecursively(MusicDirectory parent, List songs) throws Exception { - if (songs.size() > MAX_SONGS) { - return; - } - - for (Entry song : parent.getChildren(false, true)) { - if (!song.isVideo() && song.getRating() != 1) { - songs.add(song); - } - } - for (Entry dir : parent.getChildren(true, false)) { - if(dir.getRating() == 1) { - continue; - } - - MusicDirectory musicDirectory; - if(Util.isTagBrowsing(context) && !Util.isOffline(context)) { - musicDirectory = musicService.getAlbum(dir.getId(), dir.getTitle(), false, context, this); - } else { - musicDirectory = musicService.getMusicDirectory(dir.getId(), dir.getTitle(), false, context, this); - } - getSongsRecursively(musicDirectory, songs); - } - } - - @Override - protected void done(Boolean result) { - warnIfStorageUnavailable(); - - if(playNowOverride) { - playNow(songs); - return; - } - - if(result) { - Util.startActivityWithoutTransition(context, DownloadActivity.class); - } - } - } -} diff --git a/src/github/daneren2005/dsub/fragments/UserFragment.java b/src/github/daneren2005/dsub/fragments/UserFragment.java deleted file mode 100644 index 2fa804cc..00000000 --- a/src/github/daneren2005/dsub/fragments/UserFragment.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.fragments; - -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.widget.SwipeRefreshLayout; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.TextView; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.SubsonicActivity; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.domain.User; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.util.UserUtil; -import github.daneren2005.dsub.adapter.SettingsAdapter; - -public class UserFragment extends SubsonicFragment{ - private ListView listView; - private User user; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false); - - refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); - refreshLayout.setEnabled(false); - - Bundle args = getArguments(); - user = (User) args.getSerializable(Constants.INTENT_EXTRA_NAME_ID); - - listView = (ListView)rootView.findViewById(R.id.fragment_list); - createHeader(); - listView.setAdapter(new SettingsAdapter(context, user.getSettings(), UserUtil.isCurrentAdmin() && ServerInfo.checkServerVersion(context, "1.10"))); - - setTitle(user.getUsername()); - - return rootView; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - ((SubsonicActivity) activity).supportInvalidateOptionsMenu(); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - // For some reason this is called before onAttach - if(!primaryFragment || context == null) { - return; - } - - if(UserUtil.isCurrentAdmin() && ServerInfo.checkServerVersion(context, "1.10")) { - menuInflater.inflate(R.menu.user, menu); - } else if(UserUtil.isCurrentRole(User.SETTINGS)) { - menuInflater.inflate(R.menu.user_user, menu); - } else { - menuInflater.inflate(R.menu.empty, menu); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(super.onOptionsItemSelected(item)) { - return true; - } - - switch (item.getItemId()) { - case R.id.menu_update_permissions: - UserUtil.updateSettings(context, user); - return true; - case R.id.menu_change_password: - UserUtil.changePassword(context, user); - return true; - case R.id.menu_change_email: - UserUtil.changeEmail(context, user); - return true; - } - - return false; - } - - private void createHeader() { - View header = LayoutInflater.from(context).inflate(R.layout.user_header, listView, false); - - final ImageLoader imageLoader = getImageLoader(); - ImageView coverArtView = (ImageView) header.findViewById(R.id.user_avatar); - imageLoader.loadAvatar(context, coverArtView, user.getUsername()); - - TextView usernameView = (TextView) header.findViewById(R.id.user_username); - usernameView.setText(user.getUsername()); - - final TextView emailView = (TextView) header.findViewById(R.id.user_email); - if(user.getEmail() != null) { - emailView.setText(user.getEmail()); - } else { - emailView.setVisibility(View.GONE); - } - - listView.addHeaderView(header); - } -} diff --git a/src/github/daneren2005/dsub/provider/DLNARouteProvider.java b/src/github/daneren2005/dsub/provider/DLNARouteProvider.java deleted file mode 100644 index 73d4b5de..00000000 --- a/src/github/daneren2005/dsub/provider/DLNARouteProvider.java +++ /dev/null @@ -1,425 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2014 (C) Scott Jackson -*/ -package github.daneren2005.dsub.provider; - -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.media.AudioManager; -import android.media.MediaRouter; -import android.os.IBinder; -import android.support.v7.media.MediaControlIntent; -import android.support.v7.media.MediaRouteDescriptor; -import android.support.v7.media.MediaRouteDiscoveryRequest; -import android.support.v7.media.MediaRouteProvider; -import android.support.v7.media.MediaRouteProviderDescriptor; -import android.util.Log; - -import org.eclipse.jetty.util.log.Logger; -import org.fourthline.cling.android.AndroidUpnpService; -import org.fourthline.cling.android.AndroidUpnpServiceImpl; -import org.fourthline.cling.model.action.ActionInvocation; -import org.fourthline.cling.model.message.UpnpResponse; -import org.fourthline.cling.model.meta.Device; -import org.fourthline.cling.model.meta.LocalDevice; -import org.fourthline.cling.model.meta.RemoteDevice; -import org.fourthline.cling.model.meta.StateVariable; -import org.fourthline.cling.model.meta.StateVariableAllowedValueRange; -import org.fourthline.cling.model.types.ServiceType; -import org.fourthline.cling.registry.Registry; -import org.fourthline.cling.registry.RegistryListener; -import org.fourthline.cling.support.renderingcontrol.callback.GetVolume; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import github.daneren2005.dsub.domain.DLNADevice; -import github.daneren2005.dsub.domain.RemoteControlState; -import github.daneren2005.dsub.service.DLNAController; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.RemoteController; - -public class DLNARouteProvider extends MediaRouteProvider { - private static final String TAG = DLNARouteProvider.class.getSimpleName(); - public static final String CATEGORY_DLNA = "github.daneren2005.dsub.DLNA"; - - private DownloadService downloadService; - private RemoteController controller; - - private HashMap devices = new HashMap(); - private List adding = new ArrayList(); - private List removing = new ArrayList(); - private AndroidUpnpService dlnaService; - private ServiceConnection dlnaServiceConnection; - private boolean searchOnConnect = false; - - public DLNARouteProvider(Context context) { - super(context); - - // Use custom logger - org.eclipse.jetty.util.log.Log.setLog(new JettyAndroidLog()); - - this.downloadService = (DownloadService) context; - dlnaServiceConnection = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - dlnaService = (AndroidUpnpService) service; - dlnaService.getRegistry().addListener(new RegistryListener() { - @Override - public void remoteDeviceDiscoveryStarted(Registry registry, RemoteDevice remoteDevice) { - - } - - @Override - public void remoteDeviceDiscoveryFailed(Registry registry, RemoteDevice remoteDevice, Exception e) { - // Error is displayed in log anyways under W/trieveRemoteDescriptors - } - - @Override - public void remoteDeviceAdded(Registry registry, RemoteDevice remoteDevice) { - deviceAdded(remoteDevice); - } - - @Override - public void remoteDeviceUpdated(Registry registry, RemoteDevice remoteDevice) { - deviceAdded(remoteDevice); - } - - @Override - public void remoteDeviceRemoved(Registry registry, RemoteDevice remoteDevice) { - deviceRemoved(remoteDevice); - } - - @Override - public void localDeviceAdded(Registry registry, LocalDevice localDevice) { - deviceAdded(localDevice); - } - - @Override - public void localDeviceRemoved(Registry registry, LocalDevice localDevice) { - deviceRemoved(localDevice); - } - - @Override - public void beforeShutdown(Registry registry) { - - } - - @Override - public void afterShutdown() { - - } - }); - - for (Device device : dlnaService.getControlPoint().getRegistry().getDevices()) { - deviceAdded(device); - } - if(searchOnConnect) { - dlnaService.getControlPoint().search(); - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - dlnaService = null; - } - }; - - if(!context.getApplicationContext().bindService(new Intent(context, AndroidUpnpServiceImpl.class), dlnaServiceConnection, Context.BIND_AUTO_CREATE)) { - Log.e(TAG, "Failed to bind to DLNA service"); - } - } - - private void broadcastDescriptors() { - // Create intents - IntentFilter routeIntentFilter = new IntentFilter(); - routeIntentFilter.addCategory(CATEGORY_DLNA); - routeIntentFilter.addAction(MediaControlIntent.ACTION_START_SESSION); - routeIntentFilter.addAction(MediaControlIntent.ACTION_GET_SESSION_STATUS); - routeIntentFilter.addAction(MediaControlIntent.ACTION_END_SESSION); - - // Create descriptor - MediaRouteProviderDescriptor.Builder providerBuilder = new MediaRouteProviderDescriptor.Builder(); - - // Create route descriptor - for(Map.Entry deviceEntry: devices.entrySet()) { - DLNADevice device = deviceEntry.getValue(); - - int volume; - if(device.volumeMax == 0) { - volume = 5; - } else { - int increments = device.volumeMax / 10; - volume = controller == null ? device.volume : (int) controller.getVolume(); - volume = volume / increments; - } - - MediaRouteDescriptor.Builder routeBuilder = new MediaRouteDescriptor.Builder(device.id, device.name); - routeBuilder.addControlFilter(routeIntentFilter) - .setPlaybackStream(AudioManager.STREAM_MUSIC) - .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) - .setDescription(device.description) - .setVolume(volume) - .setVolumeMax(10) - .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE); - providerBuilder.addRoute(routeBuilder.build()); - } - - setDescriptor(providerBuilder.build()); - } - - @Override - public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) { - if (request != null && request.isActiveScan()) { - if(dlnaService != null) { - dlnaService.getControlPoint().search(); - } else { - searchOnConnect = true; - } - } - } - - @Override - public RouteController onCreateRouteController(String routeId) { - DLNADevice device = devices.get(routeId); - if(device == null) { - Log.w(TAG, "No device exists for " + routeId); - return null; - } - - return new DLNARouteController(device); - } - - private void deviceAdded(final Device device) { - final org.fourthline.cling.model.meta.Service renderingControl = device.findService(new ServiceType("schemas-upnp-org", "RenderingControl")); - if(renderingControl == null) { - return; - } - - final String id = device.getIdentity().getUdn().toString(); - // In the process of looking up it's details already - if(adding.contains(id)) { - return; - } - // Just a temp disconnect, already have it's info - if(removing.contains(id)) { - removing.remove(id); - return; - } - adding.add(id); - - if(device.getType().getType().equals("MediaRenderer") && device instanceof RemoteDevice) { - try { - dlnaService.getControlPoint().execute(new GetVolume(renderingControl) { - @Override - public void received(ActionInvocation actionInvocation, int currentVolume) { - int maxVolume = 100; - StateVariable volume = renderingControl.getStateVariable("Volume"); - if (volume != null) { - StateVariableAllowedValueRange volumeRange = volume.getTypeDetails().getAllowedValueRange(); - maxVolume = (int) volumeRange.getMaximum(); - } - - // Create a new DLNADevice to represent this item - String id = device.getIdentity().getUdn().toString(); - String name = device.getDetails().getFriendlyName(); - String displayName = device.getDisplayString(); - - DLNADevice newDevice = new DLNADevice(device, id, name, displayName, currentVolume, maxVolume); - devices.put(id, newDevice); - downloadService.post(new Runnable() { - @Override - public void run() { - broadcastDescriptors(); - } - }); - adding.remove(id); - } - - @Override - public void failure(ActionInvocation actionInvocation, UpnpResponse upnpResponse, String s) { - Log.w(TAG, "Failed to get default volume for DLNA route"); - Log.w(TAG, "Reason: " + s); - adding.remove(id); - } - }); - } catch(Exception e) { - Log.e(TAG, "Failed to add device", e); - } - } else { - adding.remove(id); - } - } - private void deviceRemoved(Device device) { - if(device.getType().getType().equals("MediaRenderer") && device instanceof RemoteDevice) { - final String id = device.getIdentity().getUdn().toString(); - removing.add(id); - - // Delay removal for a few seconds to make sure that it isn't just a temp disconnect - dlnaService.getControlPoint().search(); - downloadService.postDelayed(new Runnable() { - @Override - public void run() { - if(removing.contains(id)) { - devices.remove(id); - removing.remove(id); - broadcastDescriptors(); - } - } - }, 5000L); - } - } - - private class DLNARouteController extends RouteController { - private DLNADevice device; - - public DLNARouteController(DLNADevice device) { - this.device = device; - } - - @Override - public boolean onControlRequest(Intent intent, android.support.v7.media.MediaRouter.ControlRequestCallback callback) { - if (intent.hasCategory(CATEGORY_DLNA)) { - return true; - } else { - return false; - } - } - - @Override - public void onRelease() { - downloadService.setRemoteEnabled(RemoteControlState.LOCAL); - controller = null; - } - - @Override - public void onSelect() { - controller = new DLNAController(downloadService, dlnaService.getControlPoint(), device); - downloadService.setRemoteEnabled(RemoteControlState.DLNA, controller); - } - - @Override - public void onUnselect() { - downloadService.setRemoteEnabled(RemoteControlState.LOCAL); - controller = null; - } - - @Override - public void onUpdateVolume(int delta) { - if(controller != null) { - controller.updateVolume(delta > 0); - } - broadcastDescriptors(); - } - - @Override - public void onSetVolume(int volume) { - if(controller != null) { - controller.setVolume(volume); - } - broadcastDescriptors(); - } - } - - public static class JettyAndroidLog implements Logger { - final private static java.util.logging.Logger log = java.util.logging.Logger.getLogger("Jetty"); - - public static boolean __isIgnoredEnabled = false; - public String _name; - - public JettyAndroidLog() { - this (JettyAndroidLog.class.getName()); - } - - public JettyAndroidLog(String name) { - _name = name; - } - - public String getName () { - return _name; - } - - public void debug(Throwable th) { - // Log.d(TAG, "", th); - } - - public void debug(String msg, Throwable th) { - // Log.d(TAG, msg, th); - } - - public void debug(String msg, Object... args) { - // Log.d(TAG, msg); - } - - public Logger getLogger(String name) { - return new JettyAndroidLog(name); - } - - public void info(String msg, Object... args) { - // Log.i(TAG, msg); - } - - public void info(Throwable th) { - // Log.i(TAG, "", th); - } - - public void info(String msg, Throwable th) { - // Log.i(TAG, msg, th); - } - - public boolean isDebugEnabled() { - return false; - } - - public void warn(Throwable th) { - // Log.w(TAG, "", th); - } - - public void warn(String msg, Object... args) { - // Log.w(TAG, msg); - } - - public void warn(String msg, Throwable th) { - // Log.w(TAG, msg, th); - } - - public boolean isIgnoredEnabled () { - return __isIgnoredEnabled; - } - - - public void ignore(Throwable ignored) { - if (__isIgnoredEnabled) { - warn("IGNORED", ignored); - } - } - - public void setIgnoredEnabled(boolean enabled) { - __isIgnoredEnabled = enabled; - } - - public void setDebugEnabled(boolean enabled) { - - } - } -} diff --git a/src/github/daneren2005/dsub/provider/DSubSearchProvider.java b/src/github/daneren2005/dsub/provider/DSubSearchProvider.java deleted file mode 100644 index 63bbaaa4..00000000 --- a/src/github/daneren2005/dsub/provider/DSubSearchProvider.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.provider; - -import android.app.SearchManager; -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.database.MatrixCursor; -import android.net.Uri; -import android.util.Log; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.SearchCritera; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.Util; - -/** - * Provides search suggestions based on recent searches. - * - * @author Sindre Mehus - */ -public class DSubSearchProvider extends ContentProvider { - private static final String TAG = DSubSearchProvider.class.getSimpleName(); - - private static final String RESOURCE_PREFIX = "android.resource://github.daneren2005.dsub/"; - private static final String[] COLUMNS = {"_id", - SearchManager.SUGGEST_COLUMN_TEXT_1, - SearchManager.SUGGEST_COLUMN_TEXT_2, - SearchManager.SUGGEST_COLUMN_INTENT_DATA, - SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA, - SearchManager.SUGGEST_COLUMN_ICON_1}; - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - String query = selectionArgs[0] + "*"; - SearchResult searchResult = search(query); - return createCursor(selectionArgs[0], searchResult); - } - - private SearchResult search(String query) { - MusicService musicService = MusicServiceFactory.getMusicService(getContext()); - if (musicService == null) { - return null; - } - - try { - return musicService.search(new SearchCritera(query, 5, 10, 10), getContext(), null); - } catch (Exception e) { - return null; - } - } - - private Cursor createCursor(String query, SearchResult searchResult) { - MatrixCursor cursor = new MatrixCursor(COLUMNS); - if (searchResult == null) { - return cursor; - } - - // Add all results into one pot - List results = new ArrayList(); - results.addAll(searchResult.getArtists()); - results.addAll(searchResult.getAlbums()); - results.addAll(searchResult.getSongs()); - - // For each, calculate its string distance to the query - for(Object obj: results) { - if(obj instanceof Artist) { - Artist artist = (Artist) obj; - artist.setCloseness(Util.getStringDistance(query, artist.getName())); - } else { - MusicDirectory.Entry entry = (MusicDirectory.Entry) obj; - entry.setCloseness(Util.getStringDistance(query, entry.getTitle())); - } - } - - // Sort based on the closeness paramater - Collections.sort(results, new Comparator() { - @Override - public int compare(Object lhs, Object rhs) { - // Get the closeness of the two objects - int left, right; - boolean leftArtist = lhs instanceof Artist; - boolean rightArtist = rhs instanceof Artist; - if (leftArtist) { - left = ((Artist) lhs).getCloseness(); - } else { - left = ((MusicDirectory.Entry) lhs).getCloseness(); - } - if (rightArtist) { - right = ((Artist) rhs).getCloseness(); - } else { - right = ((MusicDirectory.Entry) rhs).getCloseness(); - } - - if (left == right) { - if(leftArtist && rightArtist) { - return 0; - } else if(leftArtist) { - return -1; - } else if(rightArtist) { - return 1; - } else { - return 0; - } - } else if (left > right) { - return 1; - } else { - return -1; - } - } - }); - - // Done sorting, add results to cursor - for(Object obj: results) { - if(obj instanceof Artist) { - Artist artist = (Artist) obj; - String icon = RESOURCE_PREFIX + R.drawable.ic_action_artist; - cursor.addRow(new Object[]{artist.getId().hashCode(), artist.getName(), null, "ar-" + artist.getId(), artist.getName(), icon}); - } else { - MusicDirectory.Entry entry = (MusicDirectory.Entry) obj; - - if(entry.isDirectory()) { - String icon = RESOURCE_PREFIX + R.drawable.ic_action_album; - cursor.addRow(new Object[]{entry.getId().hashCode(), entry.getTitle(), entry.getArtist(), entry.getId(), entry.getTitle(), icon}); - } else { - String icon = RESOURCE_PREFIX + R.drawable.ic_action_song; - String id; - if(Util.isTagBrowsing(getContext())) { - id = entry.getAlbumId(); - } else { - id = entry.getParent(); - } - cursor.addRow(new Object[]{entry.getId().hashCode(), entry.getTitle(), entry.getArtist(), "so-" + id, entry.getTitle(), icon}); - } - } - } - return cursor; - } - - @Override - public boolean onCreate() { - return false; - } - - @Override - public String getType(Uri uri) { - return null; - } - - @Override - public Uri insert(Uri uri, ContentValues contentValues) { - return null; - } - - @Override - public int delete(Uri uri, String s, String[] strings) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues contentValues, String s, String[] strings) { - return 0; - } - -} diff --git a/src/github/daneren2005/dsub/provider/DSubWidget4x1.java b/src/github/daneren2005/dsub/provider/DSubWidget4x1.java deleted file mode 100644 index 9919eb22..00000000 --- a/src/github/daneren2005/dsub/provider/DSubWidget4x1.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.provider; - -import github.daneren2005.dsub.R; - -public class DSubWidget4x1 extends DSubWidgetProvider { - @Override - protected int getLayout() { - return R.layout.appwidget4x1; - } -} diff --git a/src/github/daneren2005/dsub/provider/DSubWidget4x2.java b/src/github/daneren2005/dsub/provider/DSubWidget4x2.java deleted file mode 100644 index 2aa6beae..00000000 --- a/src/github/daneren2005/dsub/provider/DSubWidget4x2.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.provider; - -import github.daneren2005.dsub.R; - -public class DSubWidget4x2 extends DSubWidgetProvider { - @Override - protected int getLayout() { - return R.layout.appwidget4x2; - } -} diff --git a/src/github/daneren2005/dsub/provider/DSubWidget4x3.java b/src/github/daneren2005/dsub/provider/DSubWidget4x3.java deleted file mode 100644 index dfe071c0..00000000 --- a/src/github/daneren2005/dsub/provider/DSubWidget4x3.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.provider; - -import github.daneren2005.dsub.R; - -public class DSubWidget4x3 extends DSubWidgetProvider { - @Override - protected int getLayout() { - return R.layout.appwidget4x3; - } -} diff --git a/src/github/daneren2005/dsub/provider/DSubWidget4x4.java b/src/github/daneren2005/dsub/provider/DSubWidget4x4.java deleted file mode 100644 index fa53918d..00000000 --- a/src/github/daneren2005/dsub/provider/DSubWidget4x4.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.provider; - -import github.daneren2005.dsub.R; - -public class DSubWidget4x4 extends DSubWidgetProvider { - @Override - protected int getLayout() { - return R.layout.appwidget4x4; - } -} diff --git a/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java b/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java deleted file mode 100644 index 444b6cff..00000000 --- a/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.provider; - -import android.app.PendingIntent; -import android.appwidget.AppWidgetManager; -import android.appwidget.AppWidgetProvider; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.res.Resources; -import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PorterDuff.Mode; -import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; -import android.graphics.RectF; -import android.os.Environment; -import android.util.Log; -import android.view.View; -import android.widget.RemoteViews; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.DownloadActivity; -import github.daneren2005.dsub.activity.SubsonicActivity; -import github.daneren2005.dsub.activity.SubsonicFragmentActivity; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerQueue; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.DownloadServiceLifecycleSupport; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.util.Util; - -/** - * Simple widget to show currently playing album art along - * with play/pause and next track buttons. - *

- * Based on source code from the stock Android Music app. - * - * @author Sindre Mehus - */ -public class DSubWidgetProvider extends AppWidgetProvider { - private static final String TAG = DSubWidgetProvider.class.getSimpleName(); - private static DSubWidget4x1 instance4x1; - private static DSubWidget4x2 instance4x2; - private static DSubWidget4x3 instance4x3; - private static DSubWidget4x4 instance4x4; - - public static synchronized void notifyInstances(Context context, DownloadService service, boolean playing) { - if(instance4x1 == null) { - instance4x1 = new DSubWidget4x1(); - } - if(instance4x2 == null) { - instance4x2 = new DSubWidget4x2(); - } - if(instance4x3 == null) { - instance4x3 = new DSubWidget4x3(); - } - if(instance4x4 == null) { - instance4x4 = new DSubWidget4x4(); - } - - instance4x1.notifyChange(context, service, playing); - instance4x2.notifyChange(context, service, playing); - instance4x3.notifyChange(context, service, playing); - instance4x4.notifyChange(context, service, playing); - } - - @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { - defaultAppWidget(context, appWidgetIds); - } - - @Override - public void onEnabled(Context context) { - notifyInstances(context, DownloadService.getInstance(), false); - } - - protected int getLayout() { - return 0; - } - - /** - * Initialize given widgets to default state, where we launch Subsonic on default click - * and hide actions if service not running. - */ - private void defaultAppWidget(Context context, int[] appWidgetIds) { - final Resources res = context.getResources(); - final RemoteViews views = new RemoteViews(context.getPackageName(), getLayout()); - - views.setTextViewText(R.id.artist, res.getText(R.string.widget_initial_text)); - if(getLayout() == R.layout.appwidget4x2) { - views.setTextViewText(R.id.album, ""); - } - - linkButtons(context, views, false); - performUpdate(context, null, appWidgetIds, false); - } - - private void pushUpdate(Context context, int[] appWidgetIds, RemoteViews views) { - // Update specific list of appWidgetIds if given, otherwise default to all - final AppWidgetManager manager = AppWidgetManager.getInstance(context); - if (appWidgetIds != null) { - manager.updateAppWidget(appWidgetIds, views); - } else { - manager.updateAppWidget(new ComponentName(context, this.getClass()), views); - } - } - - /** - * Handle a change notification coming over from {@link DownloadService} - */ - public void notifyChange(Context context, DownloadService service, boolean playing) { - if (hasInstances(context)) { - performUpdate(context, service, null, playing); - } - } - - /** - * Check against {@link AppWidgetManager} if there are any instances of this widget. - */ - private boolean hasInstances(Context context) { - AppWidgetManager manager = AppWidgetManager.getInstance(context); - int[] appWidgetIds = manager.getAppWidgetIds(new ComponentName(context, getClass())); - return (appWidgetIds.length > 0); - } - - /** - * Update all active widget instances by pushing changes - */ - private void performUpdate(Context context, DownloadService service, int[] appWidgetIds, boolean playing) { - final Resources res = context.getResources(); - final RemoteViews views = new RemoteViews(context.getPackageName(), getLayout()); - - if(playing) { - views.setViewVisibility(R.id.widget_root, View.VISIBLE); - } else { - // Hide widget - SharedPreferences prefs = Util.getPreferences(context); - if(prefs.getBoolean(Constants.PREFERENCES_KEY_HIDE_WIDGET, false)) { - views.setViewVisibility(R.id.widget_root, View.GONE); - } - } - - // Get Entry from current playing DownloadFile - MusicDirectory.Entry currentPlaying = null; - if(service == null) { - // Deserialize from playling list to setup - PlayerQueue state = FileUtil.deserialize(context, DownloadServiceLifecycleSupport.FILENAME_DOWNLOADS_SER, PlayerQueue.class); - if(state != null && state.currentPlayingIndex != -1) { - currentPlaying = state.songs.get(state.currentPlayingIndex); - } - } else { - currentPlaying = service.getCurrentPlaying() == null ? null : service.getCurrentPlaying().getSong(); - } - - String title = currentPlaying == null ? null : currentPlaying.getTitle(); - CharSequence artist = currentPlaying == null ? null : currentPlaying.getArtist(); - CharSequence album = currentPlaying == null ? null : currentPlaying.getAlbum(); - CharSequence errorState = null; - - // Show error message? - String status = Environment.getExternalStorageState(); - if (status.equals(Environment.MEDIA_SHARED) || - status.equals(Environment.MEDIA_UNMOUNTED)) { - errorState = res.getText(R.string.widget_sdcard_busy); - } else if (status.equals(Environment.MEDIA_REMOVED)) { - errorState = res.getText(R.string.widget_sdcard_missing); - } else if (currentPlaying == null) { - errorState = res.getText(R.string.widget_initial_text); - } - - if (errorState != null) { - // Show error state to user - views.setTextViewText(R.id.title,null); - views.setTextViewText(R.id.artist, errorState); - views.setTextViewText(R.id.album, ""); - if(getLayout() != R.layout.appwidget4x1) { - views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_default); - } - } else { - // No error, so show normal titles - views.setTextViewText(R.id.title, title); - views.setTextViewText(R.id.artist, artist); - if(getLayout() != R.layout.appwidget4x1) { - views.setTextViewText(R.id.album, album); - } - } - - // Set correct drawable for pause state - if (playing) { - views.setImageViewResource(R.id.control_play, R.drawable.ic_appwidget_music_pause); - } else { - views.setImageViewResource(R.id.control_play, R.drawable.ic_appwidget_music_play); - } - - // Set the cover art - try { - boolean large = false; - if(getLayout() != R.layout.appwidget4x1 && getLayout() != R.layout.appwidget4x2) { - large = true; - } - ImageLoader imageLoader = SubsonicActivity.getStaticImageLoader(context); - Bitmap bitmap = imageLoader == null ? null : imageLoader.getCachedImage(context, currentPlaying, large); - - if (bitmap == null) { - // Set default cover art - views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_unknown); - } else { - bitmap = getRoundedCornerBitmap(bitmap); - views.setImageViewBitmap(R.id.appwidget_coverart, bitmap); - } - } catch (Exception x) { - Log.e(TAG, "Failed to load cover art", x); - views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_unknown); - } - - // Link actions buttons to intents - linkButtons(context, views, currentPlaying != null); - - pushUpdate(context, appWidgetIds, views); - } - - /** - * Round the corners of a bitmap for the cover art image - */ - private static Bitmap getRoundedCornerBitmap(Bitmap bitmap) { - Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); - Canvas canvas = new Canvas(output); - - final int color = 0xff424242; - final Paint paint = new Paint(); - final float roundPx = 10; - - // Add extra width to the rect so the right side wont be rounded. - final Rect rect = new Rect(0, 0, bitmap.getWidth() + (int) roundPx, bitmap.getHeight()); - final RectF rectF = new RectF(rect); - - paint.setAntiAlias(true); - canvas.drawARGB(0, 0, 0, 0); - paint.setColor(color); - canvas.drawRoundRect(rectF, roundPx, roundPx, paint); - - paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); - canvas.drawBitmap(bitmap, rect, rect, paint); - - return output; - } - - /** - * Link up various button actions using {@link PendingIntent}. - * - * @param playerActive True if player is active in background, which means - * widget click will launch {@link DownloadActivity}, - * otherwise we launch {@link github.daneren2005.dsub.activity.SubsonicFragmentActivity}. - */ - private void linkButtons(Context context, RemoteViews views, boolean playerActive) { - Intent intent = new Intent(context, SubsonicFragmentActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); - views.setOnClickPendingIntent(R.id.appwidget_coverart, pendingIntent); - views.setOnClickPendingIntent(R.id.appwidget_top, pendingIntent); - - // Emulate media button clicks. - intent = new Intent("DSub.PLAY_PAUSE"); - intent.setComponent(new ComponentName(context, DownloadService.class)); - intent.setAction(DownloadService.CMD_TOGGLEPAUSE); - pendingIntent = PendingIntent.getService(context, 0, intent, 0); - views.setOnClickPendingIntent(R.id.control_play, pendingIntent); - - intent = new Intent("DSub.NEXT"); // Use a unique action name to ensure a different PendingIntent to be created. - intent.setComponent(new ComponentName(context, DownloadService.class)); - intent.setAction(DownloadService.CMD_NEXT); - pendingIntent = PendingIntent.getService(context, 0, intent, 0); - views.setOnClickPendingIntent(R.id.control_next, pendingIntent); - - intent = new Intent("DSub.PREVIOUS"); // Use a unique action name to ensure a different PendingIntent to be created. - intent.setComponent(new ComponentName(context, DownloadService.class)); - intent.setAction(DownloadService.CMD_PREVIOUS); - pendingIntent = PendingIntent.getService(context, 0, intent, 0); - views.setOnClickPendingIntent(R.id.control_previous, pendingIntent); - } -} diff --git a/src/github/daneren2005/dsub/provider/JukeboxRouteProvider.java b/src/github/daneren2005/dsub/provider/JukeboxRouteProvider.java deleted file mode 100644 index 0d2a5ff5..00000000 --- a/src/github/daneren2005/dsub/provider/JukeboxRouteProvider.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2014 (C) Scott Jackson -*/ -package github.daneren2005.dsub.provider; - -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.media.AudioManager; -import android.media.MediaRouter; -import android.support.v7.media.MediaControlIntent; -import android.support.v7.media.MediaRouteDescriptor; -import android.support.v7.media.MediaRouteProvider; -import android.support.v7.media.MediaRouteProviderDescriptor; - -import github.daneren2005.dsub.domain.RemoteControlState; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.RemoteController; - -/** - * Created by Scott on 11/28/13. - */ -public class JukeboxRouteProvider extends MediaRouteProvider { - public static final String CATEGORY_JUKEBOX_ROUTE = "github.daneren2005.dsub.SERVER_JUKEBOX"; - private RemoteController controller; - private static final int MAX_VOLUME = 10; - - private DownloadService downloadService; - - public JukeboxRouteProvider(Context context) { - super(context); - this.downloadService = (DownloadService) context; - - broadcastDescriptor(); - } - - private void broadcastDescriptor() { - // Create intents - IntentFilter routeIntentFilter = new IntentFilter(); - routeIntentFilter.addCategory(CATEGORY_JUKEBOX_ROUTE); - routeIntentFilter.addAction(MediaControlIntent.ACTION_START_SESSION); - routeIntentFilter.addAction(MediaControlIntent.ACTION_GET_SESSION_STATUS); - routeIntentFilter.addAction(MediaControlIntent.ACTION_END_SESSION); - - // Create route descriptor - MediaRouteDescriptor.Builder routeBuilder = new MediaRouteDescriptor.Builder("Jukebox Route", "Subsonic Jukebox"); - routeBuilder.addControlFilter(routeIntentFilter) - .setPlaybackStream(AudioManager.STREAM_MUSIC) - .setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE) - .setDescription("Subsonic Jukebox") - .setVolume(controller == null ? 5 : (int) (controller.getVolume() * 10)) - .setVolumeMax(MAX_VOLUME) - .setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE); - - // Create descriptor - MediaRouteProviderDescriptor.Builder providerBuilder = new MediaRouteProviderDescriptor.Builder(); - providerBuilder.addRoute(routeBuilder.build()); - setDescriptor(providerBuilder.build()); - } - - @Override - public MediaRouteProvider.RouteController onCreateRouteController(String routeId) { - return new JukeboxRouteController(downloadService); - } - - private class JukeboxRouteController extends RouteController { - private DownloadService downloadService; - - public JukeboxRouteController(DownloadService downloadService) { - this.downloadService = downloadService; - } - - @Override - public boolean onControlRequest(Intent intent, android.support.v7.media.MediaRouter.ControlRequestCallback callback) { - if (intent.hasCategory(CATEGORY_JUKEBOX_ROUTE)) { - return true; - } else { - return false; - } - } - - @Override - public void onRelease() { - downloadService.setRemoteEnabled(RemoteControlState.LOCAL); - controller = null; - } - - @Override - public void onSelect() { - downloadService.setRemoteEnabled(RemoteControlState.JUKEBOX_SERVER); - controller = downloadService.getRemoteController(); - } - - @Override - public void onUnselect() { - downloadService.setRemoteEnabled(RemoteControlState.LOCAL); - controller = null; - } - - @Override - public void onUpdateVolume(int delta) { - if(controller != null) { - controller.updateVolume(delta > 0); - } - broadcastDescriptor(); - } - - @Override - public void onSetVolume(int volume) { - if(controller != null) { - controller.setVolume(volume); - } - broadcastDescriptor(); - } - } -} diff --git a/src/github/daneren2005/dsub/provider/MostRecentStubProvider.java b/src/github/daneren2005/dsub/provider/MostRecentStubProvider.java deleted file mode 100644 index 17447cda..00000000 --- a/src/github/daneren2005/dsub/provider/MostRecentStubProvider.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.provider; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -/** - * Created by Scott on 8/28/13. - */ - -public class MostRecentStubProvider extends ContentProvider { - @Override - public boolean onCreate() { - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return ""; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/src/github/daneren2005/dsub/provider/PlaylistStubProvider.java b/src/github/daneren2005/dsub/provider/PlaylistStubProvider.java deleted file mode 100644 index e817c047..00000000 --- a/src/github/daneren2005/dsub/provider/PlaylistStubProvider.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.provider; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -/** - * Created by Scott on 8/28/13. - */ - -public class PlaylistStubProvider extends ContentProvider { - @Override - public boolean onCreate() { - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return ""; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/src/github/daneren2005/dsub/provider/PodcastStubProvider.java b/src/github/daneren2005/dsub/provider/PodcastStubProvider.java deleted file mode 100644 index 1c70e7f4..00000000 --- a/src/github/daneren2005/dsub/provider/PodcastStubProvider.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.provider; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -/** - * Created by Scott on 8/28/13. - */ - -public class PodcastStubProvider extends ContentProvider { - @Override - public boolean onCreate() { - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return ""; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/src/github/daneren2005/dsub/provider/StarredStubProvider.java b/src/github/daneren2005/dsub/provider/StarredStubProvider.java deleted file mode 100644 index 27a84e3f..00000000 --- a/src/github/daneren2005/dsub/provider/StarredStubProvider.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.provider; - -import android.content.ContentProvider; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; - -/** - * Created by Scott on 8/28/13. - */ - -public class StarredStubProvider extends ContentProvider { - @Override - public boolean onCreate() { - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - return null; - } - - @Override - public String getType(Uri uri) { - return ""; - } - - @Override - public Uri insert(Uri uri, ContentValues values) { - return null; - } - - @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - return 0; - } - - @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - return 0; - } -} diff --git a/src/github/daneren2005/dsub/receiver/A2dpIntentReceiver.java b/src/github/daneren2005/dsub/receiver/A2dpIntentReceiver.java deleted file mode 100644 index f1837fd7..00000000 --- a/src/github/daneren2005/dsub/receiver/A2dpIntentReceiver.java +++ /dev/null @@ -1,47 +0,0 @@ -package github.daneren2005.dsub.receiver; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.util.Log; -import github.daneren2005.dsub.service.DownloadService; - -public class A2dpIntentReceiver extends BroadcastReceiver { - private static final String PLAYSTATUS_RESPONSE = "com.android.music.playstatusresponse"; - private String TAG = A2dpIntentReceiver.class.getSimpleName(); - - @Override - public void onReceive(Context context, Intent intent) { - Log.i(TAG, "GOT INTENT " + intent); - - DownloadService downloadService = DownloadService.getInstance(); - - if (downloadService != null){ - - Intent avrcpIntent = new Intent(PLAYSTATUS_RESPONSE); - - avrcpIntent.putExtra("duration", (long) downloadService.getPlayerDuration()); - avrcpIntent.putExtra("position", (long) downloadService.getPlayerPosition()); - avrcpIntent.putExtra("ListSize", (long) downloadService.getSongs().size()); - - switch (downloadService.getPlayerState()){ - case STARTED: - avrcpIntent.putExtra("playing", true); - break; - case STOPPED: - avrcpIntent.putExtra("playing", false); - break; - case PAUSED: - avrcpIntent.putExtra("playing", false); - break; - case COMPLETED: - avrcpIntent.putExtra("playing", false); - break; - default: - return; - } - - context.sendBroadcast(avrcpIntent); - } - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/receiver/AudioNoisyReceiver.java b/src/github/daneren2005/dsub/receiver/AudioNoisyReceiver.java deleted file mode 100644 index b4ace297..00000000 --- a/src/github/daneren2005/dsub/receiver/AudioNoisyReceiver.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.receiver; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.media.AudioManager; -import android.util.Log; - -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; - -public class AudioNoisyReceiver extends BroadcastReceiver { - private static final String TAG = AudioNoisyReceiver.class.getSimpleName(); - - @Override - public void onReceive(Context context, Intent intent) { - DownloadService downloadService = DownloadService.getInstance(); - // Don't do anything if downloadService is not started - if(downloadService == null) { - return; - } - - if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals (intent.getAction ())) { - if(!downloadService.isRemoteEnabled() && (downloadService.getPlayerState() == PlayerState.STARTED || downloadService.getPlayerState() == PlayerState.PAUSED_TEMP)) { - SharedPreferences prefs = Util.getPreferences(downloadService); - int pausePref = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_PAUSE_DISCONNECT, "0")); - if(pausePref == 0) { - downloadService.pause(); - } - } - } - } -} diff --git a/src/github/daneren2005/dsub/receiver/BootReceiver.java b/src/github/daneren2005/dsub/receiver/BootReceiver.java deleted file mode 100644 index 634aeeee..00000000 --- a/src/github/daneren2005/dsub/receiver/BootReceiver.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2015 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.receiver; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -import github.daneren2005.dsub.service.HeadphoneListenerService; -import github.daneren2005.dsub.util.Util; - -public class BootReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if(Util.shouldStartOnHeadphones(context)) { - Intent serviceIntent = new Intent(); - serviceIntent.setClassName(context.getPackageName(), HeadphoneListenerService.class.getName()); - context.startService(serviceIntent); - } - } -} diff --git a/src/github/daneren2005/dsub/receiver/HeadphonePlugReceiver.java b/src/github/daneren2005/dsub/receiver/HeadphonePlugReceiver.java deleted file mode 100644 index 77948c41..00000000 --- a/src/github/daneren2005/dsub/receiver/HeadphonePlugReceiver.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2015 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.receiver; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.util.Log; - -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.util.Util; - -public class HeadphonePlugReceiver extends BroadcastReceiver { - private static final String TAG = HeadphonePlugReceiver.class.getSimpleName(); - - @Override - public void onReceive(Context context, Intent intent) { - if(Intent.ACTION_HEADSET_PLUG.equals(intent.getAction())) { - int headphoneState = intent.getIntExtra("state", -1); - Log.d(TAG, "State: " + headphoneState); - if(headphoneState == 1 && Util.shouldStartOnHeadphones(context)) { - Log.d(TAG, "Fired play event"); - Intent start = new Intent(context, DownloadService.class); - start.setAction(DownloadService.START_PLAY); - context.startService(start); - } - } - } -} diff --git a/src/github/daneren2005/dsub/receiver/MediaButtonIntentReceiver.java b/src/github/daneren2005/dsub/receiver/MediaButtonIntentReceiver.java deleted file mode 100644 index 8119ef2d..00000000 --- a/src/github/daneren2005/dsub/receiver/MediaButtonIntentReceiver.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.receiver; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.util.Log; -import android.view.KeyEvent; - -import github.daneren2005.dsub.service.DownloadService; - -/** - * @author Sindre Mehus - */ -public class MediaButtonIntentReceiver extends BroadcastReceiver { - - private static final String TAG = MediaButtonIntentReceiver.class.getSimpleName(); - - @Override - public void onReceive(Context context, Intent intent) { - KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT); - if(DownloadService.getInstance() == null && (event.getKeyCode() == KeyEvent.KEYCODE_MEDIA_STOP || - event.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) { - Log.w(TAG, "Ignore keycode event because downloadService is off"); - return; - } - Log.i(TAG, "Got MEDIA_BUTTON key event: " + event); - - Intent serviceIntent = new Intent(context, DownloadService.class); - serviceIntent.putExtra(Intent.EXTRA_KEY_EVENT, event); - context.startService(serviceIntent); - if (isOrderedBroadcast()) { - try { - abortBroadcast(); - } catch (Exception x) { - // Ignored. - } - } - } -} diff --git a/src/github/daneren2005/dsub/receiver/PlayActionReceiver.java b/src/github/daneren2005/dsub/receiver/PlayActionReceiver.java deleted file mode 100644 index 2c04d829..00000000 --- a/src/github/daneren2005/dsub/receiver/PlayActionReceiver.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.receiver; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.util.Log; - -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.util.Constants; - -public class PlayActionReceiver extends BroadcastReceiver { - private static final String TAG = PlayActionReceiver.class.getSimpleName(); - - @Override - public void onReceive(Context context, Intent intent) { - if(intent.hasExtra(Constants.TASKER_EXTRA_BUNDLE)) { - Bundle data = intent.getBundleExtra(Constants.TASKER_EXTRA_BUNDLE); - Boolean startShuffled = data.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE); - - Intent start = new Intent(context, DownloadService.class); - start.setAction(DownloadService.START_PLAY); - start.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, startShuffled); - start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR)); - start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR)); - start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE)); - start.putExtra(Constants.PREFERENCES_KEY_OFFLINE, data.getInt(Constants.PREFERENCES_KEY_OFFLINE)); - context.startService(start); - } - } -} diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java deleted file mode 100644 index 61d6205a..00000000 --- a/src/github/daneren2005/dsub/service/CachedMusicService.java +++ /dev/null @@ -1,1424 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.concurrent.TimeUnit; - -import org.apache.http.HttpResponse; - -import android.content.Context; -import android.graphics.Bitmap; - -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.ArtistInfo; -import github.daneren2005.dsub.domain.Bookmark; -import github.daneren2005.dsub.domain.ChatMessage; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.PlayerQueue; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.domain.RemoteStatus; -import github.daneren2005.dsub.domain.Lyrics; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.MusicFolder; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.domain.SearchCritera; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.domain.Share; -import github.daneren2005.dsub.domain.User; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.TimeLimitedCache; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Util; - -import static github.daneren2005.dsub.domain.MusicDirectory.Entry; - -/** - * @author Sindre Mehus - */ -public class CachedMusicService implements MusicService { - private static final String TAG = CachedMusicService.class.getSimpleName(); - - private static final int MUSIC_DIR_CACHE_SIZE = 20; - private static final int TTL_MUSIC_DIR = 5 * 60; // Five minutes - - private final RESTMusicService musicService; - private final TimeLimitedCache cachedLicenseValid = new TimeLimitedCache(120, TimeUnit.SECONDS); - private final TimeLimitedCache cachedIndexes = new TimeLimitedCache(60 * 60, TimeUnit.SECONDS); - private final TimeLimitedCache> cachedPlaylists = new TimeLimitedCache>(3600, TimeUnit.SECONDS); - private final TimeLimitedCache> cachedMusicFolders = new TimeLimitedCache>(10 * 3600, TimeUnit.SECONDS); - private final TimeLimitedCache> cachedPodcastChannels = new TimeLimitedCache>(10 * 3600, TimeUnit.SECONDS); - private String restUrl; - private String musicFolderId; - private boolean isTagBrowsing = false; - - public CachedMusicService(RESTMusicService musicService) { - this.musicService = musicService; - } - - @Override - public void ping(Context context, ProgressListener progressListener) throws Exception { - checkSettingsChanged(context); - musicService.ping(context, progressListener); - } - - @Override - public boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception { - checkSettingsChanged(context); - Boolean result = cachedLicenseValid.get(); - if (result == null) { - result = FileUtil.deserialize(context, getCacheName(context, "license"), Boolean.class); - - if(result == null) { - result = musicService.isLicenseValid(context, progressListener); - - // Only save a copy license is valid - if(result) { - FileUtil.serialize(context, (Boolean) result, getCacheName(context, "license")); - } - } - cachedLicenseValid.set(result, result ? 30L * 60L : 2L * 60L, TimeUnit.SECONDS); - } - return result; - } - - @Override - public List getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkSettingsChanged(context); - if (refresh) { - cachedMusicFolders.clear(); - } - List result = cachedMusicFolders.get(); - if (result == null) { - if(!refresh) { - result = FileUtil.deserialize(context, getCacheName(context, "musicFolders"), ArrayList.class); - } - - if(result == null) { - result = musicService.getMusicFolders(refresh, context, progressListener); - FileUtil.serialize(context, new ArrayList(result), getCacheName(context, "musicFolders")); - } - cachedMusicFolders.set(result); - } - return result; - } - - @Override - public void startRescan(Context context, ProgressListener listener) throws Exception { - musicService.startRescan(context, listener); - } - - @Override - public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkSettingsChanged(context); - if (refresh) { - cachedIndexes.clear(); - cachedMusicFolders.clear(); - } - Indexes result = cachedIndexes.get(); - if (result == null) { - String name = Util.isTagBrowsing(context, musicService.getInstance(context)) ? "artists" : "indexes"; - name = getCacheName(context, name, musicFolderId); - if(!refresh) { - result = FileUtil.deserialize(context, name, Indexes.class); - } - - if(result == null) { - result = musicService.getIndexes(musicFolderId, refresh, context, progressListener); - FileUtil.serialize(context, result, name); - } - cachedIndexes.set(result); - } - return result; - } - - @Override - public MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - MusicDirectory dir = null; - MusicDirectory cached = FileUtil.deserialize(context, getCacheName(context, "directory", id), MusicDirectory.class); - if(!refresh) { - dir = cached; - } - - if(dir == null) { - dir = musicService.getMusicDirectory(id, name, refresh, context, progressListener); - FileUtil.serialize(context, dir, getCacheName(context, "directory", id)); - - // If a cached copy exists to check against, look for removes - deleteRemovedEntries(context, dir, cached); - } - - return dir; - } - - @Override - public MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - MusicDirectory dir = null; - MusicDirectory cached = FileUtil.deserialize(context, getCacheName(context, "artist", id), MusicDirectory.class); - if(!refresh) { - dir = cached; - } - - if(dir == null) { - dir = musicService.getArtist(id, name, refresh, context, progressListener); - FileUtil.serialize(context, dir, getCacheName(context, "artist", id)); - - // If a cached copy exists to check against, look for removes - deleteRemovedEntries(context, dir, cached); - } - - return dir; - } - - @Override - public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - MusicDirectory dir = null; - MusicDirectory cached = FileUtil.deserialize(context, getCacheName(context, "album", id), MusicDirectory.class); - if(!refresh) { - dir = cached; - } - - if(dir == null) { - dir = musicService.getAlbum(id, name, refresh, context, progressListener); - FileUtil.serialize(context, dir, getCacheName(context, "album", id)); - - // If a cached copy exists to check against, look for removes - deleteRemovedEntries(context, dir, cached); - } - - return dir; - } - - @Override - public SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception { - return musicService.search(criteria, context, progressListener); - } - - @Override - public MusicDirectory getPlaylist(boolean refresh, String id, String name, Context context, ProgressListener progressListener) throws Exception { - MusicDirectory dir = null; - MusicDirectory cachedPlaylist = FileUtil.deserialize(context, getCacheName(context, "playlist", id), MusicDirectory.class); - if(!refresh) { - dir = cachedPlaylist; - } - if(dir == null) { - dir = musicService.getPlaylist(refresh, id, name, context, progressListener); - FileUtil.serialize(context, dir, getCacheName(context, "playlist", id)); - - File playlistFile = FileUtil.getPlaylistFile(context, Util.getServerName(context, musicService.getInstance(context)), dir.getName()); - if(cachedPlaylist == null || !playlistFile.exists() || !cachedPlaylist.getChildren().equals(dir.getChildren())) { - FileUtil.writePlaylistFile(context, playlistFile, dir); - } - } - return dir; - } - - @Override - public List getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkSettingsChanged(context); - List result = refresh ? null : cachedPlaylists.get(); - if (result == null) { - if(!refresh) { - result = FileUtil.deserialize(context, getCacheName(context, "playlist"), ArrayList.class); - } - - if(result == null) { - result = musicService.getPlaylists(refresh, context, progressListener); - FileUtil.serialize(context, new ArrayList(result), getCacheName(context, "playlist")); - } - cachedPlaylists.set(result); - } - return result; - } - - @Override - public void createPlaylist(String id, String name, List entries, Context context, ProgressListener progressListener) throws Exception { - cachedPlaylists.clear(); - Util.delete(new File(context.getCacheDir(), getCacheName(context, "playlist"))); - musicService.createPlaylist(id, name, entries, context, progressListener); - } - - @Override - public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception { - musicService.deletePlaylist(id, context, progressListener); - - new PlaylistUpdater(context, id) { - @Override - public void updateResult(List objects, Playlist result) { - objects.remove(result); - cachedPlaylists.set(objects); - } - }.execute(); - } - - @Override - public void addToPlaylist(String id, final List toAdd, Context context, ProgressListener progressListener) throws Exception { - musicService.addToPlaylist(id, toAdd, context, progressListener); - - new MusicDirectoryUpdater(context, "playlist", id) { - @Override - public boolean checkResult(Entry check) { - return true; - } - - @Override - public void updateResult(List objects, Entry result) { - objects.addAll(toAdd); - } - }.execute(); - } - - @Override - public void removeFromPlaylist(String id, final List toRemove, Context context, ProgressListener progressListener) throws Exception { - musicService.removeFromPlaylist(id, toRemove, context, progressListener); - - new MusicDirectoryUpdater(context, "playlist", id) { - @Override - public boolean checkResult(Entry check) { - return true; - } - - @Override - public void updateResult(List objects, Entry result) { - // Remove in reverse order so indexes are still correct as we iterate through - for(ListIterator iterator = toRemove.listIterator(toRemove.size()); iterator.hasPrevious(); ) { - objects.remove((int) iterator.previous()); - } - } - }.execute(); - } - - @Override - public void overwritePlaylist(String id, String name, int toRemove, final List toAdd, Context context, ProgressListener progressListener) throws Exception { - musicService.overwritePlaylist(id, name, toRemove, toAdd, context, progressListener); - - new MusicDirectoryUpdater(context, "playlist", id) { - @Override - public boolean checkResult(Entry check) { - return true; - } - - @Override - public void updateResult(List objects, Entry result) { - objects.clear(); - objects.addAll(toAdd); - } - }.execute(); - } - - @Override - public void updatePlaylist(String id, final String name, final String comment, final boolean pub, Context context, ProgressListener progressListener) throws Exception { - musicService.updatePlaylist(id, name, comment, pub, context, progressListener); - - new PlaylistUpdater(context, id) { - @Override - public void updateResult(List objects, Playlist result) { - result.setName(name); - result.setComment(comment); - result.setPublic(pub); - - cachedPlaylists.set(objects); - } - }.execute(); - } - - @Override - public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception { - return musicService.getLyrics(artist, title, context, progressListener); - } - - @Override - public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception { - musicService.scrobble(id, submission, context, progressListener); - } - - @Override - public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception { - try { - MusicDirectory dir = musicService.getAlbumList(type, size, offset, context, progressListener); - - // Do some serialization updates for changes to recently added - if ("newest".equals(type) && offset == 0) { - String recentlyAddedFile = getCacheName(context, type); - ArrayList recents = FileUtil.deserialize(context, recentlyAddedFile, ArrayList.class); - if (recents == null) { - recents = new ArrayList(); - } - - // Add any new items - final int instance = musicService.getInstance(context); - isTagBrowsing = Util.isTagBrowsing(context, instance); - for (final Entry album : dir.getChildren()) { - if (!recents.contains(album.getId())) { - recents.add(album.getId()); - - String cacheName, parent; - if (isTagBrowsing) { - cacheName = "artist"; - parent = album.getArtistId(); - } else { - cacheName = "directory"; - parent = album.getParent(); - } - - // Add album to artist - if (parent != null) { - new MusicDirectoryUpdater(context, cacheName, parent) { - private boolean changed = false; - - @Override - public boolean checkResult(Entry check) { - return true; - } - - @Override - public void updateResult(List objects, Entry result) { - // Only add if it doesn't already exist in it! - if (!objects.contains(album)) { - objects.add(album); - changed = true; - } - } - - @Override - public void save(ArrayList objects) { - // Only save if actually added to artist - if (changed) { - musicDirectory.replaceChildren(objects); - // Reapply sort after addition - musicDirectory.sortChildren(context, instance); - FileUtil.serialize(context, musicDirectory, cacheName); - } - } - }.execute(); - } else { - // If parent is null, then this is a root level album - final Artist artist = new Artist(); - artist.setId(album.getId()); - artist.setName(album.getTitle()); - - new IndexesUpdater(context, isTagBrowsing ? "artists" : "indexes") { - private boolean changed = false; - - @Override - public boolean checkResult(Artist check) { - return true; - } - - @Override - public void updateResult(List objects, Artist result) { - if (!objects.contains(artist)) { - objects.add(artist); - changed = true; - } - } - - @Override - public void save(ArrayList objects) { - if (changed) { - indexes.setArtists(objects); - // Reapply sort after addition - indexes.sortChildren(context); - FileUtil.serialize(context, indexes, cacheName); - cachedIndexes.set(indexes); - } - } - }.execute(); - } - } - } - - // Keep list from growing into infinity - while (recents.size() > 0) { - recents.remove(0); - } - FileUtil.serialize(context, recents, recentlyAddedFile); - } - - FileUtil.serialize(context, dir, getCacheName(context, type, Integer.toString(offset))); - return dir; - } catch(IOException e) { - MusicDirectory dir = FileUtil.deserialize(context, getCacheName(context, type, Integer.toString(offset)), MusicDirectory.class); - - if(dir == null) { - // If we are at start and no cache, throw error higher - if(offset == 0) { - throw e; - } else { - // Otherwise just pretend we are at the end of the list - return new MusicDirectory(); - } - } else { - return dir; - } - } - } - - @Override - public MusicDirectory getAlbumList(String type, String extra, int size, int offset, Context context, ProgressListener progressListener) throws Exception { - try { - MusicDirectory dir = musicService.getAlbumList(type, extra, size, offset, context, progressListener); - FileUtil.serialize(context, dir, getCacheName(context, type + extra, Integer.toString(offset))); - return dir; - } catch(IOException e) { - MusicDirectory dir = FileUtil.deserialize(context, getCacheName(context, type + extra, Integer.toString(offset)), MusicDirectory.class); - - if(dir == null) { - // If we are at start and no cache, throw error higher - if(offset == 0) { - throw e; - } else { - // Otherwise just pretend we are at the end of the list - return new MusicDirectory(); - } - } else { - return dir; - } - } - } - - @Override - public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception { - return musicService.getRandomSongs(size, artistId, context, progressListener); - } - - @Override - public MusicDirectory getStarredList(Context context, ProgressListener progressListener) throws Exception { - try { - MusicDirectory dir = musicService.getStarredList(context, progressListener); - - MusicDirectory oldDir = FileUtil.deserialize(context, "starred", MusicDirectory.class); - if (oldDir != null) { - final List newList = new ArrayList(); - newList.addAll(dir.getChildren()); - final List oldList = oldDir.getChildren(); - - for (Iterator it = oldList.iterator(); it.hasNext(); ) { - Entry oldEntry = it.next(); - - // Remove entries from newList - if (newList.remove(oldEntry)) { - // If it was removed, then remove it from old list as well - it.remove(); - } else { - oldEntry.setStarred(false); - } - } - - List totalList = new ArrayList(); - totalList.addAll(oldList); - totalList.addAll(newList); - - new StarUpdater(context, totalList).execute(); - } - FileUtil.serialize(context, dir, "starred"); - - return dir; - } catch(IOException e) { - MusicDirectory dir = FileUtil.deserialize(context, "starred", MusicDirectory.class); - if(dir == null) { - throw e; - } else { - return dir; - } - } - } - - @Override - public MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception { - return musicService.getRandomSongs(size, folder, genre, startYear, endYear, context, progressListener); - } - - @Override - public String getCoverArtUrl(Context context, Entry entry) throws Exception { - return musicService.getCoverArtUrl(context, entry); - } - - @Override - public Bitmap getCoverArt(Context context, Entry entry, int size, ProgressListener progressListener, SilentBackgroundTask task) throws Exception { - return musicService.getCoverArt(context, entry, size, progressListener, task); - } - - @Override - public HttpResponse getDownloadInputStream(Context context, Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception { - return musicService.getDownloadInputStream(context, song, offset, maxBitrate, task); - } - - @Override - public String getMusicUrl(Context context, Entry song, int maxBitrate) throws Exception { - return musicService.getMusicUrl(context, song, maxBitrate); - } - - @Override - public String getVideoUrl(int maxBitrate, Context context, String id) { - return musicService.getVideoUrl(maxBitrate, context, id); - } - - @Override - public String getVideoStreamUrl(String format, int maxBitrate, Context context, String id) throws Exception { - return musicService.getVideoStreamUrl(format, maxBitrate, context, id); - } - - @Override - public String getHlsUrl(String id, int bitRate, Context context) throws Exception { - return musicService.getHlsUrl(id, bitRate, context); - } - - @Override - public RemoteStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception { - return musicService.updateJukeboxPlaylist(ids, context, progressListener); - } - - @Override - public RemoteStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception { - return musicService.skipJukebox(index, offsetSeconds, context, progressListener); - } - - @Override - public RemoteStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception { - return musicService.stopJukebox(context, progressListener); - } - - @Override - public RemoteStatus startJukebox(Context context, ProgressListener progressListener) throws Exception { - return musicService.startJukebox(context, progressListener); - } - - @Override - public RemoteStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception { - return musicService.getJukeboxStatus(context, progressListener); - } - - @Override - public RemoteStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception { - return musicService.setJukeboxGain(gain, context, progressListener); - } - - @Override - public void setStarred(List entries, List artists, List albums, final boolean starred, ProgressListener progressListener, Context context) throws Exception { - musicService.setStarred(entries, artists, albums, starred, progressListener, context); - - // Fuzzy logic to update parents serialization - List allEntries = new ArrayList(); - if(artists != null) { - allEntries.addAll(artists); - } - if(albums != null) { - allEntries.addAll(albums); - } - if (entries != null) { - allEntries.addAll(entries); - } - - new StarUpdater(context, allEntries).execute(); - } - - @Override - public List getShares(Context context, ProgressListener progressListener) throws Exception { - return musicService.getShares(context, progressListener); - } - - @Override - public List createShare(List ids, String description, Long expires, Context context, ProgressListener progressListener) throws Exception { - return musicService.createShare(ids, description, expires, context, progressListener); - } - - @Override - public void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception { - musicService.deleteShare(id, context, progressListener); - } - - @Override - public void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception { - musicService.updateShare(id, description, expires, context, progressListener); - } - - @Override - public List getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception { - return musicService.getChatMessages(since, context, progressListener); - } - - @Override - public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception { - musicService.addChatMessage(message, context, progressListener); - } - - @Override - public List getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List result = null; - - if(!refresh) { - result = FileUtil.deserialize(context, getCacheName(context, "genre"), ArrayList.class); - } - - if(result == null) { - result = musicService.getGenres(refresh, context, progressListener); - FileUtil.serialize(context, new ArrayList(result), getCacheName(context, "genre")); - } - - return result; - } - - @Override - public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception { - try { - MusicDirectory dir = musicService.getSongsByGenre(genre, count, offset, context, progressListener); - FileUtil.serialize(context, dir, getCacheName(context, "genreSongs", Integer.toString(offset))); - - return dir; - } catch(IOException e) { - MusicDirectory dir = FileUtil.deserialize(context, getCacheName(context, "genreSongs", Integer.toString(offset)), MusicDirectory.class); - - if(dir == null) { - // If we are at start and no cache, throw error higher - if(offset == 0) { - throw e; - } else { - // Otherwise just pretend we are at the end of the list - return new MusicDirectory(); - } - } else { - return dir; - } - } - } - - @Override - public MusicDirectory getTopTrackSongs(String artist, int size, Context context, ProgressListener progressListener) throws Exception { - return musicService.getTopTrackSongs(artist, size, context, progressListener); - } - - @Override - public List getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkSettingsChanged(context); - List result = refresh ? null : cachedPodcastChannels.get(); - - if (result == null) { - if(!refresh) { - result = FileUtil.deserialize(context, getCacheName(context, "podcast"), ArrayList.class); - } - - if(result == null) { - result = musicService.getPodcastChannels(refresh, context, progressListener); - FileUtil.serialize(context, new ArrayList(result), getCacheName(context, "podcast")); - } - cachedPodcastChannels.set(result); - } - - return result; - } - - @Override - public MusicDirectory getPodcastEpisodes(boolean refresh, String id, Context context, ProgressListener progressListener) throws Exception { - String altId = "p-" + id; - MusicDirectory result = null; - - if(!refresh) { - result = FileUtil.deserialize(context, getCacheName(context, "directory", altId), MusicDirectory.class, 10); - } - - if(result == null) { - result = musicService.getPodcastEpisodes(refresh, id, context, progressListener); - FileUtil.serialize(context, result, getCacheName(context, "directory", altId)); - } - - return result; - } - - @Override - public void refreshPodcasts(Context context, ProgressListener progressListener) throws Exception { - musicService.refreshPodcasts(context, progressListener); - } - - @Override - public void createPodcastChannel(String url, Context context, ProgressListener progressListener) throws Exception{ - musicService.createPodcastChannel(url, context, progressListener); - } - - @Override - public void deletePodcastChannel(final String id, Context context, ProgressListener progressListener) throws Exception{ - new SerializeUpdater(context, "podcast") { - @Override - public boolean checkResult(PodcastChannel check) { - return id.equals(check.getId()); - } - - @Override - public void updateResult(List objects, PodcastChannel result) { - objects.remove(result); - cachedPodcastChannels.set(objects); - } - }.execute(); - musicService.deletePodcastChannel(id, context, progressListener); - } - - @Override - public void downloadPodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{ - musicService.downloadPodcastEpisode(id, context, progressListener); - } - - @Override - public void deletePodcastEpisode(final String id, String parent, ProgressListener progressListener, Context context) throws Exception{ - musicService.deletePodcastEpisode(id, parent, progressListener, context); - - new MusicDirectoryUpdater(context, "directory", "p-" + parent) { - @Override - public boolean checkResult(Entry check) { - return id.equals(((PodcastEpisode) check).getEpisodeId()); - } - - @Override - public void updateResult(List objects, Entry result) { - objects.remove(result); - } - }.execute(); - } - - @Override - public void setRating(final Entry entry, final int rating, Context context, ProgressListener progressListener) throws Exception { - musicService.setRating(entry, rating, context, progressListener); - - new GenericEntryUpdater(context, entry) { - @Override - public void updateResult(Entry result) { - result.setRating(rating); - } - }.execute(); - } - - @Override - public MusicDirectory getBookmarks(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - MusicDirectory bookmarks = musicService.getBookmarks(refresh, context, progressListener); - - MusicDirectory oldBookmarks = FileUtil.deserialize(context, "bookmarks", MusicDirectory.class); - if(oldBookmarks != null) { - final List oldList = oldBookmarks.getChildren(); - final List newList = new ArrayList(); - newList.addAll(bookmarks.getChildren()); - - for(Iterator it = oldList.iterator(); it.hasNext(); ) { - Entry oldEntry = it.next(); - // Remove entries from newList - int position = newList.indexOf(oldEntry); - if(position != -1) { - Entry newEntry = newList.get(position); - if(newEntry.getBookmark().getPosition() == oldEntry.getBookmark().getPosition()) { - newList.remove(position); - } - - // Remove from old regardless of whether position is wrong - it.remove(); - } else { - oldEntry.setBookmark(null); - } - } - - List totalList = new ArrayList(); - totalList.addAll(oldList); - totalList.addAll(newList); - - new BookmarkUpdater(context, totalList).execute(); - } - FileUtil.serialize(context, bookmarks, "bookmarks"); - - return bookmarks; - } - - @Override - public void createBookmark(Entry entry, int position, String comment, Context context, ProgressListener progressListener) throws Exception { - musicService.createBookmark(entry, position, comment, context, progressListener); - - new BookmarkUpdater(context, entry).execute(); - } - - @Override - public void deleteBookmark(Entry entry, Context context, ProgressListener progressListener) throws Exception { - musicService.deleteBookmark(entry, context, progressListener); - - new BookmarkUpdater(context, entry).execute(); - } - - @Override - public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception { - User result = null; - - try { - result = musicService.getUser(refresh, username, context, progressListener); - FileUtil.serialize(context, result, getCacheName(context, "user-" + username)); - } catch(Exception e) { - // Don't care - } - - if(result == null && !refresh) { - result = FileUtil.deserialize(context, getCacheName(context, "user-" + username), User.class); - } - - return result; - } - - @Override - public List getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List result = null; - - if(!refresh) { - result = FileUtil.deserialize(context, getCacheName(context, "users"), ArrayList.class); - } - - if(result == null) { - result = musicService.getUsers(refresh, context, progressListener); - FileUtil.serialize(context, new ArrayList(result), getCacheName(context, "users")); - } - - return result; - } - - @Override - public void createUser(final User user, Context context, ProgressListener progressListener) throws Exception { - musicService.createUser(user, context, progressListener); - - new UserUpdater(context, "") { - @Override - public boolean checkResult(User check) { - return true; - } - - @Override - public void updateResult(List users, User result) { - users.add(user); - } - }.execute(); - } - - @Override - public void updateUser(final User user, Context context, ProgressListener progressListener) throws Exception { - musicService.updateUser(user, context, progressListener); - - new UserUpdater(context, user.getUsername()) { - @Override - public void updateResult(List users, User result) { - result.setEmail(user.getEmail()); - result.setSettings(user.getSettings()); - } - }.execute(); - } - - @Override - public void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception { - musicService.deleteUser(username, context, progressListener); - - new UserUpdater(context, username) { - @Override - public void updateResult(List users, User result) { - users.remove(result); - } - }.execute(); - } - - @Override - public void changeEmail(String username, final String email, Context context, ProgressListener progressListener) throws Exception { - musicService.changeEmail(username, email, context, progressListener); - - // Update cached email for user - new UserUpdater(context, username) { - @Override - public void updateResult(List users, User result) { - result.setEmail(email); - } - }.execute(); - } - - @Override - public void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception { - musicService.changePassword(username, password, context, progressListener); - } - - @Override - public Bitmap getAvatar(String username, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception { - return musicService.getAvatar(username, size, context, progressListener, task); - } - - @Override - public ArtistInfo getArtistInfo(String id, boolean refresh, boolean allowNetwork, Context context, ProgressListener progressListener) throws Exception { - String cacheName = getCacheName(context, "artistInfo", id); - ArtistInfo info = null; - if(!refresh) { - info = FileUtil.deserialize(context, cacheName, ArtistInfo.class); - } - - if(info == null && allowNetwork) { - info = musicService.getArtistInfo(id, refresh, allowNetwork, context, progressListener); - FileUtil.serialize(context, info, cacheName); - } - - return info; - } - - @Override - public Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception { - return musicService.getBitmap(url, size, context, progressListener, task); - } - - @Override - public MusicDirectory getVideos(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - try { - MusicDirectory dir = musicService.getVideos(refresh, context, progressListener); - FileUtil.serialize(context, dir, "videos"); - - return dir; - } catch(IOException e) { - MusicDirectory dir = FileUtil.deserialize(context, "videos", MusicDirectory.class); - if(dir == null) { - throw e; - } else { - return dir; - } - } - } - - @Override - public void savePlayQueue(List songs, Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception { - musicService.savePlayQueue(songs, currentPlaying, position, context, progressListener); - } - - @Override - public PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception { - return musicService.getPlayQueue(context, progressListener); - } - - @Override - public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ - return musicService.processOfflineSyncs(context, progressListener); - } - - @Override - public void setInstance(Integer instance) throws Exception { - musicService.setInstance(instance); - } - - private String getCacheName(Context context, String name, String id) { - String s = musicService.getRestUrl(context, null, false) + id; - return name + "-" + s.hashCode() + ".ser"; - } - private String getCacheName(Context context, String name) { - String s = musicService.getRestUrl(context, null, false); - return name + "-" + s.hashCode() + ".ser"; - } - - private void deleteRemovedEntries(Context context, MusicDirectory dir, MusicDirectory cached) { - if(cached != null) { - List oldList = new ArrayList(); - oldList.addAll(cached.getChildren()); - - // Remove all current items from old list - for(Entry entry: dir.getChildren()) { - oldList.remove(entry); - } - - // Anything remaining has been removed from server - MediaStoreService store = new MediaStoreService(context); - for(Entry entry: oldList) { - File file = FileUtil.getEntryFile(context, entry); - FileUtil.recursiveDelete(file, store); - } - } - } - - private abstract class SerializeUpdater { - final Context context; - final String cacheName; - final boolean singleUpdate; - - public SerializeUpdater(Context context, String cacheName) { - this(context, cacheName, true); - } - public SerializeUpdater(Context context, String cacheName, boolean singleUpdate) { - this.context = context; - this.cacheName = getCacheName(context, cacheName); - this.singleUpdate = singleUpdate; - } - public SerializeUpdater(Context context, String cacheName, String id) { - this(context, cacheName, id, true); - } - public SerializeUpdater(Context context, String cacheName, String id, boolean singleUpdate) { - this.context = context; - this.cacheName = getCacheName(context, cacheName, id); - this.singleUpdate = singleUpdate; - } - - public ArrayList getArrayList() { - return FileUtil.deserialize(context, cacheName, ArrayList.class); - } - public abstract boolean checkResult(T check); - public abstract void updateResult(List objects, T result); - public void save(ArrayList objects) { - FileUtil.serialize(context, objects, cacheName); - } - - public void execute() { - ArrayList objects = getArrayList(); - - // Only execute if something to check against - if(objects != null) { - List results = new ArrayList(); - for(T check: objects) { - if(checkResult(check)) { - results.add(check); - if(singleUpdate) { - break; - } - } - } - - // Iterate through and update each object matched - for(T result: results) { - updateResult(objects, result); - } - - // Only reserialize if at least one match was found - if(results.size() > 0) { - save(objects); - } - } - } - } - private abstract class UserUpdater extends SerializeUpdater { - String username; - - public UserUpdater(Context context, String username) { - super(context, "users"); - this.username = username; - } - - @Override - public boolean checkResult(User check) { - return username.equals(check.getUsername()); - } - } - private abstract class PlaylistUpdater extends SerializeUpdater { - String id; - - public PlaylistUpdater(Context context, String id) { - super(context, "playlist"); - this.id = id; - } - - @Override - public boolean checkResult(Playlist check) { - return id.equals(check.getId()); - } - } - private abstract class MusicDirectoryUpdater extends SerializeUpdater { - protected MusicDirectory musicDirectory; - - public MusicDirectoryUpdater(Context context, String cacheName, String id) { - super(context, cacheName, id, true); - } - public MusicDirectoryUpdater(Context context, String cacheName, String id, boolean singleUpdate) { - super(context, cacheName, id, singleUpdate); - } - - @Override - public ArrayList getArrayList() { - musicDirectory = FileUtil.deserialize(context, cacheName, MusicDirectory.class); - if(musicDirectory != null) { - return new ArrayList(musicDirectory.getChildren()); - } else { - return null; - } - } - public void save(ArrayList objects) { - musicDirectory.replaceChildren(objects); - FileUtil.serialize(context, musicDirectory, cacheName); - } - } - private abstract class PlaylistDirectoryUpdater { - Context context; - - public PlaylistDirectoryUpdater(Context context) { - this.context = context; - } - - public abstract boolean checkResult(Entry check); - public abstract void updateResult(Entry result); - - public void execute() { - List playlists = FileUtil.deserialize(context, getCacheName(context, "playlist"), ArrayList.class); - if(playlists == null) { - // No playlist list cache, nothing to update! - return; - } - - for(Playlist playlist: playlists) { - new MusicDirectoryUpdater(context, "playlist", playlist.getId(), false) { - @Override - public boolean checkResult(Entry check) { - return PlaylistDirectoryUpdater.this.checkResult(check); - } - - @Override - public void updateResult(List objects, Entry result) { - PlaylistDirectoryUpdater.this.updateResult(result); - } - }.execute(); - } - } - } - private abstract class GenericEntryUpdater { - Context context; - List entries; - - public GenericEntryUpdater(Context context, Entry entry) { - this.context = context; - this.entries = Arrays.asList(entry); - } - public GenericEntryUpdater(Context context, List entries) { - this.context = context; - this.entries = entries; - } - - public boolean checkResult(Entry entry, Entry check) { - return entry.getId().equals(check.getId()); - } - public abstract void updateResult(Entry result); - - public void execute() { - String cacheName, parent; - // Make sure it is up to date - isTagBrowsing = Util.isTagBrowsing(context, musicService.getInstance(context)); - - // Run through each entry, trying to update the directory it is in - final List songs = new ArrayList(); - for(final Entry entry: entries) { - if(isTagBrowsing) { - // If starring album, needs to reference artist instead - if(entry.isDirectory()) { - if(entry.isAlbum()) { - cacheName = "artist"; - parent = entry.getArtistId(); - } else { - cacheName = "artists"; - parent = null; - } - } else { - cacheName = "album"; - parent = entry.getAlbumId(); - } - } else { - if(entry.isDirectory() && !entry.isAlbum()) { - cacheName = "indexes"; - parent = null; - } else { - cacheName = "directory"; - parent = entry.getParent(); - } - } - - // Parent is only null when it is an artist - if(parent == null) { - new IndexesUpdater(context, cacheName) { - @Override - public boolean checkResult(Artist check) { - return GenericEntryUpdater.this.checkResult(entry, new Entry(check)); - } - - @Override - public void updateResult(List objects, Artist result) { - // Don't try to put anything here, as the Entry update method will not be called since it's a artist! - } - }.execute(); - } else { - new MusicDirectoryUpdater(context, cacheName, parent) { - @Override - public boolean checkResult(Entry check) { - return GenericEntryUpdater.this.checkResult(entry, check); - } - - @Override - public void updateResult(List objects, Entry result) { - GenericEntryUpdater.this.updateResult(result); - } - }.execute(); - } - - if(entry instanceof PodcastEpisode) { - new MusicDirectoryUpdater(context, cacheName, "p-" + entry.getParent()) { - @Override - public boolean checkResult(Entry check) { - return GenericEntryUpdater.this.checkResult(entry, check); - } - - @Override - public void updateResult(List objects, Entry result) { - GenericEntryUpdater.this.updateResult(result); - } - }.execute(); - } else if(!entry.isDirectory()) { - songs.add(entry); - } - } - - // Only run through playlists once and check each song against it - if(songs.size() > 0) { - new PlaylistDirectoryUpdater(context) { - @Override - public boolean checkResult(Entry check) { - for(Entry entry: songs) { - if(GenericEntryUpdater.this.checkResult(entry, check)) { - return true; - } - } - - return false; - } - - @Override - public void updateResult(Entry result) { - GenericEntryUpdater.this.updateResult(result); - } - }.execute(); - } - } - } - private class BookmarkUpdater extends GenericEntryUpdater { - public BookmarkUpdater(Context context, Entry entry) { - super(context, entry); - } - public BookmarkUpdater(Context context, List entries) { - super(context, entries); - } - - @Override - public boolean checkResult(Entry entry, Entry check) { - if(entry.getId().equals(check.getId())) { - int position; - if(entry.getBookmark() == null) { - position = -1; - } else { - position = entry.getBookmark().getPosition(); - } - - if(position == -1 && check.getBookmark() != null) { - check.setBookmark(null); - return true; - } else if(position >= 0 && (check.getBookmark() == null || check.getBookmark().getPosition() != position)) { - Bookmark bookmark = check.getBookmark(); - - // Create one if empty - if(bookmark == null) { - bookmark = new Bookmark(); - check.setBookmark(bookmark); - } - - // Update bookmark position no matter what - bookmark.setPosition(position); - return true; - } - } - - return false; - } - - @Override - public void updateResult(Entry result) { - - } - } - private class StarUpdater extends GenericEntryUpdater { - public StarUpdater(Context context, List entries) { - super(context, entries); - } - - @Override - public boolean checkResult(Entry entry, Entry check) { - if (entry.getId().equals(check.getId())) { - if(entry.isStarred() != check.isStarred()) { - check.setStarred(entry.isStarred()); - return true; - } - } - - return false; - } - - @Override - public void updateResult(Entry result) { - - } - }; - private abstract class IndexesUpdater extends SerializeUpdater { - Indexes indexes; - - IndexesUpdater(Context context, String name) { - super(context, name, Util.getSelectedMusicFolderId(context, musicService.getInstance(context))); - } - - @Override - public ArrayList getArrayList() { - indexes = FileUtil.deserialize(context, cacheName, Indexes.class); - if(indexes == null) { - return null; - } - - ArrayList artists = new ArrayList(); - artists.addAll(indexes.getArtists()); - artists.addAll(indexes.getShortcuts()); - return artists; - } - - public void save(ArrayList objects) { - indexes.setArtists(objects); - FileUtil.serialize(context, indexes, cacheName); - cachedIndexes.set(indexes); - } - } - - private void checkSettingsChanged(Context context) { - int instance = musicService.getInstance(context); - String newUrl = musicService.getRestUrl(context, null, false); - boolean newIsTagBrowsing = Util.isTagBrowsing(context, instance); - if (!Util.equals(newUrl, restUrl) || isTagBrowsing != newIsTagBrowsing) { - cachedMusicFolders.clear(); - cachedLicenseValid.clear(); - cachedIndexes.clear(); - cachedPlaylists.clear(); - cachedPodcastChannels.clear(); - restUrl = newUrl; - isTagBrowsing = newIsTagBrowsing; - } - - String newMusicFolderId = Util.getSelectedMusicFolderId(context, instance); - if(!Util.equals(newMusicFolderId, musicFolderId)) { - cachedIndexes.clear(); - musicFolderId = newMusicFolderId; - } - } - - public RESTMusicService getMusicService() { - return musicService; - } -} diff --git a/src/github/daneren2005/dsub/service/ChromeCastController.java b/src/github/daneren2005/dsub/service/ChromeCastController.java deleted file mode 100644 index a729ed4e..00000000 --- a/src/github/daneren2005/dsub/service/ChromeCastController.java +++ /dev/null @@ -1,522 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.service; - -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Bundle; -import android.util.Log; - -import com.google.android.gms.cast.ApplicationMetadata; -import com.google.android.gms.cast.Cast; -import com.google.android.gms.cast.CastDevice; -import com.google.android.gms.cast.MediaInfo; -import com.google.android.gms.cast.MediaMetadata; -import com.google.android.gms.cast.MediaStatus; -import com.google.android.gms.cast.RemoteMediaPlayer; -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.api.GoogleApiClient; -import com.google.android.gms.common.api.ResultCallback; -import com.google.android.gms.common.api.Status; -import com.google.android.gms.common.images.WebImage; - -import java.io.File; -import java.io.IOException; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.domain.RemoteControlState; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.util.compat.CastCompat; -import github.daneren2005.serverproxy.FileProxy; -import github.daneren2005.serverproxy.ServerProxy; -import github.daneren2005.serverproxy.WebProxy; - -/** - * Created by owner on 2/9/14. - */ -public class ChromeCastController extends RemoteController { - private static final String TAG = ChromeCastController.class.getSimpleName(); - - private CastDevice castDevice; - private GoogleApiClient apiClient; - - private boolean applicationStarted = false; - private boolean waitingForReconnect = false; - private boolean error = false; - private boolean ignoreNextPaused = false; - private String sessionId; - - private ServerProxy proxy; - private String rootLocation; - private RemoteMediaPlayer mediaPlayer; - private double gain = 0.5; - - public ChromeCastController(DownloadService downloadService, CastDevice castDevice) { - this.downloadService = downloadService; - this.castDevice = castDevice; - - SharedPreferences prefs = Util.getPreferences(downloadService); - rootLocation = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - } - - @Override - public void create(boolean playing, int seconds) { - downloadService.setPlayerState(PlayerState.PREPARING); - - ConnectionCallbacks connectionCallbacks = new ConnectionCallbacks(playing, seconds); - ConnectionFailedListener connectionFailedListener = new ConnectionFailedListener(); - Cast.Listener castClientListener = new Cast.Listener() { - @Override - public void onApplicationStatusChanged() { - if (apiClient != null && apiClient.isConnected()) { - Log.i(TAG, "onApplicationStatusChanged: " + Cast.CastApi.getApplicationStatus(apiClient)); - } - } - - @Override - public void onVolumeChanged() { - if (apiClient != null && applicationStarted) { - try { - gain = Cast.CastApi.getVolume(apiClient); - } catch (Exception e) { - Log.w(TAG, "Failed to get volume"); - } - } - } - - @Override - public void onApplicationDisconnected(int errorCode) { - shutdownInternal(); - } - - }; - - Cast.CastOptions.Builder apiOptionsBuilder = Cast.CastOptions.builder(castDevice, castClientListener).setVerboseLoggingEnabled(true); - apiClient = new GoogleApiClient.Builder(downloadService).useDefaultAccount() - .addApi(Cast.API, apiOptionsBuilder.build()) - .addConnectionCallbacks(connectionCallbacks) - .addOnConnectionFailedListener(connectionFailedListener) - .build(); - - apiClient.connect(); - } - - @Override - public void start() { - if(error) { - error = false; - Log.w(TAG, "Attempting to restart song"); - startSong(downloadService.getCurrentPlaying(), true, 0); - return; - } - - try { - mediaPlayer.play(apiClient); - } catch(Exception e) { - Log.e(TAG, "Failed to start"); - } - } - - @Override - public void stop() { - try { - mediaPlayer.pause(apiClient); - } catch(Exception e) { - Log.e(TAG, "Failed to pause"); - } - } - - @Override - public void shutdown() { - try { - if(mediaPlayer != null && !error) { - mediaPlayer.stop(apiClient); - } - } catch(Exception e) { - Log.e(TAG, "Failed to stop mediaPlayer", e); - } - - try { - if(apiClient != null) { - Cast.CastApi.stopApplication(apiClient); - Cast.CastApi.removeMessageReceivedCallbacks(apiClient, mediaPlayer.getNamespace()); - mediaPlayer = null; - applicationStarted = false; - } - } catch(Exception e) { - Log.e(TAG, "Failed to shutdown application", e); - } - - if(apiClient != null && apiClient.isConnected()) { - apiClient.disconnect(); - } - apiClient = null; - - if(proxy != null) { - proxy.stop(); - proxy = null; - } - } - - private void shutdownInternal() { - // This will call this.shutdown() indirectly - downloadService.setRemoteEnabled(RemoteControlState.LOCAL, null); - } - - @Override - public void updatePlaylist() { - if(downloadService.getCurrentPlaying() == null) { - startSong(null, false, 0); - } - } - - @Override - public void changePosition(int seconds) { - try { - mediaPlayer.seek(apiClient, seconds * 1000L); - } catch(Exception e) { - Log.e(TAG, "FAiled to seek to " + seconds); - } - } - - @Override - public void changeTrack(int index, DownloadFile song) { - startSong(song, true, 0); - } - - @Override - public void setVolume(int volume) { - gain = volume / 10.0; - - try { - Cast.CastApi.setVolume(apiClient, gain); - } catch(Exception e) { - Log.e(TAG, "Failed to the volume"); - } - } - @Override - public void updateVolume(boolean up) { - double delta = up ? 0.1 : -0.1; - gain += delta; - gain = Math.max(gain, 0.0); - gain = Math.min(gain, 1.0); - - try { - Cast.CastApi.setVolume(apiClient, gain); - } catch(Exception e) { - Log.e(TAG, "Failed to the volume"); - } - } - @Override - public double getVolume() { - return Cast.CastApi.getVolume(apiClient); - } - - @Override - public int getRemotePosition() { - if(mediaPlayer != null) { - return (int) (mediaPlayer.getApproximateStreamPosition() / 1000L); - } else { - return 0; - } - } - - @Override - public int getRemoteDuration() { - if(mediaPlayer != null) { - return (int) (mediaPlayer.getStreamDuration() / 1000L); - } else { - return 0; - } - } - - void startSong(DownloadFile currentPlaying, boolean autoStart, int position) { - if(currentPlaying == null) { - try { - if (mediaPlayer != null && !error) { - mediaPlayer.stop(apiClient); - } - } catch(Exception e) { - // Just means it didn't need to be stopped - } - downloadService.setPlayerState(PlayerState.IDLE); - return; - } - downloadService.setPlayerState(PlayerState.PREPARING); - MusicDirectory.Entry song = currentPlaying.getSong(); - - try { - MusicService musicService = MusicServiceFactory.getMusicService(downloadService); - String url; - // Offline, use file proxy - if(Util.isOffline(downloadService) || song.getId().indexOf(rootLocation) != -1) { - if(proxy == null) { - proxy = new FileProxy(downloadService); - proxy.start(); - } - - // Offline song - if(song.getId().indexOf(rootLocation) != -1) { - url = proxy.getPublicAddress(song.getId()); - } else { - // Playing online song in offline mode - url = proxy.getPublicAddress(currentPlaying.getCompleteFile().getPath()); - } - } else { - // Check if we want a proxy going still - if(Util.isCastProxy(downloadService)) { - if(proxy instanceof FileProxy) { - proxy.stop(); - proxy = null; - } - - if(proxy == null) { - proxy = createWebProxy(); - proxy.start(); - } - } else if(proxy != null) { - proxy.stop(); - proxy = null; - } - - if(song.isVideo()) { - url = musicService.getHlsUrl(song.getId(), currentPlaying.getBitRate(), downloadService); - } else { - url = musicService.getMusicUrl(downloadService, song, currentPlaying.getBitRate()); - } - - // If proxy is going, it is a WebProxy - if(proxy != null) { - url = proxy.getPublicAddress(url); - } - } - - // Setup song/video information - MediaMetadata meta = new MediaMetadata(song.isVideo() ? MediaMetadata.MEDIA_TYPE_MOVIE : MediaMetadata.MEDIA_TYPE_MUSIC_TRACK); - meta.putString(MediaMetadata.KEY_TITLE, song.getTitle()); - if(song.getTrack() != null) { - meta.putInt(MediaMetadata.KEY_TRACK_NUMBER, song.getTrack()); - } - if(!song.isVideo()) { - meta.putString(MediaMetadata.KEY_ARTIST, song.getArtist()); - meta.putString(MediaMetadata.KEY_ALBUM_ARTIST, song.getArtist()); - meta.putString(MediaMetadata.KEY_ALBUM_TITLE, song.getAlbum()); - - String coverArt = ""; - if(proxy == null || proxy instanceof WebProxy) { - coverArt = musicService.getCoverArtUrl(downloadService, song); - - // If proxy is going, it is a web proxy - if(proxy != null) { - coverArt = proxy.getPublicAddress(coverArt); - } - - meta.addImage(new WebImage(Uri.parse(coverArt))); - } else { - File coverArtFile = FileUtil.getAlbumArtFile(downloadService, song); - if(coverArtFile != null && coverArtFile.exists()) { - coverArt = proxy.getPublicAddress(coverArtFile.getPath()); - meta.addImage(new WebImage(Uri.parse(coverArt))); - } - } - } - - String contentType; - if(song.isVideo()) { - contentType = "application/x-mpegURL"; - } - else if(song.getTranscodedContentType() != null) { - contentType = song.getTranscodedContentType(); - } else if(song.getContentType() != null) { - contentType = song.getContentType(); - } else { - contentType = "audio/mpeg"; - } - - // Load it into a MediaInfo wrapper - MediaInfo mediaInfo = new MediaInfo.Builder(url) - .setContentType(contentType) - .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) - .setMetadata(meta) - .build(); - - if(autoStart) { - ignoreNextPaused = true; - } - - mediaPlayer.load(apiClient, mediaInfo, autoStart, position * 1000L).setResultCallback(new ResultCallback() { - @Override - public void onResult(RemoteMediaPlayer.MediaChannelResult result) { - if (result.getStatus().isSuccess()) { - // Handled in other handler - } else { - Log.e(TAG, "Failed to load: " + result.getStatus().toString()); - failedLoad(); - } - } - }); - } catch (IllegalStateException e) { - Log.e(TAG, "Problem occurred with media during loading", e); - failedLoad(); - } catch (Exception e) { - Log.e(TAG, "Problem opening media during loading", e); - failedLoad(); - } - } - - private void failedLoad() { - Util.toast(downloadService, downloadService.getResources().getString(R.string.download_failed_to_load)); - downloadService.setPlayerState(PlayerState.STOPPED); - error = true; - } - - - private class ConnectionCallbacks implements GoogleApiClient.ConnectionCallbacks { - private boolean isPlaying; - private int position; - private ResultCallback resultCallback; - - ConnectionCallbacks(boolean isPlaying, int position) { - this.isPlaying = isPlaying; - this.position = position; - - resultCallback = new ResultCallback() { - @Override - public void onResult(Cast.ApplicationConnectionResult result) { - Status status = result.getStatus(); - if (status.isSuccess()) { - ApplicationMetadata applicationMetadata = result.getApplicationMetadata(); - sessionId = result.getSessionId(); - String applicationStatus = result.getApplicationStatus(); - boolean wasLaunched = result.getWasLaunched(); - - applicationStarted = true; - setupChannel(); - } else { - shutdownInternal(); - } - } - }; - } - - @Override - public void onConnected(Bundle connectionHint) { - if (waitingForReconnect) { - Log.i(TAG, "Reconnecting"); - reconnectApplication(); - } else { - launchApplication(); - } - } - - @Override - public void onConnectionSuspended(int cause) { - Log.w(TAG, "Connection suspended"); - isPlaying = downloadService.getPlayerState() == PlayerState.STARTED; - position = getRemotePosition(); - waitingForReconnect = true; - } - - void launchApplication() { - try { - Cast.CastApi.launchApplication(apiClient, CastCompat.APPLICATION_ID, false).setResultCallback(resultCallback); - } catch (Exception e) { - Log.e(TAG, "Failed to launch application", e); - } - } - void reconnectApplication() { - try { - Cast.CastApi.joinApplication(apiClient, CastCompat.APPLICATION_ID, sessionId).setResultCallback(resultCallback); - } catch (Exception e) { - Log.e(TAG, "Failed to reconnect application", e); - } - } - void setupChannel() { - if(!waitingForReconnect) { - mediaPlayer = new RemoteMediaPlayer(); - mediaPlayer.setOnStatusUpdatedListener(new RemoteMediaPlayer.OnStatusUpdatedListener() { - @Override - public void onStatusUpdated() { - MediaStatus mediaStatus = mediaPlayer.getMediaStatus(); - if (mediaStatus == null) { - return; - } - - switch (mediaStatus.getPlayerState()) { - case MediaStatus.PLAYER_STATE_PLAYING: - if (ignoreNextPaused) { - ignoreNextPaused = false; - } - downloadService.setPlayerState(PlayerState.STARTED); - break; - case MediaStatus.PLAYER_STATE_PAUSED: - if (!ignoreNextPaused) { - downloadService.setPlayerState(PlayerState.PAUSED); - } - break; - case MediaStatus.PLAYER_STATE_BUFFERING: - downloadService.setPlayerState(PlayerState.PREPARING); - break; - case MediaStatus.PLAYER_STATE_IDLE: - if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_FINISHED) { - downloadService.setPlayerState(PlayerState.COMPLETED); - downloadService.postPlayCleanup(); - downloadService.onSongCompleted(); - } else if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_INTERRUPTED) { - if (downloadService.getPlayerState() != PlayerState.PREPARING) { - downloadService.setPlayerState(PlayerState.PREPARING); - } - } else if (mediaStatus.getIdleReason() == MediaStatus.IDLE_REASON_ERROR) { - Log.e(TAG, "Idle due to unknown error"); - downloadService.setPlayerState(PlayerState.COMPLETED); - downloadService.next(); - } else { - Log.w(TAG, "Idle reason: " + mediaStatus.getIdleReason()); - downloadService.setPlayerState(PlayerState.IDLE); - } - break; - } - } - }); - } - - try { - Cast.CastApi.setMessageReceivedCallbacks(apiClient, mediaPlayer.getNamespace(), mediaPlayer); - } catch (IOException e) { - Log.e(TAG, "Exception while creating channel", e); - } - - if(!waitingForReconnect) { - DownloadFile currentPlaying = downloadService.getCurrentPlaying(); - startSong(currentPlaying, isPlaying, position); - } - if(waitingForReconnect) { - waitingForReconnect = false; - } - } - } - - private class ConnectionFailedListener implements GoogleApiClient.OnConnectionFailedListener { - @Override - public void onConnectionFailed(ConnectionResult result) { - shutdownInternal(); - } - } -} diff --git a/src/github/daneren2005/dsub/service/DLNAController.java b/src/github/daneren2005/dsub/service/DLNAController.java deleted file mode 100644 index 036b111e..00000000 --- a/src/github/daneren2005/dsub/service/DLNAController.java +++ /dev/null @@ -1,687 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.service; - -import android.content.SharedPreferences; -import android.os.Looper; -import android.util.Log; - -import org.fourthline.cling.controlpoint.ActionCallback; -import org.fourthline.cling.controlpoint.ControlPoint; -import org.fourthline.cling.controlpoint.SubscriptionCallback; -import org.fourthline.cling.model.action.ActionInvocation; -import org.fourthline.cling.model.gena.CancelReason; -import org.fourthline.cling.model.gena.GENASubscription; -import org.fourthline.cling.model.message.UpnpResponse; -import org.fourthline.cling.model.meta.Action; -import org.fourthline.cling.model.meta.Service; -import org.fourthline.cling.model.meta.StateVariable; -import org.fourthline.cling.model.state.StateVariableValue; -import org.fourthline.cling.model.types.ServiceType; -import org.fourthline.cling.model.types.UnsignedIntegerFourBytes; -import org.fourthline.cling.support.avtransport.callback.GetPositionInfo; -import org.fourthline.cling.support.avtransport.callback.Pause; -import org.fourthline.cling.support.avtransport.callback.Play; -import org.fourthline.cling.support.avtransport.callback.Seek; -import org.fourthline.cling.support.avtransport.callback.SetAVTransportURI; -import org.fourthline.cling.support.avtransport.callback.Stop; -import org.fourthline.cling.support.avtransport.lastchange.AVTransportLastChangeParser; -import org.fourthline.cling.support.avtransport.lastchange.AVTransportVariable; -import org.fourthline.cling.support.contentdirectory.DIDLParser; -import org.fourthline.cling.support.lastchange.LastChange; -import org.fourthline.cling.support.model.DIDLContent; -import org.fourthline.cling.support.model.DIDLObject; -import org.fourthline.cling.support.model.PositionInfo; -import org.fourthline.cling.support.model.Res; -import org.fourthline.cling.support.model.SeekMode; -import org.fourthline.cling.support.model.item.Item; -import org.fourthline.cling.support.model.item.MusicTrack; -import org.fourthline.cling.support.model.item.VideoItem; -import org.fourthline.cling.support.renderingcontrol.callback.SetVolume; -import org.seamless.util.MimeType; - -import java.io.File; -import java.net.URI; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Map; -import java.util.TimeZone; -import java.util.concurrent.atomic.AtomicLong; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.DLNADevice; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Pair; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.serverproxy.FileProxy; -import github.daneren2005.serverproxy.ServerProxy; -import github.daneren2005.serverproxy.WebProxy; - -public class DLNAController extends RemoteController { - private static final String TAG = DLNAController.class.getSimpleName(); - private static final long SEARCH_UPDATE_INTERVAL_SECONDS = 10L * 60L * 1000L; - private static final long STATUS_UPDATE_INTERVAL_SECONDS = 3000L; - - DLNADevice device; - ControlPoint controlPoint; - SubscriptionCallback callback; - boolean supportsSeek = false; - boolean supportsSetupNext = false; - - private ServerProxy proxy; - String rootLocation = ""; - boolean error = false; - - final AtomicLong lastUpdate = new AtomicLong(); - int currentPosition = 0; - String currentPlayingURI; - String nextPlayingURI; - DownloadFile nextPlaying; - boolean running = true; - boolean hasDuration = false; - Runnable searchDLNA = new Runnable() { - @Override - public void run() { - if(controlPoint == null || !running) { - return; - } - - controlPoint.search(); - downloadService.postDelayed(searchDLNA, SEARCH_UPDATE_INTERVAL_SECONDS); - } - }; - - public DLNAController(DownloadService downloadService, ControlPoint controlPoint, DLNADevice device) { - this.downloadService = downloadService; - this.controlPoint = controlPoint; - this.device = device; - - SharedPreferences prefs = Util.getPreferences(downloadService); - rootLocation = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - nextSupported = true; - } - - @Override - public void create(final boolean playing, final int seconds) { - downloadService.setPlayerState(PlayerState.PREPARING); - - callback = new SubscriptionCallback(getTransportService(), 600) { - @Override - protected void failed(GENASubscription genaSubscription, UpnpResponse upnpResponse, Exception e, String msg) { - Log.w(TAG, "Register subscription callback failed: " + msg, e); - } - - @Override - protected void established(GENASubscription genaSubscription) { - Action seekAction = genaSubscription.getService().getAction("Seek"); - if(seekAction != null) { - StateVariable seekMode = genaSubscription.getService().getStateVariable("A_ARG_TYPE_SeekMode"); - for(String allowedValue: seekMode.getTypeDetails().getAllowedValues()) { - if("REL_TIME".equals(allowedValue)) { - supportsSeek = true; - } - } - } - Action setupNextAction = genaSubscription.getService().getAction("SetNextAVTransportURI"); - if(setupNextAction != null) { - supportsSetupNext = true; - } - - startSong(downloadService.getCurrentPlaying(), playing, seconds); - downloadService.postDelayed(searchDLNA, SEARCH_UPDATE_INTERVAL_SECONDS); - } - - @Override - protected void ended(GENASubscription genaSubscription, CancelReason cancelReason, UpnpResponse upnpResponse) { - Log.i(TAG, "Ended subscription"); - if(cancelReason != null) { - Log.i(TAG, "Cancel Reason: " + cancelReason.toString()); - } - if(upnpResponse != null) { - Log.i(TAG, "Reponse Message: " + upnpResponse.getStatusMessage()); - Log.i(TAG, "Response Details: " + upnpResponse.getResponseDetails()); - } - } - - @Override - protected void eventReceived(GENASubscription genaSubscription) { - Map m = genaSubscription.getCurrentValues(); - try { - LastChange lastChange = new LastChange(new AVTransportLastChangeParser(), m.get("LastChange").toString()); - if (lastChange.getEventedValue(0, AVTransportVariable.TransportState.class) == null) { - return; - } - - switch (lastChange.getEventedValue(0, AVTransportVariable.TransportState.class).getValue()) { - case PLAYING: - downloadService.setPlayerState(PlayerState.STARTED); - - // Try to setup next playing after playback start has been registered - if(supportsSetupNext && downloadService.getNextPlayerState() == PlayerState.IDLE) { - downloadService.setNextPlaying(); - } - break; - case PAUSED_PLAYBACK: - downloadService.setPlayerState(PlayerState.PAUSED); - break; - case STOPPED: - boolean failed = false; - for(StateVariableValue val: m.values()) { - if(val.toString().indexOf("TransportStatus val=\"ERROR_OCCURRED\"") != -1) { - Log.w(TAG, "Failed to load with event: " + val.toString()); - failed = true; - } - } - - if(failed) { - failedLoad(); - } else if(downloadService.getPlayerState() == PlayerState.STARTED) { - // Played until the end - downloadService.setPlayerState(PlayerState.COMPLETED); - downloadService.postPlayCleanup(); - downloadService.onSongCompleted(); - } else { - downloadService.setPlayerState(PlayerState.STOPPED); - } - break; - case TRANSITIONING: - downloadService.setPlayerState(PlayerState.PREPARING); - break; - case NO_MEDIA_PRESENT: - downloadService.setPlayerState(PlayerState.IDLE); - break; - default: - } - } - catch (Exception e) { - Log.w(TAG, "Failed to parse UPNP event", e); - failedLoad(); - } - } - - @Override - protected void eventsMissed(GENASubscription genaSubscription, int i) { - Log.w(TAG, "Event missed: " + i); - } - }; - controlPoint.execute(callback); - } - - @Override - public void start() { - if(error) { - Log.w(TAG, "Attempting to restart song"); - startSong(downloadService.getCurrentPlaying(), true, 0); - return; - } - - try { - controlPoint.execute(new Play(getTransportService()) { - @Override - public void success(ActionInvocation invocation) { - lastUpdate.set(System.currentTimeMillis()); - downloadService.setPlayerState(PlayerState.STARTED); - } - - @Override - public void failure(ActionInvocation actionInvocation, UpnpResponse upnpResponse, String msg) { - Log.w(TAG, "Failed to start playing: " + msg); - failedLoad(); - } - }); - } catch(Exception e) { - Log.w(TAG, "Failed to start", e); - } - } - - @Override - public void stop() { - try { - controlPoint.execute(new Pause(getTransportService()) { - @Override - public void success(ActionInvocation invocation) { - int secondsSinceLastUpdate = (int) ((System.currentTimeMillis() - lastUpdate.get()) / 1000L); - currentPosition += secondsSinceLastUpdate; - - downloadService.setPlayerState(PlayerState.PAUSED); - } - - @Override - public void failure(ActionInvocation actionInvocation, UpnpResponse upnpResponse, String msg) { - Log.w(TAG, "Failed to pause playing: " + msg); - } - }); - } catch(Exception e) { - Log.w(TAG, "Failed to stop", e); - } - } - - @Override - public void shutdown() { - try { - controlPoint.execute(new Stop(getTransportService()) { - @Override - public void failure(ActionInvocation invocation, org.fourthline.cling.model.message.UpnpResponse operation, String defaultMessage) { - Log.w(TAG, "Stop failed: " + defaultMessage); - } - }); - } catch(Exception e) { - Log.w(TAG, "Failed to shutdown", e); - } - - if(callback != null) { - callback.end(); - callback = null; - } - - if(proxy != null) { - proxy.stop(); - proxy = null; - } - - running = false; - } - - @Override - public void updatePlaylist() { - if(downloadService.getCurrentPlaying() == null) { - startSong(null, false, 0); - } - } - - @Override - public void changePosition(int seconds) { - SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); - controlPoint.execute(new Seek(getTransportService(), SeekMode.REL_TIME, df.format(new Date(seconds * 1000))) { - @SuppressWarnings("rawtypes") - @Override - public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMessage) { - Log.w(TAG, "Seek failed: " + defaultMessage); - } - }); - } - - @Override - public void changeTrack(int index, DownloadFile song) { - startSong(song, true, 0); - } - - @Override - public void changeNextTrack(DownloadFile song) { - setupNextSong(song); - } - - @Override - public void setVolume(int volume) { - if(volume < 0) { - volume = 0; - } else if(volume > device.volumeMax) { - volume = device.volumeMax; - } - - device.volume = volume; - try { - controlPoint.execute(new SetVolume(device.renderer.findService(new ServiceType("schemas-upnp-org", "RenderingControl")), volume) { - @SuppressWarnings("rawtypes") - @Override - public void failure(ActionInvocation invocation, UpnpResponse operation, String defaultMessage) { - Log.w(TAG, "Set volume failed: " + defaultMessage); - } - }); - } catch(Exception e) { - Log.w(TAG, "Failed to set volume"); - } - } - - @Override - public void updateVolume(boolean up) { - int increment = device.volumeMax / 10; - setVolume(device.volume + (up ? increment : -increment)); - } - - @Override - public double getVolume() { - return device.volume; - } - - @Override - public int getRemotePosition() { - if(downloadService.getPlayerState() == PlayerState.STARTED) { - int secondsSinceLastUpdate = (int) ((System.currentTimeMillis() - lastUpdate.get()) / 1000L); - return currentPosition + secondsSinceLastUpdate; - } else { - return currentPosition; - } - } - - @Override - public boolean isSeekable() { - return supportsSeek && hasDuration; - } - - private void startSong(final DownloadFile currentPlaying, final boolean autoStart, final int position) { - try { - controlPoint.execute(new Stop(getTransportService()) { - @Override - public void success(ActionInvocation invocation) { - startSongRemote(currentPlaying, autoStart, position); - } - - @Override - public void failure(ActionInvocation invocation, org.fourthline.cling.model.message.UpnpResponse operation, String defaultMessage) { - Log.w(TAG, "Stop failed before startSong: " + defaultMessage); - startSongRemote(currentPlaying, autoStart, position); - } - }); - } catch(Exception e) { - Log.w(TAG, "Failed to stop before startSong", e); - startSongRemote(currentPlaying, autoStart, position); - } - } - private void startSongRemote(final DownloadFile currentPlaying, final boolean autoStart, final int position) { - if(currentPlaying == null) { - downloadService.setPlayerState(PlayerState.IDLE); - return; - } - error = false; - - downloadService.setPlayerState(PlayerState.PREPARING); - - try { - Pair songInfo = getSongInfo(currentPlaying); - - currentPlayingURI = songInfo.getFirst(); - downloadService.setNextPlayerState(PlayerState.IDLE); - controlPoint.execute(new SetAVTransportURI(getTransportService(), songInfo.getFirst(), songInfo.getSecond()) { - @Override - public void success(ActionInvocation invocation) { - if(position != 0) { - changePosition(position); - } - - if (autoStart) { - start(); - } else { - downloadService.setPlayerState(PlayerState.PAUSED); - } - - currentPosition = position; - lastUpdate.set(System.currentTimeMillis()); - getUpdatedStatus(); - } - - @Override - public void failure(ActionInvocation actionInvocation, UpnpResponse upnpResponse, String msg) { - Log.w(TAG, "Set URI failed: " + msg); - failedLoad(); - } - }); - } catch (Exception e) { - Log.w(TAG, "Failed startSong", e); - failedLoad(); - } - } - private void setupNextSong(final DownloadFile nextPlaying) { - this.nextPlaying = nextPlaying; - nextPlayingURI = null; - if(nextPlaying == null) { - downloadService.setNextPlayerState(PlayerState.IDLE); - Log.i(TAG, "Nothing to play next"); - return; - } - - downloadService.setNextPlayerState(PlayerState.PREPARING); - try { - Pair songInfo = getSongInfo(nextPlaying); - - nextPlayingURI = songInfo.getFirst(); - controlPoint.execute(new SetNextAVTransportURI(getTransportService(), songInfo.getFirst(), songInfo.getSecond()) { - @Override - public void success(ActionInvocation invocation) { - downloadService.setNextPlayerState(PlayerState.PREPARED); - } - - @Override - public void failure(ActionInvocation actionInvocation, UpnpResponse upnpResponse, String msg) { - Log.w(TAG, "Set next URI failed: " + msg); - nextPlayingURI = null; - DLNAController.this.nextPlaying = null; - downloadService.setNextPlayerState(PlayerState.IDLE); - } - }); - } catch (Exception e) { - Log.w(TAG, "Failed to setup next song", e); - nextPlayingURI = null; - this.nextPlaying = null; - downloadService.setNextPlayerState(PlayerState.IDLE); - } - } - - Pair getSongInfo(final DownloadFile downloadFile) throws Exception { - MusicDirectory.Entry song = downloadFile.getSong(); - - // Get url for entry - MusicService musicService = MusicServiceFactory.getMusicService(downloadService); - String url; - // In offline mode or playing offline song - if(Util.isOffline(downloadService) || song.getId().indexOf(rootLocation) != -1) { - if(proxy == null) { - proxy = new FileProxy(downloadService); - proxy.start(); - } - - // Offline song - if(song.getId().indexOf(rootLocation) != -1) { - url = proxy.getPublicAddress(song.getId()); - } else { - // Playing online song in offline mode - url = proxy.getPublicAddress(downloadFile.getCompleteFile().getPath()); - } - } else { - // Check if we want a proxy going still - if(Util.isCastProxy(downloadService)) { - if(proxy instanceof FileProxy) { - proxy.stop(); - proxy = null; - } - - if(proxy == null) { - proxy = createWebProxy(); - proxy.start(); - } - } else if(proxy != null) { - proxy.stop(); - proxy = null; - } - - if(song.isVideo()) { - url = musicService.getHlsUrl(song.getId(), downloadFile.getBitRate(), downloadService); - } else { - url = musicService.getMusicUrl(downloadService, song, downloadFile.getBitRate()); - } - - // If proxy is going, it is a WebProxy - if(proxy != null) { - url = proxy.getPublicAddress(url); - } - } - - // Create metadata for entry - Item track; - if(song.isVideo()) { - track = new VideoItem(song.getId(), song.getParent(), song.getTitle(), song.getArtist()); - } else { - String contentType = null; - if(song.getTranscodedContentType() != null) { - contentType = song.getTranscodedContentType(); - } else if(song.getContentType() != null) { - contentType = song.getContentType(); - } - - MimeType mimeType; - // If we can parse the content type, use it instead of hard coding - if(contentType != null && contentType.indexOf("/") != -1 && contentType.indexOf("/") != (contentType.length() - 1)) { - String[] typeParts = contentType.split("/"); - mimeType = new MimeType(typeParts[0], typeParts[1]); - } else { - mimeType = new MimeType("audio", "mpeg"); - } - - Res res = new Res(mimeType, song.getSize(), url); - - if(song.getDuration() != null) { - SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss"); - df.setTimeZone(TimeZone.getTimeZone("UTC")); - res.setDuration(df.format(new Date(song.getDuration() * 1000))); - } - - MusicTrack musicTrack = new MusicTrack(song.getId(), song.getParent(), song.getTitle(), song.getArtist(), song.getAlbum(), song.getArtist(), res); - musicTrack.setOriginalTrackNumber(song.getTrack()); - - if(song.getCoverArt() != null) { - String coverArt = null; - if(proxy == null || proxy instanceof WebProxy) { - coverArt = musicService.getCoverArtUrl(downloadService, song); - - // If proxy is going, it is a web proxy - if(proxy != null) { - coverArt = proxy.getPublicAddress(coverArt); - } - } else { - File coverArtFile = FileUtil.getAlbumArtFile(downloadService, song); - if(coverArtFile != null && coverArtFile.exists()) { - coverArt = proxy.getPublicAddress(coverArtFile.getPath()); - } - } - - if(coverArt != null) { - DIDLObject.Property.UPNP.ALBUM_ART_URI albumArtUri = new DIDLObject.Property.UPNP.ALBUM_ART_URI(URI.create(coverArt)); - musicTrack.addProperty(albumArtUri); - } - } - - track = musicTrack; - } - - DIDLParser parser = new DIDLParser(); - DIDLContent didl = new DIDLContent(); - didl.addItem(track); - - String metadata = ""; - try { - metadata = parser.generate(didl); - } catch(Exception e) { - Log.w(TAG, "Metadata generation failed", e); - } - - return new Pair(url, metadata); - } - - private void failedLoad() { - downloadService.setPlayerState(PlayerState.STOPPED); - error = true; - - if(Looper.myLooper() != Looper.getMainLooper()) { - downloadService.post(new Runnable() { - @Override - public void run() { - Util.toast(downloadService, downloadService.getResources().getString(R.string.download_failed_to_load)); - } - }); - } else { - Util.toast(downloadService, downloadService.getResources().getString(R.string.download_failed_to_load)); - } - } - - private Service getTransportService() { - return device.renderer.findService(new ServiceType("schemas-upnp-org", "AVTransport")); - } - - private void getUpdatedStatus() { - // Don't care if shutdown in the meantime - if(!running) { - return; - } - - controlPoint.execute(new GetPositionInfo(getTransportService()) { - @Override - public void received(ActionInvocation actionInvocation, PositionInfo positionInfo) { - // Don't care if shutdown in the meantime - if(!running) { - return; - } - - long duration = positionInfo.getTrackDurationSeconds(); - hasDuration = duration > 0; - - lastUpdate.set(System.currentTimeMillis()); - - // Let's get the updated position - currentPosition = (int) positionInfo.getTrackElapsedSeconds(); - - if(positionInfo.getTrackURI() != null && positionInfo.getTrackURI().equals(nextPlayingURI) && downloadService.getNextPlayerState() == PlayerState.PREPARED) { - downloadService.setCurrentPlaying(nextPlaying, true); - downloadService.setPlayerState(PlayerState.STARTED); - downloadService.setNextPlaying(); - } - - downloadService.postDelayed(new Runnable() { - @Override - public void run() { - getUpdatedStatus(); - } - }, STATUS_UPDATE_INTERVAL_SECONDS); - } - - @Override - public void failure(ActionInvocation actionInvocation, UpnpResponse upnpResponse, String s) { - Log.w(TAG, "Failed to get an update"); - - downloadService.postDelayed(new Runnable() { - @Override - public void run() { - getUpdatedStatus(); - } - }, STATUS_UPDATE_INTERVAL_SECONDS); - } - }); - } - - private abstract class SetNextAVTransportURI extends ActionCallback { - public SetNextAVTransportURI(Service service, String uri) { - this(new UnsignedIntegerFourBytes(0), service, uri, null); - } - - public SetNextAVTransportURI(Service service, String uri, String metadata) { - this(new UnsignedIntegerFourBytes(0), service, uri, metadata); - } - - public SetNextAVTransportURI(UnsignedIntegerFourBytes instanceId, Service service, String uri) { - this(instanceId, service, uri, null); - } - - public SetNextAVTransportURI(UnsignedIntegerFourBytes instanceId, Service service, String uri, String metadata) { - super(new ActionInvocation(service.getAction("SetNextAVTransportURI"))); - getActionInvocation().setInput("InstanceID", instanceId); - getActionInvocation().setInput("NextURI", uri); - getActionInvocation().setInput("NextURIMetaData", metadata); - } - } -} diff --git a/src/github/daneren2005/dsub/service/DownloadFile.java b/src/github/daneren2005/dsub/service/DownloadFile.java deleted file mode 100644 index 505e4a6d..00000000 --- a/src/github/daneren2005/dsub/service/DownloadFile.java +++ /dev/null @@ -1,607 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.OutputStream; - -import android.content.Context; -import android.net.wifi.WifiManager; -import android.os.PowerManager; -import android.util.Log; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.util.CacheCleaner; -import github.daneren2005.serverproxy.BufferFile; - -import org.apache.http.Header; - -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public class DownloadFile implements BufferFile { - private static final String TAG = DownloadFile.class.getSimpleName(); - private static final int MAX_FAILURES = 5; - private final Context context; - private final MusicDirectory.Entry song; - private final File partialFile; - private final File completeFile; - private final File saveFile; - - private final MediaStoreService mediaStoreService; - private DownloadTask downloadTask; - private boolean save; - private boolean failedDownload = false; - private int failed = 0; - private int bitRate; - private boolean isPlaying = false; - private boolean saveWhenDone = false; - private boolean completeWhenDone = false; - private Long contentLength = null; - private long currentSpeed = 0; - private boolean rateLimit = false; - - public DownloadFile(Context context, MusicDirectory.Entry song, boolean save) { - this.context = context; - this.song = song; - this.save = save; - saveFile = FileUtil.getSongFile(context, song); - bitRate = getActualBitrate(); - partialFile = new File(saveFile.getParent(), FileUtil.getBaseName(saveFile.getName()) + - ".partial." + FileUtil.getExtension(saveFile.getName())); - completeFile = new File(saveFile.getParent(), FileUtil.getBaseName(saveFile.getName()) + - ".complete." + FileUtil.getExtension(saveFile.getName())); - mediaStoreService = new MediaStoreService(context); - } - - public MusicDirectory.Entry getSong() { - return song; - } - - /** - * Returns the effective bit rate. - */ - public int getBitRate() { - if(!partialFile.exists()) { - bitRate = getActualBitrate(); - } - if (bitRate > 0) { - return bitRate; - } - return song.getBitRate() == null ? 160 : song.getBitRate(); - } - private int getActualBitrate() { - int br = song.isVideo() ? Util.getMaxVideoBitrate(context) : Util.getMaxBitrate(context); - if(br == 0 && song.getTranscodedSuffix() != null && "mp3".equals(song.getTranscodedSuffix().toLowerCase())) { - if(song.getBitRate() != null) { - br = Math.min(320, song.getBitRate()); - } else { - br = 320; - } - } else if(song.getSuffix() != null && (song.getTranscodedSuffix() == null || song.getSuffix().equals(song.getTranscodedSuffix()))) { - // If just downsampling, don't try to upsample (ie: 128 kpbs -> 192 kpbs) - if(song.getBitRate() != null && br > song.getBitRate()) { - br = song.getBitRate(); - } - } - - return br; - } - - public Long getContentLength() { - return contentLength; - } - - public long getCurrentSize() { - if(partialFile.exists()) { - return partialFile.length(); - } else { - File file = getCompleteFile(); - if(file.exists()) { - return file.length(); - } else { - return 0L; - } - } - } - - @Override - public long getEstimatedSize() { - if(contentLength != null) { - return contentLength; - } - - File file = getCompleteFile(); - if(file.exists()) { - return file.length(); - } else if(song.getDuration() == null) { - return 0; - } else { - int br = (getBitRate() * 1000) / 8; - int duration = song.getDuration(); - return br * duration; - } - } - - public long getBytesPerSecond() { - return currentSpeed; - } - - public synchronized void download() { - rateLimit = false; - preDownload(); - downloadTask.execute(); - } - public synchronized void downloadNow(MusicService musicService) { - rateLimit = true; - preDownload(); - downloadTask.setMusicService(musicService); - try { - downloadTask.doInBackground(); - } catch(InterruptedException e) { - // This should never be reached - } - } - private void preDownload() { - FileUtil.createDirectoryForParent(saveFile); - failedDownload = false; - if(!partialFile.exists()) { - bitRate = getActualBitrate(); - } - downloadTask = new DownloadTask(context); - } - - public synchronized void cancelDownload() { - if (downloadTask != null) { - downloadTask.cancel(); - } - } - - @Override - public File getFile() { - if (saveFile.exists()) { - return saveFile; - } else if (completeFile.exists()) { - return completeFile; - } else { - return partialFile; - } - } - - public File getCompleteFile() { - if (saveFile.exists()) { - return saveFile; - } - - if (completeFile.exists()) { - return completeFile; - } - - return saveFile; - } - - public File getPartialFile() { - return partialFile; - } - - public boolean isSaved() { - return saveFile.exists(); - } - - public synchronized boolean isCompleteFileAvailable() { - return saveFile.exists() || completeFile.exists(); - } - - @Override - public synchronized boolean isWorkDone() { - return saveFile.exists() || (completeFile.exists() && !save) || saveWhenDone || completeWhenDone; - } - - @Override - public void onStart() { - setPlaying(true); - } - - @Override - public void onStop() { - setPlaying(false); - } - - @Override - public synchronized void onResume() { - if(!isWorkDone() && !isFailedMax() && !isDownloading() && !isDownloadCancelled()) { - download(); - } - } - - public synchronized boolean isDownloading() { - return downloadTask != null && downloadTask.isRunning(); - } - - public synchronized boolean isDownloadCancelled() { - return downloadTask != null && downloadTask.isCancelled(); - } - - public boolean shouldSave() { - return save; - } - - public boolean isFailed() { - return failedDownload; - } - public boolean isFailedMax() { - return failed > MAX_FAILURES; - } - - public void delete() { - cancelDownload(); - - // Remove from mediaStore BEFORE deleting file since it calls getCompleteFile - deleteFromStore(); - - // Delete all possible versions of the file - File parent = partialFile.getParentFile(); - Util.delete(partialFile); - Util.delete(completeFile); - Util.delete(saveFile); - FileUtil.deleteEmptyDir(parent); - } - - public void unpin() { - if (saveFile.exists()) { - // Delete old store entry before renaming to pinned file - saveFile.renameTo(completeFile); - renameInStore(saveFile, completeFile); - } - } - - public boolean cleanup() { - boolean ok = true; - if (completeFile.exists() || saveFile.exists()) { - ok = Util.delete(partialFile); - } - if (saveFile.exists()) { - ok &= Util.delete(completeFile); - } - return ok; - } - - // In support of LRU caching. - public void updateModificationDate() { - updateModificationDate(saveFile); - updateModificationDate(partialFile); - updateModificationDate(completeFile); - } - - private void updateModificationDate(File file) { - if (file.exists()) { - boolean ok = file.setLastModified(System.currentTimeMillis()); - if (!ok) { - Log.w(TAG, "Failed to set last-modified date on " + file); - } - } - } - - public void setPlaying(boolean isPlaying) { - try { - if(saveWhenDone && !isPlaying) { - Util.renameFile(completeFile, saveFile); - renameInStore(completeFile, saveFile); - saveWhenDone = false; - } else if(completeWhenDone && !isPlaying) { - if(save) { - Util.renameFile(partialFile, saveFile); - saveToStore(); - } else { - Util.renameFile(partialFile, completeFile); - saveToStore(); - } - completeWhenDone = false; - } - } catch(IOException ex) { - Log.w(TAG, "Failed to rename file " + completeFile + " to " + saveFile, ex); - } - - this.isPlaying = isPlaying; - } - public void renamePartial() { - try { - Util.renameFile(partialFile, completeFile); - saveToStore(); - } catch(IOException ex) { - Log.w(TAG, "Failed to rename file " + partialFile + " to " + completeFile, ex); - } - } - public boolean getPlaying() { - return isPlaying; - } - - private void deleteFromStore() { - try { - mediaStoreService.deleteFromMediaStore(this); - } catch(Exception e) { - Log.w(TAG, "Failed to remove from store", e); - } - } - private void saveToStore() { - if(!Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_HIDE_MEDIA, false)) { - try { - mediaStoreService.saveInMediaStore(this); - } catch(Exception e) { - Log.w(TAG, "Failed to save in media store", e); - } - } - } - private void renameInStore(File start, File end) { - try { - mediaStoreService.renameInMediaStore(start, end); - } catch(Exception e) { - Log.w(TAG, "Failed to rename in store", e); - } - } - - @Override - public String toString() { - return "DownloadFile (" + song + ")"; - } - - private class DownloadTask extends SilentBackgroundTask { - private MusicService musicService; - - public DownloadTask(Context context) { - super(context); - } - - @Override - public Void doInBackground() throws InterruptedException { - InputStream in = null; - FileOutputStream out = null; - PowerManager.WakeLock wakeLock = null; - WifiManager.WifiLock wifiLock = null; - try { - - if (Util.isScreenLitOnDownload(context)) { - PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, toString()); - wakeLock.acquire(); - } - - wifiLock = Util.createWifiLock(context, toString()); - wifiLock.acquire(); - - if (saveFile.exists()) { - Log.i(TAG, saveFile + " already exists. Skipping."); - checkDownloads(); - return null; - } - if (completeFile.exists()) { - if (save) { - if(isPlaying) { - saveWhenDone = true; - } else { - Util.renameFile(completeFile, saveFile); - renameInStore(completeFile, saveFile); - } - } else { - Log.i(TAG, completeFile + " already exists. Skipping."); - } - checkDownloads(); - return null; - } - - if(musicService == null) { - musicService = MusicServiceFactory.getMusicService(context); - } - - // Some devices seem to throw error on partial file which doesn't exist - boolean compare; - try { - compare = (bitRate == 0) || (song.getDuration() == 0) || (partialFile.length() == 0) || (bitRate * song.getDuration() * 1000 / 8) > partialFile.length(); - } catch(Exception e) { - compare = true; - } - if(compare) { - // Attempt partial HTTP GET, appending to the file if it exists. - HttpResponse response = musicService.getDownloadInputStream(context, song, partialFile.length(), bitRate, DownloadTask.this); - Header contentLengthHeader = response.getFirstHeader("Content-Length"); - if(contentLengthHeader != null) { - String contentLengthString = contentLengthHeader.getValue(); - if(contentLengthString != null) { - Log.i(TAG, "Content Length: " + contentLengthString); - contentLength = Long.parseLong(contentLengthString); - } - } - in = response.getEntity().getContent(); - boolean partial = response.getStatusLine().getStatusCode() == HttpStatus.SC_PARTIAL_CONTENT; - if (partial) { - Log.i(TAG, "Executed partial HTTP GET, skipping " + partialFile.length() + " bytes"); - } - - out = new FileOutputStream(partialFile, partial); - long n = copy(in, out); - Log.i(TAG, "Downloaded " + n + " bytes to " + partialFile); - out.flush(); - out.close(); - - if (isCancelled()) { - throw new Exception("Download of '" + song + "' was cancelled"); - } else if(partialFile.length() == 0) { - throw new Exception("Download of '" + song + "' failed. File is 0 bytes long."); - } - - downloadAndSaveCoverArt(musicService); - } - - if(isPlaying) { - completeWhenDone = true; - } else { - if(save) { - Util.renameFile(partialFile, saveFile); - } else { - Util.renameFile(partialFile, completeFile); - } - DownloadFile.this.saveToStore(); - } - - } catch(InterruptedException x) { - throw x; - } catch(FileNotFoundException x) { - Util.delete(completeFile); - Util.delete(saveFile); - if(!isCancelled()) { - failed = MAX_FAILURES + 1; - failedDownload = true; - Log.w(TAG, "Failed to download '" + song + "'.", x); - } - } catch(IOException x) { - Util.delete(completeFile); - Util.delete(saveFile); - if(!isCancelled()) { - failedDownload = true; - Log.w(TAG, "Failed to download '" + song + "'.", x); - } - } catch (Exception x) { - Util.delete(completeFile); - Util.delete(saveFile); - if (!isCancelled()) { - failed++; - failedDownload = true; - Log.w(TAG, "Failed to download '" + song + "'.", x); - } - } finally { - Util.close(in); - Util.close(out); - if (wakeLock != null) { - wakeLock.release(); - Log.i(TAG, "Released wake lock " + wakeLock); - } - if (wifiLock != null) { - wifiLock.release(); - } - } - - // Only run these if not interrupted, ie: cancelled - if(!isCancelled()) { - new CacheCleaner(context, DownloadService.getInstance()).cleanSpace(); - checkDownloads(); - } - - return null; - } - - private void checkDownloads() { - DownloadService downloadService = DownloadService.getInstance(); - if(downloadService != null) { - downloadService.checkDownloads(); - } - } - - @Override - public String toString() { - return "DownloadTask (" + song + ")"; - } - - public void setMusicService(MusicService musicService) { - this.musicService = musicService; - } - - private void downloadAndSaveCoverArt(MusicService musicService) throws Exception { - try { - if (song.getCoverArt() != null) { - // Check if album art already exists, don't want to needlessly load into memory - File albumArtFile = FileUtil.getAlbumArtFile(context, song); - if(!albumArtFile.exists()) { - musicService.getCoverArt(context, song, 0, null, null); - } - } - } catch (Exception x) { - Log.e(TAG, "Failed to get cover art.", x); - } - } - - private long copy(final InputStream in, OutputStream out) throws IOException, InterruptedException { - - // Start a thread that will close the input stream if the task is - // cancelled, thus causing the copy() method to return. - new Thread("DownloadFile_copy") { - @Override - public void run() { - while (true) { - Util.sleepQuietly(3000L); - if (isCancelled()) { - Util.close(in); - return; - } - if (!isRunning()) { - return; - } - } - } - }.start(); - - byte[] buffer = new byte[1024 * 16]; - long count = 0; - int n; - long lastLog = System.currentTimeMillis(); - long lastCount = 0; - - boolean activeLimit = rateLimit; - while (!isCancelled() && (n = in.read(buffer)) != -1) { - out.write(buffer, 0, n); - count += n; - lastCount += n; - - long now = System.currentTimeMillis(); - if (now - lastLog > 3000L) { // Only every so often. - Log.i(TAG, "Downloaded " + Util.formatBytes(count) + " of " + song); - currentSpeed = lastCount / ((now - lastLog) / 1000L); - lastLog = now; - lastCount = 0; - - // Re-establish every few seconds whether screen is on or not - if(rateLimit) { - PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); - if(pm.isScreenOn()) { - activeLimit = true; - } else { - activeLimit = false; - } - } - } - - // If screen is on and rateLimit is true, stop downloading from exhausting bandwidth - if(activeLimit) { - Thread.sleep(10L); - } - } - return count; - } - } -} diff --git a/src/github/daneren2005/dsub/service/DownloadService.java b/src/github/daneren2005/dsub/service/DownloadService.java deleted file mode 100644 index 3f1c022c..00000000 --- a/src/github/daneren2005/dsub/service/DownloadService.java +++ /dev/null @@ -1,2410 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -import static android.support.v7.media.MediaRouter.RouteInfo; -import static github.daneren2005.dsub.domain.PlayerState.COMPLETED; -import static github.daneren2005.dsub.domain.PlayerState.DOWNLOADING; -import static github.daneren2005.dsub.domain.PlayerState.IDLE; -import static github.daneren2005.dsub.domain.PlayerState.PAUSED; -import static github.daneren2005.dsub.domain.PlayerState.PAUSED_TEMP; -import static github.daneren2005.dsub.domain.PlayerState.PREPARED; -import static github.daneren2005.dsub.domain.PlayerState.PREPARING; -import static github.daneren2005.dsub.domain.PlayerState.STARTED; -import static github.daneren2005.dsub.domain.PlayerState.STOPPED; -import static github.daneren2005.dsub.domain.RemoteControlState.LOCAL; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.audiofx.AudioEffectsController; -import github.daneren2005.dsub.audiofx.EqualizerController; -import github.daneren2005.dsub.domain.Bookmark; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.domain.RemoteControlState; -import github.daneren2005.dsub.domain.RepeatMode; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.receiver.MediaButtonIntentReceiver; -import github.daneren2005.dsub.util.ArtistRadioBuffer; -import github.daneren2005.dsub.util.Notifications; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.MediaRouteManager; -import github.daneren2005.dsub.util.ShufflePlayBuffer; -import github.daneren2005.dsub.util.SimpleServiceBinder; -import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.util.compat.RemoteControlClientHelper; -import github.daneren2005.dsub.util.tags.BastpUtil; -import github.daneren2005.dsub.view.UpdateView; -import github.daneren2005.serverproxy.BufferProxy; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -import android.annotation.TargetApi; -import android.app.Service; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.media.audiofx.AudioEffect; -import android.os.Build; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.PowerManager; -import android.support.v7.media.MediaRouteSelector; -import android.support.v7.media.MediaRouter; -import android.util.Log; -import android.support.v4.util.LruCache; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public class DownloadService extends Service { - private static final String TAG = DownloadService.class.getSimpleName(); - - public static final String CMD_PLAY = "github.daneren2005.dsub.CMD_PLAY"; - public static final String CMD_TOGGLEPAUSE = "github.daneren2005.dsub.CMD_TOGGLEPAUSE"; - public static final String CMD_PAUSE = "github.daneren2005.dsub.CMD_PAUSE"; - public static final String CMD_STOP = "github.daneren2005.dsub.CMD_STOP"; - public static final String CMD_PREVIOUS = "github.daneren2005.dsub.CMD_PREVIOUS"; - public static final String CMD_NEXT = "github.daneren2005.dsub.CMD_NEXT"; - public static final String CANCEL_DOWNLOADS = "github.daneren2005.dsub.CANCEL_DOWNLOADS"; - public static final String START_PLAY = "github.daneren2005.dsub.START_PLAYING"; - public static final int FAST_FORWARD = 30000; - public static final int REWIND = 10000; - private static final double DELETE_CUTOFF = 0.84; - private static final int REQUIRED_ALBUM_MATCHES = 4; - private static final int SHUFFLE_MODE_NONE = 0; - private static final int SHUFFLE_MODE_ALL = 1; - private static final int SHUFFLE_MODE_ARTIST = 2; - - private RemoteControlClientHelper mRemoteControl; - - private final IBinder binder = new SimpleServiceBinder(this); - private Looper mediaPlayerLooper; - private MediaPlayer mediaPlayer; - private MediaPlayer nextMediaPlayer; - private int audioSessionId; - private boolean nextSetup = false; - private final List downloadList = new ArrayList(); - private final List backgroundDownloadList = new ArrayList(); - private final List toDelete = new ArrayList(); - private final Handler handler = new Handler(); - private Handler mediaPlayerHandler; - private final DownloadServiceLifecycleSupport lifecycleSupport = new DownloadServiceLifecycleSupport(this); - private ShufflePlayBuffer shufflePlayBuffer; - private ArtistRadioBuffer artistRadioBuffer; - - private final LruCache downloadFileCache = new LruCache(100); - private final List cleanupCandidates = new ArrayList(); - private final Scrobbler scrobbler = new Scrobbler(); - private RemoteController remoteController; - private DownloadFile currentPlaying; - private int currentPlayingIndex = -1; - private DownloadFile nextPlaying; - private DownloadFile currentDownloading; - private SilentBackgroundTask bufferTask; - private SilentBackgroundTask nextPlayingTask; - private PlayerState playerState = IDLE; - private PlayerState nextPlayerState = IDLE; - private boolean removePlayed; - private boolean shufflePlay; - private boolean artistRadio; - private long revision; - private static DownloadService instance; - private String suggestedPlaylistName; - private String suggestedPlaylistId; - private PowerManager.WakeLock wakeLock; - private boolean keepScreenOn; - private int cachedPosition = 0; - private boolean downloadOngoing = false; - private float volume = 1.0f; - - private AudioEffectsController effectsController; - private RemoteControlState remoteState = LOCAL; - private PositionCache positionCache; - private BufferProxy proxy; - - private Timer sleepTimer; - private int timerDuration; - private boolean autoPlayStart = false; - - private MediaRouteManager mediaRouter; - - // Variables to manage getCurrentPosition sometimes starting from an arbitrary non-zero number - private long subtractNextPosition = 0; - private int subtractPosition = 0; - - @Override - public void onCreate() { - super.onCreate(); - - final SharedPreferences prefs = Util.getPreferences(this); - new Thread(new Runnable() { - public void run() { - Looper.prepare(); - - mediaPlayer = new MediaPlayer(); - mediaPlayer.setWakeMode(DownloadService.this, PowerManager.PARTIAL_WAKE_LOCK); - mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - - mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { - @Override - public boolean onError(MediaPlayer mediaPlayer, int what, int more) { - handleError(new Exception("MediaPlayer error: " + what + " (" + more + ")")); - return false; - } - }); - try { - audioSessionId = mediaPlayer.getAudioSessionId(); - } catch(Throwable e) { - // Froyo or lower - } - - try { - Intent i = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION); - i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, audioSessionId); - i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName()); - sendBroadcast(i); - } catch(Throwable e) { - // Froyo or lower - } - - effectsController = new AudioEffectsController(DownloadService.this, audioSessionId); - if(prefs.getBoolean(Constants.PREFERENCES_EQUALIZER_ON, false)) { - getEqualizerController(); - } - - mediaPlayerLooper = Looper.myLooper(); - mediaPlayerHandler = new Handler(mediaPlayerLooper); - Looper.loop(); - } - }, "DownloadService").start(); - - Util.registerMediaButtonEventReceiver(this); - - if (mRemoteControl == null) { - // Use the remote control APIs (if available) to set the playback state - mRemoteControl = RemoteControlClientHelper.createInstance(); - ComponentName mediaButtonReceiverComponent = new ComponentName(getPackageName(), MediaButtonIntentReceiver.class.getName()); - mRemoteControl.register(this, mediaButtonReceiverComponent); - } - - PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE); - wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.getClass().getName()); - wakeLock.setReferenceCounted(false); - - try { - timerDuration = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, "5")); - } catch(Throwable e) { - timerDuration = 5; - } - sleepTimer = null; - - keepScreenOn = prefs.getBoolean(Constants.PREFERENCES_KEY_KEEP_SCREEN_ON, false); - - mediaRouter = new MediaRouteManager(this); - - instance = this; - shufflePlayBuffer = new ShufflePlayBuffer(this); - artistRadioBuffer = new ArtistRadioBuffer(this); - lifecycleSupport.onCreate(); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - super.onStartCommand(intent, flags, startId); - lifecycleSupport.onStart(intent); - return START_NOT_STICKY; - } - - @Override - public void onDestroy() { - super.onDestroy(); - instance = null; - - if(currentPlaying != null) currentPlaying.setPlaying(false); - if(sleepTimer != null){ - sleepTimer.cancel(); - sleepTimer.purge(); - } - lifecycleSupport.onDestroy(); - - try { - Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION); - i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, audioSessionId); - i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName()); - sendBroadcast(i); - } catch(Throwable e) { - // Froyo or lower - } - - mediaPlayer.release(); - if(nextMediaPlayer != null) { - nextMediaPlayer.release(); - } - mediaPlayerLooper.quit(); - shufflePlayBuffer.shutdown(); - effectsController.release(); - if (mRemoteControl != null) { - mRemoteControl.unregister(this); - mRemoteControl = null; - } - - if(bufferTask != null) { - bufferTask.cancel(); - bufferTask = null; - } - if(nextPlayingTask != null) { - nextPlayingTask.cancel(); - nextPlayingTask = null; - } - if(remoteController != null) { - remoteController.stop(); - remoteController.shutdown(); - } - if(proxy != null) { - proxy.stop(); - proxy = null; - } - mediaRouter.destroy(); - Notifications.hidePlayingNotification(this, this, handler); - Notifications.hideDownloadingNotification(this, this, handler); - } - - public static DownloadService getInstance() { - return instance; - } - - @Override - public IBinder onBind(Intent intent) { - return binder; - } - - public void post(Runnable r) { - handler.post(r); - } - public void postDelayed(Runnable r, long millis) { - handler.postDelayed(r, millis); - } - - public synchronized void download(List songs, boolean save, boolean autoplay, boolean playNext, boolean shuffle) { - download(songs, save, autoplay, playNext, shuffle, 0, 0); - } - public synchronized void download(List songs, boolean save, boolean autoplay, boolean playNext, boolean shuffle, int start, int position) { - setShufflePlayEnabled(false); - setArtistRadio(null); - int offset = 1; - boolean noNetwork = !Util.isOffline(this) && !Util.isNetworkConnected(this); - boolean warnNetwork = false; - - if (songs.isEmpty()) { - return; - } - if (playNext) { - if (autoplay && getCurrentPlayingIndex() >= 0) { - offset = 0; - } - for (MusicDirectory.Entry song : songs) { - if(song != null) { - DownloadFile downloadFile = new DownloadFile(this, song, save); - addToDownloadList(downloadFile, getCurrentPlayingIndex() + offset); - if(noNetwork && !warnNetwork) { - if(!downloadFile.isCompleteFileAvailable()) { - warnNetwork = true; - } - } - offset++; - } - } - setNextPlaying(); - revision++; - } else { - int size = size(); - int index = getCurrentPlayingIndex(); - for (MusicDirectory.Entry song : songs) { - DownloadFile downloadFile = new DownloadFile(this, song, save); - addToDownloadList(downloadFile, -1); - if(noNetwork && !warnNetwork) { - if(!downloadFile.isCompleteFileAvailable()) { - warnNetwork = true; - } - } - } - if(!autoplay && (size - 1) == index) { - setNextPlaying(); - } - revision++; - } - updateRemotePlaylist(); - - if(shuffle) { - shuffle(); - } - if(warnNetwork) { - Util.toast(this, R.string.select_album_no_network); - } - - if (autoplay) { - play(start, true, position); - } else if(start != 0 || position != 0) { - play(start, false, position); - } else { - if (currentPlaying == null) { - currentPlaying = downloadList.get(0); - currentPlayingIndex = 0; - currentPlaying.setPlaying(true); - } else { - currentPlayingIndex = downloadList.indexOf(currentPlaying); - } - checkDownloads(); - } - lifecycleSupport.serializeDownloadQueue(); - } - private void addToDownloadList(DownloadFile file, int offset) { - if(offset == -1) { - downloadList.add(file); - } else { - downloadList.add(offset, file); - } - } - public synchronized void downloadBackground(List songs, boolean save) { - for (MusicDirectory.Entry song : songs) { - DownloadFile downloadFile = new DownloadFile(this, song, save); - if(!downloadFile.isWorkDone() || (downloadFile.shouldSave() && !downloadFile.isSaved())) { - // Only add to list if there is work to be done - backgroundDownloadList.add(downloadFile); - } else if(downloadFile.isSaved() && !save) { - // Quickly unpin song instead of adding it to work to be done - downloadFile.unpin(); - } - } - revision++; - - if(!Util.isOffline(this) && !Util.isNetworkConnected(this)) { - Util.toast(this, R.string.select_album_no_network); - } - - checkDownloads(); - lifecycleSupport.serializeDownloadQueue(); - } - - private void updateRemotePlaylist() { - if (remoteState != LOCAL && remoteController != null) { - remoteController.updatePlaylist(); - } - } - - public synchronized void restore(List songs, List toDelete, int currentPlayingIndex, int currentPlayingPosition) { - SharedPreferences prefs = Util.getPreferences(this); - RemoteControlState newState = RemoteControlState.values()[prefs.getInt(Constants.PREFERENCES_KEY_CONTROL_MODE, 0)]; - if(newState != LOCAL) { - String id = prefs.getString(Constants.PREFERENCES_KEY_CONTROL_ID, null); - setRemoteState(newState, null, id); - } - if(prefs.getBoolean(Constants.PREFERENCES_KEY_REMOVE_PLAYED, false)) { - removePlayed = true; - } - int startShufflePlay = prefs.getInt(Constants.PREFERENCES_KEY_SHUFFLE_MODE, SHUFFLE_MODE_NONE); - download(songs, false, false, false, false); - if(startShufflePlay != SHUFFLE_MODE_NONE) { - if(startShufflePlay == SHUFFLE_MODE_ALL) { - shufflePlay = true; - } else if(startShufflePlay == SHUFFLE_MODE_ARTIST) { - artistRadio = true; - artistRadioBuffer.restoreArtist(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_MODE_EXTRA, null)); - } - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(Constants.PREFERENCES_KEY_SHUFFLE_MODE, startShufflePlay); - editor.commit(); - } - if (currentPlayingIndex != -1) { - while(mediaPlayer == null) { - Util.sleepQuietly(50L); - } - - play(currentPlayingIndex, autoPlayStart, currentPlayingPosition); - autoPlayStart = false; - } - - if(toDelete != null) { - for(MusicDirectory.Entry entry: toDelete) { - this.toDelete.add(forSong(entry)); - } - } - - suggestedPlaylistName = prefs.getString(Constants.PREFERENCES_KEY_PLAYLIST_NAME, null); - suggestedPlaylistId = prefs.getString(Constants.PREFERENCES_KEY_PLAYLIST_ID, null); - } - - public boolean isInitialized() { - return lifecycleSupport != null && lifecycleSupport.isInitialized(); - } - - public synchronized Date getLastStateChanged() { - return lifecycleSupport.getLastChange(); - } - - public synchronized void setRemovePlayed(boolean enabled) { - removePlayed = enabled; - if(removePlayed) { - checkDownloads(); - lifecycleSupport.serializeDownloadQueue(); - } - SharedPreferences.Editor editor = Util.getPreferences(this).edit(); - editor.putBoolean(Constants.PREFERENCES_KEY_REMOVE_PLAYED, enabled); - editor.commit(); - } - public boolean isRemovePlayed() { - return removePlayed; - } - - public synchronized void setShufflePlayEnabled(boolean enabled) { - shufflePlay = enabled; - if (shufflePlay) { - clear(); - checkDownloads(); - } - SharedPreferences.Editor editor = Util.getPreferences(this).edit(); - editor.putInt(Constants.PREFERENCES_KEY_SHUFFLE_MODE, enabled ? SHUFFLE_MODE_ALL : SHUFFLE_MODE_NONE); - editor.commit(); - } - - public boolean isShufflePlayEnabled() { - return shufflePlay; - } - - public void setArtistRadio(String artistId) { - if(artistId == null) { - artistRadio = false; - } else { - artistRadio = true; - artistRadioBuffer.setArtist(artistId); - } - - SharedPreferences.Editor editor = Util.getPreferences(this).edit(); - editor.putInt(Constants.PREFERENCES_KEY_SHUFFLE_MODE, (artistId != null) ? SHUFFLE_MODE_ARTIST : SHUFFLE_MODE_NONE); - if(artistId != null) { - editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_MODE_EXTRA, artistId); - } - editor.commit(); - } - - public synchronized void shuffle() { - Collections.shuffle(downloadList); - currentPlayingIndex = downloadList.indexOf(currentPlaying); - if (currentPlaying != null) { - downloadList.remove(getCurrentPlayingIndex()); - downloadList.add(0, currentPlaying); - currentPlayingIndex = 0; - } - revision++; - lifecycleSupport.serializeDownloadQueue(); - updateRemotePlaylist(); - setNextPlaying(); - } - - public RepeatMode getRepeatMode() { - return Util.getRepeatMode(this); - } - - public void setRepeatMode(RepeatMode repeatMode) { - Util.setRepeatMode(this, repeatMode); - setNextPlaying(); - } - - public boolean getKeepScreenOn() { - return keepScreenOn; - } - - public void setKeepScreenOn(boolean keepScreenOn) { - this.keepScreenOn = keepScreenOn; - - SharedPreferences prefs = Util.getPreferences(this); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(Constants.PREFERENCES_KEY_KEEP_SCREEN_ON, keepScreenOn); - editor.commit(); - } - - public synchronized DownloadFile forSong(MusicDirectory.Entry song) { - DownloadFile returnFile = null; - for (DownloadFile downloadFile : downloadList) { - if (downloadFile.getSong().equals(song)) { - if(((downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && downloadFile.getPartialFile().exists()) || downloadFile.isWorkDone())) { - // If downloading, return immediately - return downloadFile; - } else { - // Otherwise, check to make sure there isn't a background download going on first - returnFile = downloadFile; - } - } - } - for (DownloadFile downloadFile : backgroundDownloadList) { - if (downloadFile.getSong().equals(song)) { - return downloadFile; - } - } - - if(returnFile != null) { - return returnFile; - } - - DownloadFile downloadFile = downloadFileCache.get(song); - if (downloadFile == null) { - downloadFile = new DownloadFile(this, song, false); - downloadFileCache.put(song, downloadFile); - } - return downloadFile; - } - - public synchronized void clear() { - clear(true); - } - - public synchronized void clearBackground() { - if(currentDownloading != null && backgroundDownloadList.contains(currentDownloading)) { - currentDownloading.cancelDownload(); - currentDownloading = null; - } - backgroundDownloadList.clear(); - revision++; - Notifications.hideDownloadingNotification(this, this, handler); - } - - public synchronized void clearIncomplete() { - Iterator iterator = downloadList.iterator(); - while (iterator.hasNext()) { - DownloadFile downloadFile = iterator.next(); - if (!downloadFile.isCompleteFileAvailable()) { - iterator.remove(); - - // Reset if the current playing song has been removed - if(currentPlaying == downloadFile) { - reset(); - } - - currentPlayingIndex = downloadList.indexOf(currentPlaying); - } - } - lifecycleSupport.serializeDownloadQueue(); - updateRemotePlaylist(); - } - - public void setOnline(final boolean online) { - if(online) { - mediaRouter.addOnlineProviders(); - } else { - mediaRouter.removeOnlineProviders(); - } - if(shufflePlay) { - setShufflePlayEnabled(false); - } - if(artistRadio) { - setArtistRadio(null); - } - - lifecycleSupport.post(new Runnable() { - @Override - public void run() { - if (online) { - checkDownloads(); - } else { - clearIncomplete(); - } - } - }); - } - public void userSettingsChanged() { - mediaRouter.buildSelector(); - } - - public synchronized int size() { - return downloadList.size(); - } - - public synchronized void clear(boolean serialize) { - // Delete podcast if fully listened to - int position = getPlayerPosition(); - int duration = getPlayerDuration(); - boolean cutoff = isPastCutoff(position, duration, true); - if(currentPlaying != null && currentPlaying.getSong() instanceof PodcastEpisode) { - if(cutoff) { - currentPlaying.delete(); - } - } - for(DownloadFile podcast: toDelete) { - podcast.delete(); - } - toDelete.clear(); - - // Clear bookmarks from current playing if past a certain point - if(cutoff) { - clearCurrentBookmark(true); - } else { - // Check if we should be adding a new bookmark here - checkAddBookmark(); - } - if(currentPlaying != null) { - scrobbler.conditionalScrobble(this, currentPlaying, position, duration); - } - - reset(); - downloadList.clear(); - revision++; - if (currentDownloading != null && !backgroundDownloadList.contains(currentDownloading)) { - currentDownloading.cancelDownload(); - currentDownloading = null; - } - setCurrentPlaying(null, false); - - if (serialize) { - lifecycleSupport.serializeDownloadQueue(); - } - updateRemotePlaylist(); - setNextPlaying(); - if(proxy != null) { - proxy.stop(); - proxy = null; - } - - suggestedPlaylistName = null; - suggestedPlaylistId = null; - } - - public synchronized void remove(int which) { - downloadList.remove(which); - currentPlayingIndex = downloadList.indexOf(currentPlaying); - } - - public synchronized void remove(DownloadFile downloadFile) { - if (downloadFile == currentDownloading) { - currentDownloading.cancelDownload(); - currentDownloading = null; - } - if (downloadFile == currentPlaying) { - reset(); - setCurrentPlaying(null, false); - } - downloadList.remove(downloadFile); - currentPlayingIndex = downloadList.indexOf(currentPlaying); - backgroundDownloadList.remove(downloadFile); - revision++; - lifecycleSupport.serializeDownloadQueue(); - updateRemotePlaylist(); - if(downloadFile == nextPlaying) { - setNextPlaying(); - } - } - - public synchronized void delete(List songs) { - for (MusicDirectory.Entry song : songs) { - forSong(song).delete(); - } - } - - public synchronized void unpin(List songs) { - for (MusicDirectory.Entry song : songs) { - forSong(song).unpin(); - } - } - - synchronized void setCurrentPlaying(int currentPlayingIndex, boolean showNotification) { - try { - setCurrentPlaying(downloadList.get(currentPlayingIndex), showNotification); - } catch (IndexOutOfBoundsException x) { - // Ignored - } - } - - synchronized void setCurrentPlaying(DownloadFile currentPlaying, boolean showNotification) { - if(this.currentPlaying != null) { - this.currentPlaying.setPlaying(false); - } - this.currentPlaying = currentPlaying; - if(currentPlaying == null) { - currentPlayingIndex = -1; - setPlayerState(IDLE); - } else { - currentPlayingIndex = downloadList.indexOf(currentPlaying); - } - - if (currentPlaying != null) { - Util.broadcastNewTrackInfo(this, currentPlaying.getSong()); - mRemoteControl.updateMetadata(this, currentPlaying.getSong()); - } else { - Util.broadcastNewTrackInfo(this, null); - Notifications.hidePlayingNotification(this, this, handler); - } - } - - synchronized void setNextPlaying() { - SharedPreferences prefs = Util.getPreferences(DownloadService.this); - - // Only obey gapless playback for local - if(remoteState == LOCAL) { - boolean gaplessPlayback = prefs.getBoolean(Constants.PREFERENCES_KEY_GAPLESS_PLAYBACK, true); - if (!gaplessPlayback) { - nextPlaying = null; - nextPlayerState = IDLE; - return; - } - } - setNextPlayerState(IDLE); - - int index = getNextPlayingIndex(); - - nextSetup = false; - if(nextPlayingTask != null) { - nextPlayingTask.cancel(); - nextPlayingTask = null; - } - if(index < size() && index != -1 && index != currentPlayingIndex) { - nextPlaying = downloadList.get(index); - - if(remoteState == LOCAL) { - nextPlayingTask = new CheckCompletionTask(nextPlaying); - nextPlayingTask.execute(); - } else if(remoteController != null) { - remoteController.changeNextTrack(nextPlaying); - } - } else { - if(remoteState == LOCAL) { - resetNext(); - } else if(remoteController != null) { - remoteController.changeNextTrack(nextPlaying); - } - nextPlaying = null; - } - } - - public int getCurrentPlayingIndex() { - return currentPlayingIndex; - } - private int getNextPlayingIndex() { - int index = getCurrentPlayingIndex(); - if (index != -1) { - switch (getRepeatMode()) { - case OFF: - index = index + 1; - break; - case ALL: - index = (index + 1) % size(); - break; - case SINGLE: - break; - default: - break; - } - } - return index; - } - - public DownloadFile getCurrentPlaying() { - return currentPlaying; - } - - public DownloadFile getCurrentDownloading() { - return currentDownloading; - } - - public DownloadFile getNextPlaying() { - return nextPlaying; - } - - public List getSongs() { - return downloadList; - } - - public List getToDelete() { return toDelete; } - - public synchronized List getDownloads() { - List temp = new ArrayList(); - temp.addAll(downloadList); - temp.addAll(backgroundDownloadList); - return temp; - } - - public List getBackgroundDownloads() { - return backgroundDownloadList; - } - - /** Plays either the current song (resume) or the first/next one in queue. */ - public synchronized void play() - { - int current = getCurrentPlayingIndex(); - if (current == -1) { - play(0); - } else { - play(current); - } - } - - public synchronized void play(int index) { - play(index, true); - } - private synchronized void play(int index, boolean start) { - play(index, start, 0); - } - private synchronized void play(int index, boolean start, int position) { - int size = this.size(); - if (index < 0 || index >= size) { - reset(); - if(index >= size && size != 0) { - setCurrentPlaying(0, false); - Notifications.hidePlayingNotification(this, this, handler); - } else { - setCurrentPlaying(null, false); - } - lifecycleSupport.serializeDownloadQueue(); - } else { - if(nextPlayingTask != null) { - nextPlayingTask.cancel(); - nextPlayingTask = null; - } - setCurrentPlaying(index, start); - if (start && remoteState != LOCAL) { - remoteController.changeTrack(index, currentPlaying); - } - if (remoteState == LOCAL) { - bufferAndPlay(position, start); - checkDownloads(); - setNextPlaying(); - } - } - } - private synchronized void playNext() { - if(nextPlaying != null && nextPlayerState == PlayerState.PREPARED) { - if(!nextSetup) { - playNext(true); - } else { - nextSetup = false; - playNext(false); - } - } else { - onSongCompleted(); - } - } - private synchronized void playNext(boolean start) { - Util.broadcastPlaybackStatusChange(this, currentPlaying.getSong(), PlayerState.PREPARED); - - // Swap the media players since nextMediaPlayer is ready to play - subtractPosition = 0; - if(start) { - nextMediaPlayer.start(); - } else if(!nextMediaPlayer.isPlaying()) { - Log.w(TAG, "nextSetup lied about it's state!"); - nextMediaPlayer.start(); - } else { - Log.i(TAG, "nextMediaPlayer already playing"); - - // Next time the cachedPosition is updated, use that as position 0 - subtractNextPosition = System.currentTimeMillis(); - } - MediaPlayer tmp = mediaPlayer; - mediaPlayer = nextMediaPlayer; - nextMediaPlayer = tmp; - setCurrentPlaying(nextPlaying, true); - setPlayerState(PlayerState.STARTED); - setupHandlers(currentPlaying, false, start); - setNextPlaying(); - - // Proxy should not be being used here since the next player was already setup to play - if(proxy != null) { - proxy.stop(); - proxy = null; - } - checkDownloads(); - } - - /** Plays or resumes the playback, depending on the current player state. */ - public synchronized void togglePlayPause() { - if (playerState == PAUSED || playerState == COMPLETED || playerState == STOPPED) { - start(); - } else if (playerState == STOPPED || playerState == IDLE) { - autoPlayStart = true; - play(); - } else if (playerState == STARTED) { - pause(); - } - } - - public synchronized void seekTo(int position) { - if(position < 0) { - position = 0; - } - - try { - if (remoteState != LOCAL) { - remoteController.changePosition(position / 1000); - } else { - if(proxy != null && currentPlaying.isCompleteFileAvailable()) { - doPlay(currentPlaying, position, playerState == STARTED); - return; - } - - mediaPlayer.seekTo(position); - cachedPosition = position; - subtractPosition = 0; - } - } catch (Exception x) { - handleError(x); - } - } - - public synchronized void previous() { - int index = getCurrentPlayingIndex(); - if (index == -1) { - return; - } - - // If only one song, just skip within song - if(size() == 1) { - seekTo(getPlayerPosition() - REWIND); - return; - } - - - // Restart song if played more than five seconds. - if (getPlayerPosition() > 5000 || (index == 0 && getRepeatMode() != RepeatMode.ALL)) { - seekTo(0); - } else { - if(index == 0) { - index = size(); - } - - play(index - 1, playerState != PAUSED && playerState != STOPPED && playerState != IDLE); - } - } - - public synchronized void next() { - next(false); - } - public synchronized void next(boolean forceCutoff) { - next(forceCutoff, false); - } - public synchronized void next(boolean forceCutoff, boolean forceStart) { - // If only one song, just skip within song - if(size() == 1) { - seekTo(getPlayerPosition() + FAST_FORWARD); - return; - } else if(playerState == PREPARING || playerState == PREPARED) { - return; - } - - // Delete podcast if fully listened to - int position = getPlayerPosition(); - int duration = getPlayerDuration(); - boolean cutoff; - if(forceCutoff) { - cutoff = true; - } else { - cutoff = isPastCutoff(position, duration); - } - if(currentPlaying != null && currentPlaying.getSong() instanceof PodcastEpisode) { - if(cutoff) { - toDelete.add(currentPlaying); - } - } - if(cutoff) { - clearCurrentBookmark(true); - } - if(currentPlaying != null) { - scrobbler.conditionalScrobble(this, currentPlaying, position, duration); - } - - int index = getCurrentPlayingIndex(); - int nextPlayingIndex = getNextPlayingIndex(); - // Make sure to actually go to next when repeat song is on - if(index == nextPlayingIndex) { - nextPlayingIndex++; - } - if (index != -1 && nextPlayingIndex < size()) { - play(nextPlayingIndex, playerState != PAUSED && playerState != STOPPED && playerState != IDLE || forceStart); - } - } - - public void onSongCompleted() { - play(getNextPlayingIndex()); - } - - public synchronized void pause() { - pause(false); - } - public synchronized void pause(boolean temp) { - try { - if (playerState == STARTED) { - if (remoteState != LOCAL) { - remoteController.stop(); - } else { - mediaPlayer.pause(); - } - setPlayerState(temp ? PAUSED_TEMP : PAUSED); - } else if(playerState == PAUSED_TEMP) { - setPlayerState(temp ? PAUSED_TEMP : PAUSED); - } - } catch (Exception x) { - handleError(x); - } - } - - public synchronized void stop() { - try { - if (playerState == STARTED) { - if (remoteState != LOCAL) { - remoteController.stop(); - setPlayerState(STOPPED); - handler.post(new Runnable() { - @Override - public void run() { - mediaRouter.setDefaultRoute(); - } - }); - } else { - mediaPlayer.pause(); - setPlayerState(STOPPED); - } - } else if(playerState == PAUSED) { - setPlayerState(STOPPED); - } - } catch(Exception x) { - handleError(x); - } - } - - public synchronized void start() { - try { - if (remoteState != LOCAL) { - remoteController.start(); - } else { - // Only start if done preparing - if(playerState != PREPARING) { - mediaPlayer.start(); - } else { - // Otherwise, we need to set it up to start when done preparing - autoPlayStart = true; - } - } - setPlayerState(STARTED); - } catch (Exception x) { - handleError(x); - } - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - public synchronized void reset() { - if (bufferTask != null) { - bufferTask.cancel(); - bufferTask = null; - } - try { - // Only set to idle if it's not being killed to start RemoteController - if(remoteState == LOCAL) { - setPlayerState(IDLE); - } - mediaPlayer.setOnErrorListener(null); - mediaPlayer.setOnCompletionListener(null); - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && nextSetup) { - mediaPlayer.setNextMediaPlayer(null); - nextSetup = false; - } - mediaPlayer.reset(); - subtractPosition = 0; - } catch (Exception x) { - handleError(x); - } - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - public synchronized void resetNext() { - try { - if (nextMediaPlayer != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && nextSetup) { - mediaPlayer.setNextMediaPlayer(null); - nextSetup = false; - } - - nextMediaPlayer.setOnCompletionListener(null); - nextMediaPlayer.setOnErrorListener(null); - nextMediaPlayer.reset(); - nextMediaPlayer.release(); - nextMediaPlayer = null; - } - } catch (Exception e) { - Log.w(TAG, "Failed to reset next media player"); - } - } - - public int getPlayerPosition() { - try { - if (playerState == IDLE || playerState == DOWNLOADING || playerState == PREPARING) { - return 0; - } - if (remoteState != LOCAL) { - return remoteController.getRemotePosition() * 1000; - } else { - return Math.max(0, cachedPosition - subtractPosition); - } - } catch (Exception x) { - handleError(x); - return 0; - } - } - - public synchronized int getPlayerDuration() { - if (currentPlaying != null) { - Integer duration = currentPlaying.getSong().getDuration(); - if (duration != null) { - return duration * 1000; - } - } - if (playerState != IDLE && playerState != DOWNLOADING && playerState != PlayerState.PREPARING) { - if(remoteState == LOCAL) { - try { - return mediaPlayer.getDuration(); - } catch (Exception x) { - handleError(x); - } - } else { - return remoteController.getRemoteDuration() * 1000; - } - } - return 0; - } - - public PlayerState getPlayerState() { - return playerState; - } - - public PlayerState getNextPlayerState() { - return nextPlayerState; - } - - public synchronized void setPlayerState(final PlayerState playerState) { - Log.i(TAG, this.playerState.name() + " -> " + playerState.name() + " (" + currentPlaying + ")"); - - if (playerState == PAUSED) { - lifecycleSupport.serializeDownloadQueue(); - } - - boolean show = playerState == PlayerState.STARTED; - boolean pause = playerState == PlayerState.PAUSED; - boolean hide = playerState == PlayerState.STOPPED; - Util.broadcastPlaybackStatusChange(this, (currentPlaying != null) ? currentPlaying.getSong() : null, playerState); - - this.playerState = playerState; - - if(playerState == STARTED) { - Util.requestAudioFocus(this); - } - - if (show) { - Notifications.showPlayingNotification(this, this, handler, currentPlaying.getSong()); - } else if (pause) { - SharedPreferences prefs = Util.getPreferences(this); - if(prefs.getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false)) { - Notifications.showPlayingNotification(this, this, handler, currentPlaying.getSong()); - } else { - Notifications.hidePlayingNotification(this, this, handler); - } - } else if(hide) { - Notifications.hidePlayingNotification(this, this, handler); - } - if(mRemoteControl != null) { - mRemoteControl.setPlaybackState(playerState.getRemoteControlClientPlayState()); - } - - if (playerState == STARTED) { - scrobbler.scrobble(this, currentPlaying, false); - } else if (playerState == COMPLETED) { - scrobbler.scrobble(this, currentPlaying, true); - } - - if(playerState == STARTED && positionCache == null && remoteState == LOCAL) { - positionCache = new PositionCache(); - Thread thread = new Thread(positionCache, "PositionCache"); - thread.start(); - } else if(playerState != STARTED && positionCache != null) { - positionCache.stop(); - positionCache = null; - } - } - - private class PositionCache implements Runnable { - boolean isRunning = true; - - public void stop() { - isRunning = false; - } - - @Override - public void run() { - // Stop checking position before the song reaches completion - while(isRunning) { - try { - if(mediaPlayer != null && playerState == STARTED) { - int newPosition = mediaPlayer.getCurrentPosition(); - - // If sudden jump in position, something is wrong - if(subtractNextPosition == 0 && newPosition > (cachedPosition + 5000)) { - // Only 1 second should have gone by, subtract the rest - subtractPosition += (newPosition - cachedPosition) - 1000; - } - - cachedPosition = newPosition; - - if(subtractNextPosition > 0) { - // Subtraction amount is current position - how long ago onCompletionListener was called - subtractPosition = cachedPosition - (int) (System.currentTimeMillis() - subtractNextPosition); - if(subtractPosition < 0) { - subtractPosition = 0; - } - subtractNextPosition = 0; - } - } - Thread.sleep(1000L); - } - catch(Exception e) { - Log.w(TAG, "Crashed getting current position", e); - isRunning = false; - positionCache = null; - } - } - } - } - - private void setPlayerStateCompleted() { - Log.i(TAG, this.playerState.name() + " -> " + PlayerState.COMPLETED + " (" + currentPlaying + ")"); - this.playerState = PlayerState.COMPLETED; - if(positionCache != null) { - positionCache.stop(); - positionCache = null; - } - scrobbler.scrobble(this, currentPlaying, true); - } - - public synchronized void setNextPlayerState(PlayerState playerState) { - Log.i(TAG, "Next: " + this.nextPlayerState.name() + " -> " + playerState.name() + " (" + nextPlaying + ")"); - this.nextPlayerState = playerState; - } - - public void setSuggestedPlaylistName(String name, String id) { - this.suggestedPlaylistName = name; - this.suggestedPlaylistId = id; - - SharedPreferences.Editor editor = Util.getPreferences(this).edit(); - editor.putString(Constants.PREFERENCES_KEY_PLAYLIST_NAME, name); - editor.putString(Constants.PREFERENCES_KEY_PLAYLIST_ID, id); - editor.commit(); - } - - public String getSuggestedPlaylistName() { - return suggestedPlaylistName; - } - - public String getSuggestedPlaylistId() { - return suggestedPlaylistId; - } - - public boolean getEqualizerAvailable() { - return effectsController.isAvailable(); - } - - public EqualizerController getEqualizerController() { - EqualizerController controller = null; - try { - controller = effectsController.getEqualizerController(); - if(controller.getEqualizer() == null) { - throw new Exception("Failed to get EQ"); - } - } catch(Exception e) { - Log.w(TAG, "Failed to start EQ, retrying with new mediaPlayer: " + e); - - // If we failed, we are going to try to reinitialize the MediaPlayer - boolean playing = playerState == STARTED; - int pos = getPlayerPosition(); - mediaPlayer.pause(); - Util.sleepQuietly(10L); - reset(); - - try { - // Resetup media player - mediaPlayer.setAudioSessionId(audioSessionId); - mediaPlayer.setDataSource(currentPlaying.getFile().getCanonicalPath()); - - controller = effectsController.getEqualizerController(); - if(controller.getEqualizer() == null) { - throw new Exception("Failed to get EQ"); - } - } catch(Exception e2) { - Log.w(TAG, "Failed to setup EQ even after reinitialization"); - // Don't try again, just resetup media player and continue on - controller = null; - } - - // Restart from same position and state we left off in - play(getCurrentPlayingIndex(), false, pos); - } - - return controller; - } - - public MediaRouteSelector getRemoteSelector() { - return mediaRouter.getSelector(); - } - - public boolean isSeekable() { - if(remoteState == LOCAL) { - return currentPlaying != null && currentPlaying.isWorkDone() && playerState != PREPARING; - } else if(remoteController != null) { - return remoteController.isSeekable(); - } else { - return false; - } - } - - public boolean isRemoteEnabled() { - return remoteState != LOCAL; - } - - public RemoteController getRemoteController() { - return remoteController; - } - - public void setRemoteEnabled(RemoteControlState newState) { - if(instance != null) { - setRemoteEnabled(newState, null); - } - } - public void setRemoteEnabled(RemoteControlState newState, Object ref) { - setRemoteState(newState, ref); - - RouteInfo info = mediaRouter.getSelectedRoute(); - String routeId = info.getId(); - - SharedPreferences.Editor editor = Util.getPreferences(this).edit(); - editor.putInt(Constants.PREFERENCES_KEY_CONTROL_MODE, newState.getValue()); - editor.putString(Constants.PREFERENCES_KEY_CONTROL_ID, routeId); - editor.commit(); - } - private void setRemoteState(RemoteControlState newState, Object ref) { - setRemoteState(newState, ref, null); - } - private void setRemoteState(final RemoteControlState newState, final Object ref, final String routeId) { - // Don't try to do anything if already in the correct state - if(remoteState == newState) { - return; - } - - boolean isPlaying = playerState == STARTED; - int position = getPlayerPosition(); - - if(remoteController != null) { - remoteController.stop(); - setPlayerState(PlayerState.IDLE); - remoteController.shutdown(); - remoteController = null; - - if(newState == LOCAL) { - mediaRouter.setDefaultRoute(); - } - } - - Log.i(TAG, remoteState.name() + " => " + newState.name() + " (" + currentPlaying + ")"); - remoteState = newState; - switch(newState) { - case JUKEBOX_SERVER: - remoteController = new JukeboxController(this, handler); - break; - case CHROMECAST: case DLNA: - if(ref == null) { - remoteState = LOCAL; - break; - } - remoteController = (RemoteController) ref; - break; - case LOCAL: default: - break; - } - - if(remoteController != null) { - remoteController.create(isPlaying, position / 1000); - } else { - play(getCurrentPlayingIndex(), isPlaying, position); - } - - if (remoteState != LOCAL) { - reset(); - - // Cancel current download, if necessary. - if (currentDownloading != null) { - currentDownloading.cancelDownload(); - } - - // Cancels current setup tasks - if(bufferTask != null && bufferTask.isRunning()) { - bufferTask.cancel(); - bufferTask = null; - } - if(nextPlayingTask != null && nextPlayingTask.isRunning()) { - nextPlayingTask.cancel(); - nextPlayingTask = null; - } - } - - if(remoteState == LOCAL) { - checkDownloads(); - } - - if(routeId != null) { - final Runnable delayedReconnect = new Runnable() { - @Override - public void run() { - RouteInfo info = mediaRouter.getRouteForId(routeId); - if(info == null) { - setRemoteState(LOCAL, null); - } else if(newState == RemoteControlState.CHROMECAST) { - RemoteController controller = mediaRouter.getRemoteController(info); - if(controller != null) { - setRemoteState(RemoteControlState.CHROMECAST, controller); - } - } - mediaRouter.stopScan(); - } - }; - - handler.post(new Runnable() { - @Override - public void run() { - mediaRouter.startScan(); - RouteInfo info = mediaRouter.getRouteForId(routeId); - if(info == null) { - handler.postDelayed(delayedReconnect, 2000L); - } else if(newState == RemoteControlState.CHROMECAST) { - RemoteController controller = mediaRouter.getRemoteController(info); - if(controller != null) { - setRemoteState(RemoteControlState.CHROMECAST, controller); - } - } - } - }); - } - } - - public void registerRoute(MediaRouter router) { - if(mRemoteControl != null) { - mRemoteControl.registerRoute(router); - } - } - public void unregisterRoute(MediaRouter router) { - if(mRemoteControl != null) { - mRemoteControl.unregisterRoute(router); - } - } - - public void updateRemoteVolume(boolean up) { - AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE); - audioManager.adjustVolume(up ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER, AudioManager.FLAG_SHOW_UI); - } - - public void startRemoteScan() { - mediaRouter.startScan(); - } - - public void stopRemoteScan() { - mediaRouter.stopScan(); - } - - private synchronized void bufferAndPlay() { - bufferAndPlay(0); - } - private synchronized void bufferAndPlay(int position) { - bufferAndPlay(position, true); - } - private synchronized void bufferAndPlay(int position, boolean start) { - if(!currentPlaying.isCompleteFileAvailable()) { - reset(); - - bufferTask = new BufferTask(currentPlaying, position, start); - bufferTask.execute(); - } else { - doPlay(currentPlaying, position, start); - } - } - - private synchronized void doPlay(final DownloadFile downloadFile, final int position, final boolean start) { - try { - downloadFile.setPlaying(true); - final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile(); - boolean isPartial = file.equals(downloadFile.getPartialFile()); - downloadFile.updateModificationDate(); - - subtractPosition = 0; - mediaPlayer.setOnCompletionListener(null); - mediaPlayer.setOnPreparedListener(null); - mediaPlayer.setOnErrorListener(null); - mediaPlayer.reset(); - setPlayerState(IDLE); - try { - mediaPlayer.setAudioSessionId(audioSessionId); - } catch(Throwable e) { - mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - } - String dataSource = file.getAbsolutePath(); - if(isPartial && !Util.isOffline(this)) { - if (proxy == null) { - proxy = new BufferProxy(this); - proxy.start(); - } - proxy.setBufferFile(downloadFile); - dataSource = proxy.getPrivateAddress(dataSource); - Log.i(TAG, "Data Source: " + dataSource); - } else if(proxy != null) { - proxy.stop(); - proxy = null; - } - mediaPlayer.setDataSource(dataSource); - setPlayerState(PREPARING); - - mediaPlayer.setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() { - public void onBufferingUpdate(MediaPlayer mp, int percent) { - Log.i(TAG, "Buffered " + percent + "%"); - if (percent == 100) { - mediaPlayer.setOnBufferingUpdateListener(null); - } - } - }); - - mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { - public void onPrepared(MediaPlayer mediaPlayer) { - try { - setPlayerState(PREPARED); - - synchronized (DownloadService.this) { - if (position != 0) { - Log.i(TAG, "Restarting player from position " + position); - mediaPlayer.seekTo(position); - } - cachedPosition = position; - - applyReplayGain(mediaPlayer, downloadFile); - - if (start || autoPlayStart) { - mediaPlayer.start(); - setPlayerState(STARTED); - - // Disable autoPlayStart after done - autoPlayStart = false; - } else { - setPlayerState(PAUSED); - } - } - - // Only call when starting, setPlayerState(PAUSED) already calls this - if(start) { - lifecycleSupport.serializeDownloadQueue(); - } - } catch (Exception x) { - handleError(x); - } - } - }); - - setupHandlers(downloadFile, isPartial, start); - - mediaPlayer.prepareAsync(); - } catch (Exception x) { - handleError(x); - } - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - private synchronized void setupNext(final DownloadFile downloadFile) { - try { - final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile(); - resetNext(); - - // Exit when using remote controllers - if(remoteState != LOCAL) { - return; - } - - nextMediaPlayer = new MediaPlayer(); - nextMediaPlayer.setWakeMode(DownloadService.this, PowerManager.PARTIAL_WAKE_LOCK); - try { - nextMediaPlayer.setAudioSessionId(audioSessionId); - } catch(Throwable e) { - nextMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - } - nextMediaPlayer.setDataSource(file.getPath()); - setNextPlayerState(PREPARING); - - nextMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { - public void onPrepared(MediaPlayer mp) { - try { - setNextPlayerState(PREPARED); - - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && (playerState == PlayerState.STARTED || playerState == PlayerState.PAUSED)) { - mediaPlayer.setNextMediaPlayer(nextMediaPlayer); - nextSetup = true; - } - - applyReplayGain(nextMediaPlayer, downloadFile); - } catch (Exception x) { - handleErrorNext(x); - } - } - }); - - nextMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { - public boolean onError(MediaPlayer mediaPlayer, int what, int extra) { - Log.w(TAG, "Error on playing next " + "(" + what + ", " + extra + "): " + downloadFile); - return true; - } - }); - - nextMediaPlayer.prepareAsync(); - } catch (Exception x) { - handleErrorNext(x); - } - } - - private void setupHandlers(final DownloadFile downloadFile, final boolean isPartial, final boolean isPlaying) { - final int duration = downloadFile.getSong().getDuration() == null ? 0 : downloadFile.getSong().getDuration() * 1000; - mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { - public boolean onError(MediaPlayer mediaPlayer, int what, int extra) { - Log.w(TAG, "Error on playing file " + "(" + what + ", " + extra + "): " + downloadFile); - int pos = getPlayerPosition(); - reset(); - if (!isPartial || (downloadFile.isWorkDone() && (Math.abs(duration - pos) < 10000))) { - playNext(); - } else { - downloadFile.setPlaying(false); - doPlay(downloadFile, pos, isPlaying); - downloadFile.setPlaying(true); - } - return true; - } - }); - - mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { - @Override - public void onCompletion(MediaPlayer mediaPlayer) { - // Acquire a temporary wakelock, since when we return from - // this callback the MediaPlayer will release its wakelock - // and allow the device to go to sleep. - wakeLock.acquire(30000); - - setPlayerStateCompleted(); - - int pos = getPlayerPosition(); - Log.i(TAG, "Ending position " + pos + " of " + duration); - if (!isPartial || (downloadFile.isWorkDone() && (Math.abs(duration - pos) < 10000)) || nextSetup) { - playNext(); - postPlayCleanup(downloadFile); - } else { - // If file is not completely downloaded, restart the playback from the current position. - synchronized (DownloadService.this) { - if (downloadFile.isWorkDone()) { - // Complete was called early even though file is fully buffered - Log.i(TAG, "Requesting restart from " + pos + " of " + duration); - reset(); - downloadFile.setPlaying(false); - doPlay(downloadFile, pos, true); - downloadFile.setPlaying(true); - } else { - Log.i(TAG, "Requesting restart from " + pos + " of " + duration); - reset(); - bufferTask = new BufferTask(downloadFile, pos, true); - bufferTask.execute(); - } - } - checkDownloads(); - } - } - }); - } - - public void setSleepTimerDuration(int duration){ - timerDuration = duration; - } - - public void startSleepTimer(){ - if(sleepTimer != null){ - sleepTimer.cancel(); - sleepTimer.purge(); - } - - sleepTimer = new Timer(); - - sleepTimer.schedule(new TimerTask() { - @Override - public void run() { - pause(); - sleepTimer.cancel(); - sleepTimer.purge(); - sleepTimer = null; - } - - }, timerDuration * 60 * 1000); - } - - public void stopSleepTimer() { - if(sleepTimer != null){ - sleepTimer.cancel(); - sleepTimer.purge(); - } - sleepTimer = null; - } - - public boolean getSleepTimer() { - return sleepTimer != null; - } - - public void setVolume(float volume) { - if(mediaPlayer != null && (playerState == STARTED || playerState == PAUSED || playerState == STOPPED)) { - try { - this.volume = volume; - reapplyVolume(); - } catch(Exception e) { - Log.w(TAG, "Failed to set volume"); - } - } - } - public void reapplyVolume() { - applyReplayGain(mediaPlayer, currentPlaying); - } - - public synchronized void swap(boolean mainList, int from, int to) { - List list = mainList ? downloadList : backgroundDownloadList; - int max = list.size(); - if(to >= max) { - to = max - 1; - } - else if(to < 0) { - to = 0; - } - - DownloadFile movedSong = list.remove(from); - list.add(to, movedSong); - currentPlayingIndex = downloadList.indexOf(currentPlaying); - if(mainList) { - if(remoteState == LOCAL || (remoteController != null && remoteController.isNextSupported())) { - // Moving next playing, current playing, or moving a song to be next playing - if(movedSong == nextPlaying || movedSong == currentPlaying || (currentPlayingIndex + 1) == to) { - setNextPlaying(); - } - } else { - updateRemotePlaylist(); - } - } - } - - public synchronized void serializeQueue() { - serializeQueue(true); - } - public synchronized void serializeQueue(boolean serializeRemote) { - if(playerState == PlayerState.PAUSED) { - lifecycleSupport.serializeDownloadQueue(serializeRemote); - } - } - - private void handleError(Exception x) { - Log.w(TAG, "Media player error: " + x, x); - if(mediaPlayer != null) { - try { - mediaPlayer.reset(); - } catch(Exception e) { - Log.e(TAG, "Failed to reset player in error handler"); - } - } - setPlayerState(IDLE); - } - private void handleErrorNext(Exception x) { - Log.w(TAG, "Next Media player error: " + x, x); - try { - nextMediaPlayer.reset(); - } catch(Exception e) { - Log.e(TAG, "Failed to reset next media player", x); - } - setNextPlayerState(IDLE); - } - - public synchronized void checkDownloads() { - if (!Util.isExternalStoragePresent() || !lifecycleSupport.isExternalStorageAvailable()) { - return; - } - - if(removePlayed) { - checkRemovePlayed(); - } - if (shufflePlay) { - checkShufflePlay(); - } - if(artistRadio) { - checkArtistRadio(); - } - - if (!Util.isNetworkConnected(this, true) || Util.isOffline(this)) { - return; - } - - if (downloadList.isEmpty() && backgroundDownloadList.isEmpty()) { - return; - } - - // Need to download current playing and not casting? - if (currentPlaying != null && remoteState == LOCAL && currentPlaying != currentDownloading && !currentPlaying.isWorkDone()) { - // Cancel current download, if necessary. - if (currentDownloading != null) { - currentDownloading.cancelDownload(); - } - - currentDownloading = currentPlaying; - currentDownloading.download(); - cleanupCandidates.add(currentDownloading); - } - - // Find a suitable target for download. - else if (currentDownloading == null || currentDownloading.isWorkDone() || currentDownloading.isFailed() && ((!downloadList.isEmpty() && remoteState == LOCAL) || !backgroundDownloadList.isEmpty())) { - currentDownloading = null; - int n = size(); - - int preloaded = 0; - - if(n != 0 && remoteState == LOCAL) { - int start = currentPlaying == null ? 0 : getCurrentPlayingIndex(); - if(start == -1) { - start = 0; - } - int i = start; - do { - DownloadFile downloadFile = downloadList.get(i); - if (!downloadFile.isWorkDone() && !downloadFile.isFailedMax()) { - if (downloadFile.shouldSave() || preloaded < Util.getPreloadCount(this)) { - currentDownloading = downloadFile; - currentDownloading.download(); - cleanupCandidates.add(currentDownloading); - if(i == (start + 1)) { - setNextPlayerState(DOWNLOADING); - } - break; - } - } else if (currentPlaying != downloadFile) { - preloaded++; - } - - i = (i + 1) % n; - } while (i != start); - } - - if((preloaded + 1 == n || preloaded >= Util.getPreloadCount(this) || downloadList.isEmpty() || remoteState != LOCAL) && !backgroundDownloadList.isEmpty()) { - for(int i = 0; i < backgroundDownloadList.size(); i++) { - DownloadFile downloadFile = backgroundDownloadList.get(i); - if(downloadFile.isWorkDone() && (!downloadFile.shouldSave() || downloadFile.isSaved()) || downloadFile.isFailedMax()) { - // Don't need to keep list like active song list - backgroundDownloadList.remove(i); - revision++; - i--; - } else { - currentDownloading = downloadFile; - currentDownloading.download(); - cleanupCandidates.add(currentDownloading); - break; - } - } - } - } - - if(!backgroundDownloadList.isEmpty()) { - Notifications.showDownloadingNotification(this, this, handler, currentDownloading, backgroundDownloadList.size()); - downloadOngoing = true; - } else if(backgroundDownloadList.isEmpty() && downloadOngoing) { - Notifications.hideDownloadingNotification(this, this, handler); - downloadOngoing = false; - } - - // Delete obsolete .partial and .complete files. - cleanup(); - } - - private synchronized void checkRemovePlayed() { - while(currentPlayingIndex > 0) { - downloadList.remove(0); - currentPlayingIndex = downloadList.indexOf(currentPlaying); - revision++; - } - } - - private synchronized void checkShufflePlay() { - - // Get users desired random playlist size - SharedPreferences prefs = Util.getPreferences(this); - int listSize = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_RANDOM_SIZE, "20")); - boolean wasEmpty = downloadList.isEmpty(); - - long revisionBefore = revision; - - // First, ensure that list is at least 20 songs long. - int size = size(); - if (size < listSize) { - for (MusicDirectory.Entry song : shufflePlayBuffer.get(listSize - size)) { - DownloadFile downloadFile = new DownloadFile(this, song, false); - downloadList.add(downloadFile); - revision++; - } - } - - int currIndex = currentPlaying == null ? 0 : getCurrentPlayingIndex(); - - // Only shift playlist if playing song #5 or later. - if (currIndex > 4) { - int songsToShift = currIndex - 2; - for (MusicDirectory.Entry song : shufflePlayBuffer.get(songsToShift)) { - downloadList.add(new DownloadFile(this, song, false)); - downloadList.get(0).cancelDownload(); - downloadList.remove(0); - revision++; - } - } - currentPlayingIndex = downloadList.indexOf(currentPlaying); - - if (revisionBefore != revision) { - updateRemotePlaylist(); - } - - if (wasEmpty && !downloadList.isEmpty()) { - play(0); - } - } - - private synchronized void checkArtistRadio() { - // Get users desired random playlist size - SharedPreferences prefs = Util.getPreferences(this); - int listSize = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_RANDOM_SIZE, "20")); - boolean wasEmpty = downloadList.isEmpty(); - - long revisionBefore = revision; - - // First, ensure that list is at least 20 songs long. - int size = size(); - if (size < listSize) { - for (MusicDirectory.Entry song : artistRadioBuffer.get(listSize - size)) { - DownloadFile downloadFile = new DownloadFile(this, song, false); - downloadList.add(downloadFile); - revision++; - } - } - - int currIndex = currentPlaying == null ? 0 : getCurrentPlayingIndex(); - - // Only shift playlist if playing song #5 or later. - if (currIndex > 4) { - int songsToShift = currIndex - 2; - for (MusicDirectory.Entry song : artistRadioBuffer.get(songsToShift)) { - downloadList.add(new DownloadFile(this, song, false)); - downloadList.get(0).cancelDownload(); - downloadList.remove(0); - revision++; - } - } - currentPlayingIndex = downloadList.indexOf(currentPlaying); - - if (revisionBefore != revision) { - updateRemotePlaylist(); - } - - if (wasEmpty && !downloadList.isEmpty()) { - play(0); - } - } - - public long getDownloadListUpdateRevision() { - return revision; - } - - private synchronized void cleanup() { - Iterator iterator = cleanupCandidates.iterator(); - while (iterator.hasNext()) { - DownloadFile downloadFile = iterator.next(); - if (downloadFile != currentPlaying && downloadFile != currentDownloading) { - if (downloadFile.cleanup()) { - iterator.remove(); - } - } - } - } - - public void postPlayCleanup() { - postPlayCleanup(currentPlaying); - } - public void postPlayCleanup(DownloadFile downloadFile) { - if(downloadFile == null) { - return; - } - - // Finished loading, delete when list is cleared - if (downloadFile.getSong() instanceof PodcastEpisode) { - toDelete.add(downloadFile); - } - clearCurrentBookmark(downloadFile.getSong(), true); - } - - private boolean isPastCutoff() { - return isPastCutoff(getPlayerPosition(), getPlayerDuration()); - } - private boolean isPastCutoff(int position, int duration) { - return isPastCutoff(position, duration, false); - } - private boolean isPastCutoff(int position, int duration, boolean allowSkipping) { - if(currentPlaying == null) { - return false; - } - - int cutoffPoint = (int) (duration * DELETE_CUTOFF); - boolean isPastCutoff = duration > 0 && position > cutoffPoint; - - // Check to make sure song isn't within 10 seconds of where it was created - MusicDirectory.Entry entry = currentPlaying.getSong(); - if(entry != null && entry.getBookmark() != null) { - Bookmark bookmark = entry.getBookmark(); - if(position < (bookmark.getPosition() + 10000)) { - isPastCutoff = false; - } - } - - // Check to make sure we aren't in a series of similar content before deleting bookmark - if(isPastCutoff && allowSkipping) { - // Check to make sure: - // Is an audio book - // Next playing exists and is not a wrap around or a shuffle - // Next playing is from same context as current playing, so not at end of list - if(entry.isAudioBook() && nextPlaying != null && downloadList.indexOf(nextPlaying) != 0 && !shufflePlay - && entry.getParent() != null && entry.getParent().equals(nextPlaying.getSong().getParent())) { - isPastCutoff = false; - } - } - - return isPastCutoff; - } - - private void clearCurrentBookmark() { - clearCurrentBookmark(false); - } - private void clearCurrentBookmark(boolean checkDelete) { - // If current is null, nothing to do - if(currentPlaying == null) { - return; - } - - clearCurrentBookmark(currentPlaying.getSong(), checkDelete); - } - private void clearCurrentBookmark(final MusicDirectory.Entry entry, boolean checkDelete) { - // If no bookmark, move on - if(entry.getBookmark() == null) { - return; - } - - // If delete is not specified, check position - if(!checkDelete) { - checkDelete = isPastCutoff(); - } - - // If supposed to delete - if(checkDelete) { - new SilentBackgroundTask(this) { - @Override - public Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(DownloadService.this); - entry.setBookmark(null); - musicService.deleteBookmark(entry, DownloadService.this, null); - - MusicDirectory.Entry found = UpdateView.findEntry(entry); - if(found != null) { - found.setBookmark(null); - } - return null; - } - - @Override - public void error(Throwable error) { - Log.e(TAG, "Failed to delete bookmark", error); - - String msg; - if(error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = DownloadService.this.getResources().getString(R.string.bookmark_deleted_error, entry.getTitle()) + " " + getErrorMessage(error); - } - - Util.toast(DownloadService.this, msg, false); - } - }.execute(); - } - } - - private void checkAddBookmark() { - // Don't do anything if no current playing - if(currentPlaying == null || !ServerInfo.canBookmark(this)) { - return; - } - - final MusicDirectory.Entry entry = currentPlaying.getSong(); - int duration = getPlayerDuration(); - - // If song is podcast or long go ahead and auto add a bookmark - if(entry.isPodcast() || entry.isAudioBook() || duration > (10L * 60L * 1000L)) { - final Context context = this; - final int position = getPlayerPosition(); - - // Don't bother when at beginning - if(position < 5000L) { - return; - } - - new SilentBackgroundTask(context) { - @Override - public Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - entry.setBookmark(new Bookmark(position)); - musicService.createBookmark(entry, position, "Auto created by DSub", context, null); - - MusicDirectory.Entry found = UpdateView.findEntry(entry); - if(found != null) { - found.setBookmark(new Bookmark(position)); - } - - return null; - } - - @Override - public void error(Throwable error) { - Log.w(TAG, "Failed to create automatic bookmark", error); - - String msg; - if(error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.download_save_bookmark_failed) + getErrorMessage(error); - } - - Util.toast(context, msg, false); - } - }.execute(); - } - } - - private void applyReplayGain(MediaPlayer mediaPlayer, DownloadFile downloadFile) { - if(currentPlaying == null) { - return; - } - - SharedPreferences prefs = Util.getPreferences(this); - try { - float[] rg = BastpUtil.getReplayGainValues(downloadFile.getFile().getCanonicalPath()); /* track, album */ - float adjust = 0f; - if (prefs.getBoolean(Constants.PREFERENCES_KEY_REPLAY_GAIN, false)) { - boolean singleAlbum = false; - - String replayGainType = prefs.getString(Constants.PREFERENCES_KEY_REPLAY_GAIN_TYPE, "1"); - // 1 => Smart replay gain - if("1".equals(replayGainType)) { - // Check if part of at least consequetive songs of the same album - - int index = downloadList.indexOf(downloadFile); - if(index != -1) { - String albumName = downloadFile.getSong().getAlbum(); - int matched = 0; - - // Check forwards - for(int i = index + 1; i < downloadList.size() && matched < REQUIRED_ALBUM_MATCHES; i++) { - if(albumName.equals(downloadList.get(i).getSong().getAlbum())) { - matched++; - } else { - break; - } - } - - // Check backwards - for(int i = index - 1; i >= 0 && matched < REQUIRED_ALBUM_MATCHES; i--) { - if(albumName.equals(downloadList.get(i).getSong().getAlbum())) { - matched++; - } else { - break; - } - } - - if(matched >= REQUIRED_ALBUM_MATCHES) { - singleAlbum = true; - } - } - } - // 2 => Use album tags - else if("2".equals(replayGainType)) { - singleAlbum = true; - } - // 3 => Use track tags - // Already false, no need to do anything here - - - // If playing a single album or no track gain, use album gain - if((singleAlbum || rg[0] == 0) && rg[1] != 0) { - adjust = rg[1]; - } else { - // Otherwise, give priority to track gain - adjust = rg[0]; - } - - if (adjust == 0) { - /* No RG value found: decrease volume for untagged song if requested by user */ - int untagged = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_REPLAY_GAIN_UNTAGGED, "0")); - adjust = (untagged - 150) / 10f; - } else { - int bump = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_REPLAY_GAIN_BUMP, "150")); - adjust += (bump - 150) / 10f; - } - } - - float rg_result = ((float) Math.pow(10, (adjust / 20))) * volume; - if (rg_result > 1.0f) { - rg_result = 1.0f; /* android would IGNORE the change if this is > 1 and we would end up with the wrong volume */ - } else if (rg_result < 0.0f) { - rg_result = 0.0f; - } - mediaPlayer.setVolume(rg_result, rg_result); - } catch(IOException e) { - Log.w(TAG, "Failed to apply replay gain values", e); - } - } - - private class BufferTask extends SilentBackgroundTask { - private final DownloadFile downloadFile; - private final int position; - private final long expectedFileSize; - private final File partialFile; - private final boolean start; - - public BufferTask(DownloadFile downloadFile, int position, boolean start) { - super(instance); - this.downloadFile = downloadFile; - this.position = position; - partialFile = downloadFile.getPartialFile(); - this.start = start; - - // Calculate roughly how many bytes BUFFER_LENGTH_SECONDS corresponds to. - int bitRate = downloadFile.getBitRate(); - long byteCount = Math.max(100000, bitRate * 1024L / 8L * 5L); - - // Find out how large the file should grow before resuming playback. - Log.i(TAG, "Buffering from position " + position + " and bitrate " + bitRate); - expectedFileSize = (position * bitRate / 8) + byteCount; - } - - @Override - public Void doInBackground() throws InterruptedException { - setPlayerState(DOWNLOADING); - - while (!bufferComplete()) { - Thread.sleep(1000L); - if (isCancelled() || downloadFile.isFailedMax()) { - return null; - } else if(!downloadFile.isFailedMax() && !downloadFile.isDownloading()) { - checkDownloads(); - } - } - doPlay(downloadFile, position, start); - - return null; - } - - private boolean bufferComplete() { - boolean completeFileAvailable = downloadFile.isWorkDone(); - long size = partialFile.length(); - - Log.i(TAG, "Buffering " + partialFile + " (" + size + "/" + expectedFileSize + ", " + completeFileAvailable + ")"); - return completeFileAvailable || size >= expectedFileSize; - } - - @Override - public String toString() { - return "BufferTask (" + downloadFile + ")"; - } - } - - private class CheckCompletionTask extends SilentBackgroundTask { - private final DownloadFile downloadFile; - private final File partialFile; - - public CheckCompletionTask(DownloadFile downloadFile) { - super(instance); - this.downloadFile = downloadFile; - if(downloadFile != null) { - partialFile = downloadFile.getPartialFile(); - } else { - partialFile = null; - } - } - - @Override - public Void doInBackground() throws InterruptedException { - if(downloadFile == null) { - return null; - } - - // Do an initial sleep so this prepare can't compete with main prepare - Thread.sleep(5000L); - while (!bufferComplete()) { - Thread.sleep(5000L); - if (isCancelled()) { - return null; - } - } - - // Start the setup of the next media player - mediaPlayerHandler.post(new Runnable() { - public void run() { - setupNext(downloadFile); - } - }); - return null; - } - - private boolean bufferComplete() { - boolean completeFileAvailable = downloadFile.isWorkDone(); - Log.i(TAG, "Buffering next " + partialFile + " (" + partialFile.length() + "): " + completeFileAvailable); - return completeFileAvailable && (playerState == PlayerState.STARTED || playerState == PlayerState.PAUSED); - } - - @Override - public String toString() { - return "CheckCompletionTask (" + downloadFile + ")"; - } - } -} diff --git a/src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java b/src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java deleted file mode 100644 index c9f92f41..00000000 --- a/src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.concurrent.locks.ReentrantLock; -import java.util.concurrent.atomic.AtomicBoolean; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.media.RemoteControlClient; -import android.os.Handler; -import android.os.Looper; -import android.telephony.PhoneStateListener; -import android.telephony.TelephonyManager; -import android.util.Log; -import android.view.KeyEvent; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerQueue; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.util.BackgroundTask; -import github.daneren2005.dsub.util.CacheCleaner; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.Util; - -import static github.daneren2005.dsub.domain.PlayerState.PREPARING; - -/** - * @author Sindre Mehus - */ -public class DownloadServiceLifecycleSupport { - private static final String TAG = DownloadServiceLifecycleSupport.class.getSimpleName(); - public static final String FILENAME_DOWNLOADS_SER = "downloadstate2.ser"; - - private final DownloadService downloadService; - private Looper eventLooper; - private Handler eventHandler; - private BroadcastReceiver ejectEventReceiver; - private PhoneStateListener phoneStateListener; - private boolean externalStorageAvailable= true; - private ReentrantLock lock = new ReentrantLock(); - private final AtomicBoolean setup = new AtomicBoolean(false); - private long lastPressTime = 0; - private SilentBackgroundTask currentSavePlayQueueTask = null; - private Date lastChange = null; - - /** - * This receiver manages the intent that could come from other applications. - */ - private BroadcastReceiver intentReceiver = new BroadcastReceiver() { - @Override - public void onReceive(final Context context, final Intent intent) { - eventHandler.post(new Runnable() { - @Override - public void run() { - String action = intent.getAction(); - Log.i(TAG, "intentReceiver.onReceive: " + action); - if (DownloadService.CMD_PLAY.equals(action)) { - downloadService.play(); - } else if (DownloadService.CMD_NEXT.equals(action)) { - downloadService.next(); - } else if (DownloadService.CMD_PREVIOUS.equals(action)) { - downloadService.previous(); - } else if (DownloadService.CMD_TOGGLEPAUSE.equals(action)) { - downloadService.togglePlayPause(); - } else if (DownloadService.CMD_PAUSE.equals(action)) { - downloadService.pause(); - } else if (DownloadService.CMD_STOP.equals(action)) { - downloadService.pause(); - downloadService.seekTo(0); - } - } - }); - } - }; - - - public DownloadServiceLifecycleSupport(DownloadService downloadService) { - this.downloadService = downloadService; - } - - public void onCreate() { - new Thread(new Runnable() { - @Override - public void run() { - Looper.prepare(); - eventLooper = Looper.myLooper(); - eventHandler = new Handler(eventLooper); - - // Deserialize queue before starting looper - try { - lock.lock(); - deserializeDownloadQueueNow(); - - // Wait until PREPARING is done to mark lifecycle as ready to receive events - while(downloadService.getPlayerState() == PREPARING) { - Util.sleepQuietly(50L); - } - - setup.set(true); - } finally { - lock.unlock(); - } - - Looper.loop(); - } - }, "DownloadServiceLifecycleSupport").start(); - - // Stop when SD card is ejected. - ejectEventReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - externalStorageAvailable = Intent.ACTION_MEDIA_MOUNTED.equals(intent.getAction()); - if (!externalStorageAvailable) { - Log.i(TAG, "External media is ejecting. Stopping playback."); - downloadService.reset(); - } else { - Log.i(TAG, "External media is available."); - } - } - }; - IntentFilter ejectFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT); - ejectFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); - ejectFilter.addDataScheme("file"); - downloadService.registerReceiver(ejectEventReceiver, ejectFilter); - - // React to media buttons. - Util.registerMediaButtonEventReceiver(downloadService); - - // Pause temporarily on incoming phone calls. - phoneStateListener = new MyPhoneStateListener(); - TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE); - telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); - - // Register the handler for outside intents. - IntentFilter commandFilter = new IntentFilter(); - commandFilter.addAction(DownloadService.CMD_PLAY); - commandFilter.addAction(DownloadService.CMD_TOGGLEPAUSE); - commandFilter.addAction(DownloadService.CMD_PAUSE); - commandFilter.addAction(DownloadService.CMD_STOP); - commandFilter.addAction(DownloadService.CMD_PREVIOUS); - commandFilter.addAction(DownloadService.CMD_NEXT); - commandFilter.addAction(DownloadService.CANCEL_DOWNLOADS); - downloadService.registerReceiver(intentReceiver, commandFilter); - - new CacheCleaner(downloadService, downloadService).clean(); - } - - public boolean isInitialized() { - return setup.get(); - } - - public void onStart(final Intent intent) { - if (intent != null) { - final String action = intent.getAction(); - - if(eventHandler == null) { - Util.sleepQuietly(100L); - } - if(eventHandler == null) { - return; - } - - eventHandler.post(new Runnable() { - @Override - public void run() { - if(!setup.get()) { - lock.lock(); - lock.unlock(); - } - - if(DownloadService.START_PLAY.equals(action)) { - int offlinePref = intent.getIntExtra(Constants.PREFERENCES_KEY_OFFLINE, 0); - if(offlinePref != 0) { - boolean offline = (offlinePref == 2); - Util.setOffline(downloadService, offline); - if (offline) { - downloadService.clearIncomplete(); - } else { - downloadService.checkDownloads(); - } - } - - if(intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, false)) { - // Add shuffle parameters - SharedPreferences.Editor editor = Util.getPreferences(downloadService).edit(); - String startYear = intent.getStringExtra(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR); - if(startYear != null) { - editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYear); - } - - String endYear = intent.getStringExtra(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR); - if(endYear != null) { - editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYear); - } - - String genre = intent.getStringExtra(Constants.PREFERENCES_KEY_SHUFFLE_GENRE); - if(genre != null) { - editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre); - } - editor.commit(); - - downloadService.setShufflePlayEnabled(true); - } else { - downloadService.start(); - } - } else if(DownloadService.CMD_TOGGLEPAUSE.equals(action)) { - downloadService.togglePlayPause(); - } else if(DownloadService.CMD_NEXT.equals(action)) { - downloadService.next(); - } else if(DownloadService.CMD_PREVIOUS.equals(action)) { - downloadService.previous(); - } else if(DownloadService.CANCEL_DOWNLOADS.equals(action)) { - downloadService.clearBackground(); - } else if(intent.getExtras() != null) { - final KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT); - if (event != null) { - handleKeyEvent(event); - } - } - } - }); - } - } - - public void onDestroy() { - serializeDownloadQueue(); - eventLooper.quit(); - downloadService.unregisterReceiver(ejectEventReceiver); - downloadService.unregisterReceiver(intentReceiver); - - TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE); - telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE); - } - - public boolean isExternalStorageAvailable() { - return externalStorageAvailable; - } - - public void serializeDownloadQueue() { - serializeDownloadQueue(true); - } - public void serializeDownloadQueue(final boolean serializeRemote) { - if(!setup.get()) { - return; - } - - final List songs = new ArrayList(downloadService.getSongs()); - eventHandler.post(new Runnable() { - @Override - public void run() { - if(lock.tryLock()) { - try { - serializeDownloadQueueNow(songs, serializeRemote); - } finally { - lock.unlock(); - } - } - } - }); - } - - public void serializeDownloadQueueNow(List songs, boolean serializeRemote) { - final PlayerQueue state = new PlayerQueue(); - for (DownloadFile downloadFile : songs) { - state.songs.add(downloadFile.getSong()); - } - for (DownloadFile downloadFile : downloadService.getToDelete()) { - state.toDelete.add(downloadFile.getSong()); - } - state.currentPlayingIndex = downloadService.getCurrentPlayingIndex(); - state.currentPlayingPosition = downloadService.getPlayerPosition(); - - DownloadFile currentPlaying = downloadService.getCurrentPlaying(); - if(currentPlaying != null) { - state.renameCurrent = currentPlaying.isWorkDone() && !currentPlaying.isCompleteFileAvailable(); - } - state.changed = lastChange = new Date(); - - Log.i(TAG, "Serialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition); - FileUtil.serialize(downloadService, state, FILENAME_DOWNLOADS_SER); - - // If we are on Subsonic 5.2+, save play queue - if(serializeRemote && ServerInfo.canSavePlayQueue(downloadService) && !Util.isOffline(downloadService) && state.songs.size() > 0) { - // Cancel any currently running tasks - if(currentSavePlayQueueTask != null) { - currentSavePlayQueueTask.cancel(); - } - - currentSavePlayQueueTask = new SilentBackgroundTask(downloadService) { - @Override - protected Void doInBackground() throws Throwable { - try { - MusicService musicService = MusicServiceFactory.getMusicService(downloadService); - musicService.savePlayQueue(state.songs, state.songs.get(state.currentPlayingIndex), state.currentPlayingPosition, downloadService, null); - currentSavePlayQueueTask = null; - } catch (Exception e) { - Log.e(TAG, "Failed to save playing queue to server", e); - currentSavePlayQueueTask = null; - } - - return null; - } - - @Override - protected void error(Throwable error) { - currentSavePlayQueueTask = null; - super.error(error); - } - }; - currentSavePlayQueueTask.execute(); - } - } - - public void post(Runnable runnable) { - eventHandler.post(runnable); - } - - private void deserializeDownloadQueueNow() { - PlayerQueue state = FileUtil.deserialize(downloadService, FILENAME_DOWNLOADS_SER, PlayerQueue.class); - if (state == null) { - return; - } - Log.i(TAG, "Deserialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition); - - // Rename first thing before anything else starts - if(state.renameCurrent && state.currentPlayingIndex != -1 && state.currentPlayingIndex < state.songs.size()) { - DownloadFile currentPlaying = new DownloadFile(downloadService, state.songs.get(state.currentPlayingIndex), false); - currentPlaying.renamePartial(); - } - - downloadService.restore(state.songs, state.toDelete, state.currentPlayingIndex, state.currentPlayingPosition); - - if(state != null) { - lastChange = state.changed; - } - } - - public Date getLastChange() { - return lastChange; - } - - private void handleKeyEvent(KeyEvent event) { - if(event.getAction() == KeyEvent.ACTION_DOWN) { - switch (event.getKeyCode()) { - case RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE: - case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: - downloadService.togglePlayPause(); - break; - case KeyEvent.KEYCODE_HEADSETHOOK: - if(lastPressTime < (System.currentTimeMillis() - 500)) { - lastPressTime = System.currentTimeMillis(); - downloadService.togglePlayPause(); - } else { - downloadService.next(false, true); - } - break; - case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS: - case KeyEvent.KEYCODE_MEDIA_PREVIOUS: - downloadService.previous(); - break; - case RemoteControlClient.FLAG_KEY_MEDIA_NEXT: - case KeyEvent.KEYCODE_MEDIA_NEXT: - downloadService.next(); - break; - case RemoteControlClient.FLAG_KEY_MEDIA_STOP: - case KeyEvent.KEYCODE_MEDIA_STOP: - downloadService.stop(); - break; - case RemoteControlClient.FLAG_KEY_MEDIA_PLAY: - case KeyEvent.KEYCODE_MEDIA_PLAY: - if(downloadService.getPlayerState() != PlayerState.STARTED) { - downloadService.start(); - } - break; - case RemoteControlClient.FLAG_KEY_MEDIA_PAUSE: - case KeyEvent.KEYCODE_MEDIA_PAUSE: - downloadService.pause(); - default: - break; - } - } - } - - /** - * Logic taken from packages/apps/Music. Will pause when an incoming - * call rings or if a call (incoming or outgoing) is connected. - */ - private class MyPhoneStateListener extends PhoneStateListener { - private boolean resumeAfterCall; - - @Override - public void onCallStateChanged(final int state, String incomingNumber) { - eventHandler.post(new Runnable() { - @Override - public void run() { - switch (state) { - case TelephonyManager.CALL_STATE_RINGING: - case TelephonyManager.CALL_STATE_OFFHOOK: - if (downloadService.getPlayerState() == PlayerState.STARTED) { - resumeAfterCall = true; - downloadService.pause(true); - } - break; - case TelephonyManager.CALL_STATE_IDLE: - if (resumeAfterCall) { - resumeAfterCall = false; - if(downloadService.getPlayerState() == PlayerState.PAUSED_TEMP) { - downloadService.start(); - } - } - break; - default: - break; - } - } - }); - } - } -} diff --git a/src/github/daneren2005/dsub/service/HeadphoneListenerService.java b/src/github/daneren2005/dsub/service/HeadphoneListenerService.java deleted file mode 100644 index f4375c50..00000000 --- a/src/github/daneren2005/dsub/service/HeadphoneListenerService.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2015 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.service; - -import android.app.Service; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.IBinder; - -import github.daneren2005.dsub.receiver.HeadphonePlugReceiver; -import github.daneren2005.dsub.util.Util; - -/** - * Created by Scott on 4/6/2015. - */ -public class HeadphoneListenerService extends Service { - private HeadphonePlugReceiver receiver; - - @Override - public void onCreate() { - super.onCreate(); - - receiver = new HeadphonePlugReceiver(); - registerReceiver(receiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if(!Util.shouldStartOnHeadphones(this)) { - stopSelf(); - } - - return Service.START_STICKY; - } - - @Override - public void onDestroy() { - super.onDestroy(); - - try { - if(receiver != null) { - unregisterReceiver(receiver); - } - } catch(Exception e) { - // Don't care - } - } -} diff --git a/src/github/daneren2005/dsub/service/JukeboxController.java b/src/github/daneren2005/dsub/service/JukeboxController.java deleted file mode 100644 index e9d7cbc8..00000000 --- a/src/github/daneren2005/dsub/service/JukeboxController.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2009 (C) Sindre Mehus -*/ - -package github.daneren2005.dsub.service; - -import android.os.Handler; -import android.util.Log; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.RemoteStatus; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.domain.RemoteControlState; -import github.daneren2005.dsub.service.parser.SubsonicRESTException; -import github.daneren2005.dsub.util.Util; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -public class JukeboxController extends RemoteController { - private static final String TAG = JukeboxController.class.getSimpleName(); - private static final long STATUS_UPDATE_INTERVAL_SECONDS = 5L; - - private final Handler handler; - private boolean running = false; - private final TaskQueue tasks = new TaskQueue(); - private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); - private ScheduledFuture statusUpdateFuture; - private final AtomicLong timeOfLastUpdate = new AtomicLong(); - private RemoteStatus jukeboxStatus; - private float gain = 0.5f; - - public JukeboxController(DownloadService downloadService, Handler handler) { - this.downloadService = downloadService; - this.handler = handler; - } - - @Override - public void create(boolean playing, int seconds) { - new Thread("JukeboxController") { - @Override - public void run() { - running = true; - processTasks(); - } - }.start(); - updatePlaylist(); - // Best I can do since API doesn't support seeking without starting playback - if(seconds != 0 && playing) { - changePosition(seconds); - } - } - - @Override - public void start() { - tasks.remove(Stop.class); - tasks.remove(Start.class); - - startStatusUpdate(); - tasks.add(new Start()); - } - @Override - public void stop() { - tasks.remove(Stop.class); - tasks.remove(Start.class); - - stopStatusUpdate(); - tasks.add(new Stop()); - } - @Override - public void shutdown() { - running = false; - } - - @Override - public void updatePlaylist() { - tasks.remove(Skip.class); - tasks.remove(Stop.class); - tasks.remove(Start.class); - - List ids = new ArrayList(); - for (DownloadFile file : downloadService.getDownloads()) { - ids.add(file.getSong().getId()); - } - tasks.add(new SetPlaylist(ids)); - } - @Override - public void changePosition(int seconds) { - tasks.remove(Skip.class); - tasks.remove(Stop.class); - tasks.remove(Start.class); - - startStatusUpdate(); - if (jukeboxStatus != null) { - jukeboxStatus.setPositionSeconds(seconds); - } - tasks.add(new Skip(downloadService.getCurrentPlayingIndex(), seconds)); - downloadService.setPlayerState(PlayerState.STARTED); - } - @Override - public void changeTrack(int index, DownloadFile song) { - tasks.remove(Skip.class); - tasks.remove(Stop.class); - tasks.remove(Start.class); - - startStatusUpdate(); - tasks.add(new Skip(index, 0)); - downloadService.setPlayerState(PlayerState.STARTED); - } - @Override - public void setVolume(int volume) { - gain = volume / 10.0f; - - tasks.remove(SetGain.class); - tasks.add(new SetGain(gain)); - } - @Override - public void updateVolume(boolean up) { - float delta = up ? 0.1f : -0.1f; - gain += delta; - gain = Math.max(gain, 0.0f); - gain = Math.min(gain, 1.0f); - - tasks.remove(SetGain.class); - tasks.add(new SetGain(gain)); - } - @Override - public double getVolume() { - return gain; - } - - @Override - public int getRemotePosition() { - if (jukeboxStatus == null || jukeboxStatus.getPositionSeconds() == null || timeOfLastUpdate.get() == 0) { - return 0; - } - - if (jukeboxStatus.isPlaying()) { - int secondsSinceLastUpdate = (int) ((System.currentTimeMillis() - timeOfLastUpdate.get()) / 1000L); - return jukeboxStatus.getPositionSeconds() + secondsSinceLastUpdate; - } - - return jukeboxStatus.getPositionSeconds(); - } - - private void processTasks() { - while (running) { - RemoteTask task = null; - try { - task = tasks.take(); - RemoteStatus status = task.execute(); - if(status != null && running) { - onStatusUpdate(status); - } - } catch (Throwable x) { - onError(task, x); - } - } - } - - private synchronized void startStatusUpdate() { - stopStatusUpdate(); - Runnable updateTask = new Runnable() { - @Override - public void run() { - tasks.remove(GetStatus.class); - tasks.add(new GetStatus()); - } - }; - statusUpdateFuture = executorService.scheduleWithFixedDelay(updateTask, STATUS_UPDATE_INTERVAL_SECONDS, - STATUS_UPDATE_INTERVAL_SECONDS, TimeUnit.SECONDS); - } - - private synchronized void stopStatusUpdate() { - if (statusUpdateFuture != null) { - statusUpdateFuture.cancel(false); - statusUpdateFuture = null; - } - } - - private void onStatusUpdate(RemoteStatus jukeboxStatus) { - timeOfLastUpdate.set(System.currentTimeMillis()); - this.jukeboxStatus = jukeboxStatus; - - // Track change? - Integer index = jukeboxStatus.getCurrentPlayingIndex(); - if (index != null && index != -1 && index != downloadService.getCurrentPlayingIndex()) { - downloadService.setPlayerState(PlayerState.COMPLETED); - downloadService.setCurrentPlaying(index, true); - if(jukeboxStatus.isPlaying()) { - downloadService.setPlayerState(PlayerState.STARTED); - } - } - } - - private void onError(RemoteTask task, Throwable x) { - if (x instanceof ServerTooOldException && !(task instanceof Stop)) { - disableJukeboxOnError(x, R.string.download_jukebox_server_too_old); - } else if (x instanceof OfflineException && !(task instanceof Stop)) { - disableJukeboxOnError(x, R.string.download_jukebox_offline); - } else if (x instanceof SubsonicRESTException && ((SubsonicRESTException) x).getCode() == 50 && !(task instanceof Stop)) { - disableJukeboxOnError(x, R.string.download_jukebox_not_authorized); - } else { - Log.e(TAG, "Failed to process jukebox task: " + x, x); - } - } - - private void disableJukeboxOnError(Throwable x, final int resourceId) { - Log.w(TAG, x.toString()); - handler.post(new Runnable() { - @Override - public void run() { - Util.toast(downloadService, resourceId, false); - downloadService.setRemoteEnabled(RemoteControlState.LOCAL); - } - }); - } - - private MusicService getMusicService() { - return MusicServiceFactory.getMusicService(downloadService); - } - - private class GetStatus extends RemoteTask { - @Override - RemoteStatus execute() throws Exception { - return getMusicService().getJukeboxStatus(downloadService, null); - } - } - - private class SetPlaylist extends RemoteTask { - private final List ids; - - SetPlaylist(List ids) { - this.ids = ids; - } - - @Override - RemoteStatus execute() throws Exception { - return getMusicService().updateJukeboxPlaylist(ids, downloadService, null); - } - } - - private class Skip extends RemoteTask { - private final int index; - private final int offsetSeconds; - - Skip(int index, int offsetSeconds) { - this.index = index; - this.offsetSeconds = offsetSeconds; - } - - @Override - RemoteStatus execute() throws Exception { - return getMusicService().skipJukebox(index, offsetSeconds, downloadService, null); - } - } - - private class Stop extends RemoteTask { - @Override - RemoteStatus execute() throws Exception { - return getMusicService().stopJukebox(downloadService, null); - } - } - - private class Start extends RemoteTask { - @Override - RemoteStatus execute() throws Exception { - return getMusicService().startJukebox(downloadService, null); - } - } - - private class SetGain extends RemoteTask { - private final float gain; - - private SetGain(float gain) { - this.gain = gain; - } - - @Override - RemoteStatus execute() throws Exception { - return getMusicService().setJukeboxGain(gain, downloadService, null); - } - } - - private class ShutdownTask extends RemoteTask { - @Override - RemoteStatus execute() throws Exception { - return null; - } - } -} diff --git a/src/github/daneren2005/dsub/service/MediaStoreService.java b/src/github/daneren2005/dsub/service/MediaStoreService.java deleted file mode 100644 index 0aa3269f..00000000 --- a/src/github/daneren2005/dsub/service/MediaStoreService.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -import java.io.File; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.provider.MediaStore; -import android.util.Log; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Util; - -/** - * @author Sindre Mehus - */ -public class MediaStoreService { - - private static final String TAG = MediaStoreService.class.getSimpleName(); - private static final Uri ALBUM_ART_URI = Uri.parse("content://media/external/audio/albumart"); - - private final Context context; - - public MediaStoreService(Context context) { - this.context = context; - } - - public void saveInMediaStore(DownloadFile downloadFile) { - MusicDirectory.Entry song = downloadFile.getSong(); - File songFile = downloadFile.getCompleteFile(); - - // Delete existing row in case the song has been downloaded before. - deleteFromMediaStore(downloadFile); - - ContentResolver contentResolver = context.getContentResolver(); - ContentValues values = new ContentValues(); - if(!song.isVideo()) { - values.put(MediaStore.MediaColumns.TITLE, song.getTitle()); - values.put(MediaStore.MediaColumns.DATA, songFile.getAbsolutePath()); - values.put(MediaStore.Audio.AudioColumns.ARTIST, song.getArtist()); - values.put(MediaStore.Audio.AudioColumns.ALBUM, song.getAlbum()); - if (song.getDuration() != null) { - values.put(MediaStore.Audio.AudioColumns.DURATION, song.getDuration() * 1000L); - } - if (song.getTrack() != null) { - values.put(MediaStore.Audio.AudioColumns.TRACK, song.getTrack()); - } - if (song.getYear() != null) { - values.put(MediaStore.Audio.AudioColumns.YEAR, song.getYear()); - } - if(song.getTranscodedContentType() != null) { - values.put(MediaStore.MediaColumns.MIME_TYPE, song.getTranscodedContentType()); - } else { - values.put(MediaStore.MediaColumns.MIME_TYPE, song.getContentType()); - } - values.put(MediaStore.Audio.AudioColumns.IS_MUSIC, 1); - - Uri uri = contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values); - - // Look up album, and add cover art if found. - Cursor cursor = contentResolver.query(uri, new String[]{MediaStore.Audio.AudioColumns.ALBUM_ID}, null, null, null); - if (cursor.moveToFirst()) { - int albumId = cursor.getInt(0); - insertAlbumArt(albumId, downloadFile); - } - - cursor.close(); - } else { - values.put(MediaStore.Video.VideoColumns.TITLE, song.getTitle()); - values.put(MediaStore.Video.VideoColumns.DISPLAY_NAME, song.getTitle()); - values.put(MediaStore.Video.VideoColumns.ARTIST, song.getArtist()); - values.put(MediaStore.Video.VideoColumns.DATA, songFile.getAbsolutePath()); - if (song.getDuration() != null) { - values.put(MediaStore.Video.VideoColumns.DURATION, song.getDuration() * 1000L); - } - - String videoPlayerType = Util.getVideoPlayerType(context); - if("hls".equals(videoPlayerType)) { - // HLS should be able to transcode to mp4 automatically - values.put(MediaStore.MediaColumns.MIME_TYPE, "video/mpeg"); - } else if("raw".equals(videoPlayerType) || song.getTranscodedContentType() == null) { - // Download the original video without any transcoding - values.put(MediaStore.MediaColumns.MIME_TYPE, song.getContentType()); - } else { - values.put(MediaStore.MediaColumns.MIME_TYPE, song.getTranscodedContentType()); - } - - Uri uri = contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values); - if(uri == null) { - Log.e(TAG, "Failed to insert"); - } - } - } - - public void deleteFromMediaStore(DownloadFile downloadFile) { - ContentResolver contentResolver = context.getContentResolver(); - MusicDirectory.Entry song = downloadFile.getSong(); - File file = downloadFile.getCompleteFile(); - - Uri uri; - if(song.isVideo()) { - uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; - } else { - uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; - } - - int n = contentResolver.delete(uri, - MediaStore.MediaColumns.DATA + "=?", - new String[]{file.getAbsolutePath()}); - if (n > 0) { - Log.i(TAG, "Deleting media store row for " + song); - } - } - - public void deleteFromMediaStore(File file) { - ContentResolver contentResolver = context.getContentResolver(); - - Uri uri; - if(FileUtil.isVideoFile(file)) { - uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; - } else { - uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; - } - - int n = contentResolver.delete(uri, - MediaStore.MediaColumns.DATA + "=?", - new String[]{file.getAbsolutePath()}); - if (n > 0) { - Log.i(TAG, "Deleting media store row for " + file); - } - } - - public void renameInMediaStore(File start, File end) { - ContentResolver contentResolver = context.getContentResolver(); - - ContentValues values = new ContentValues(); - values.put(MediaStore.MediaColumns.DATA, end.getAbsolutePath()); - - int n = contentResolver.update(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, - values, - MediaStore.MediaColumns.DATA + "=?", - new String[]{start.getAbsolutePath()}); - if (n > 0) { - Log.i(TAG, "Rename media store row for " + start + " to " + end); - } - } - - private void insertAlbumArt(int albumId, DownloadFile downloadFile) { - ContentResolver contentResolver = context.getContentResolver(); - - Cursor cursor = contentResolver.query(Uri.withAppendedPath(ALBUM_ART_URI, String.valueOf(albumId)), null, null, null, null); - if (!cursor.moveToFirst()) { - - // No album art found, add it. - File albumArtFile = FileUtil.getAlbumArtFile(context, downloadFile.getSong()); - if (albumArtFile.exists()) { - ContentValues values = new ContentValues(); - values.put(MediaStore.Audio.AlbumColumns.ALBUM_ID, albumId); - values.put(MediaStore.MediaColumns.DATA, albumArtFile.getPath()); - contentResolver.insert(ALBUM_ART_URI, values); - Log.i(TAG, "Added album art: " + albumArtFile); - } - } - cursor.close(); - } - -} diff --git a/src/github/daneren2005/dsub/service/MusicService.java b/src/github/daneren2005/dsub/service/MusicService.java deleted file mode 100644 index 4d014462..00000000 --- a/src/github/daneren2005/dsub/service/MusicService.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -import java.util.List; - -import org.apache.http.HttpResponse; - -import android.content.Context; -import android.graphics.Bitmap; - -import github.daneren2005.dsub.domain.ArtistInfo; -import github.daneren2005.dsub.domain.Bookmark; -import github.daneren2005.dsub.domain.ChatMessage; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.PlayerQueue; -import github.daneren2005.dsub.domain.RemoteStatus; -import github.daneren2005.dsub.domain.Lyrics; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.MusicFolder; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.domain.SearchCritera; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.domain.Share; -import github.daneren2005.dsub.domain.User; -import github.daneren2005.dsub.domain.Version; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.ProgressListener; - -/** - * @author Sindre Mehus - */ -public interface MusicService { - - void ping(Context context, ProgressListener progressListener) throws Exception; - - boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception; - - List getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - void startRescan(Context context, ProgressListener listener) throws Exception; - - Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getStarredList(Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getPlaylist(boolean refresh, String id, String name, Context context, ProgressListener progressListener) throws Exception; - - List getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - void createPlaylist(String id, String name, List entries, Context context, ProgressListener progressListener) throws Exception; - - void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception; - - void addToPlaylist(String id, List toAdd, Context context, ProgressListener progressListener) throws Exception; - - void removeFromPlaylist(String id, List toRemove, Context context, ProgressListener progressListener) throws Exception; - - void overwritePlaylist(String id, String name, int toRemove, List toAdd, Context context, ProgressListener progressListener) throws Exception; - - void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception; - - Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception; - - void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getAlbumList(String type, String extra, int size, int offset, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception; - MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception; - - String getCoverArtUrl(Context context, MusicDirectory.Entry entry) throws Exception; - - Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, ProgressListener progressListener, SilentBackgroundTask task) throws Exception; - - HttpResponse getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception; - - String getMusicUrl(Context context, MusicDirectory.Entry song, int maxBitrate) throws Exception; - - String getVideoUrl(int maxBitrate, Context context, String id); - - String getVideoStreamUrl(String format, int Bitrate, Context context, String id) throws Exception; - - String getHlsUrl(String id, int bitRate, Context context) throws Exception; - - RemoteStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception; - - RemoteStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception; - - RemoteStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception; - - RemoteStatus startJukebox(Context context, ProgressListener progressListener) throws Exception; - - RemoteStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception; - - RemoteStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception; - - void setStarred(List entries, List artists, List albums, boolean starred, ProgressListener progressListener, Context context) throws Exception; - - List getShares(Context context, ProgressListener progressListener) throws Exception; - - List createShare(List ids, String description, Long expires, Context context, ProgressListener progressListener) throws Exception; - - void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception; - - void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception; - - List getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception; - - void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception; - - List getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getTopTrackSongs(String artist, int size, Context context, ProgressListener progressListener) throws Exception; - - List getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getPodcastEpisodes(boolean refresh, String id, Context context, ProgressListener progressListener) throws Exception; - - void refreshPodcasts(Context context, ProgressListener progressListener) throws Exception; - - void createPodcastChannel(String url, Context context, ProgressListener progressListener) throws Exception; - - void deletePodcastChannel(String id, Context context, ProgressListener progressListener) throws Exception; - - void downloadPodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception; - - void deletePodcastEpisode(String id, String parent, ProgressListener progressListener, Context context) throws Exception; - - void setRating(MusicDirectory.Entry entry, int rating, Context context, ProgressListener progressListener) throws Exception; - - MusicDirectory getBookmarks(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - void createBookmark(MusicDirectory.Entry entry, int position, String comment, Context context, ProgressListener progressListener) throws Exception; - - void deleteBookmark(MusicDirectory.Entry entry, Context context, ProgressListener progressListener) throws Exception; - - User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception; - - List getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - void createUser(User user, Context context, ProgressListener progressListener) throws Exception; - - void updateUser(User user, Context context, ProgressListener progressListener) throws Exception; - - void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception; - - void changeEmail(String username, String email, Context context, ProgressListener progressListener) throws Exception; - - void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception; - - Bitmap getAvatar(String username, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception; - - ArtistInfo getArtistInfo(String id, boolean refresh, boolean allowNetwork, Context context, ProgressListener progressListener) throws Exception; - - Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception; - - MusicDirectory getVideos(boolean refresh, Context context, ProgressListener progressListener) throws Exception; - - void savePlayQueue(List songs, MusicDirectory.Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception; - - PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception; - - int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception; - - void setInstance(Integer instance) throws Exception; -} diff --git a/src/github/daneren2005/dsub/service/MusicServiceFactory.java b/src/github/daneren2005/dsub/service/MusicServiceFactory.java deleted file mode 100644 index e04522ff..00000000 --- a/src/github/daneren2005/dsub/service/MusicServiceFactory.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -import android.content.Context; -import github.daneren2005.dsub.util.Util; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public class MusicServiceFactory { - - private static final MusicService REST_MUSIC_SERVICE = new CachedMusicService(new RESTMusicService()); - private static final MusicService OFFLINE_MUSIC_SERVICE = new OfflineMusicService(); - - public static MusicService getMusicService(Context context) { - return Util.isOffline(context) ? OFFLINE_MUSIC_SERVICE : REST_MUSIC_SERVICE; - } -} diff --git a/src/github/daneren2005/dsub/service/OfflineException.java b/src/github/daneren2005/dsub/service/OfflineException.java deleted file mode 100644 index e3a8d460..00000000 --- a/src/github/daneren2005/dsub/service/OfflineException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -/** - * Thrown by service methods that are not available in offline mode. - * - * @author Sindre Mehus - * @version $Id$ - */ -public class OfflineException extends Exception { - - public OfflineException(String message) { - super(message); - } -} diff --git a/src/github/daneren2005/dsub/service/OfflineMusicService.java b/src/github/daneren2005/dsub/service/OfflineMusicService.java deleted file mode 100644 index b4105d07..00000000 --- a/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ /dev/null @@ -1,836 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -import java.io.File; -import java.io.Reader; -import java.io.FileReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Random; -import java.util.Set; - -import android.content.Context; -import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.util.Log; - -import org.apache.http.HttpResponse; - -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.ArtistInfo; -import github.daneren2005.dsub.domain.ChatMessage; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.PlayerQueue; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.domain.RemoteStatus; -import github.daneren2005.dsub.domain.Lyrics; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.MusicFolder; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.domain.SearchCritera; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.domain.Share; -import github.daneren2005.dsub.domain.User; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.Util; -import java.io.*; -import java.util.Comparator; -import java.util.SortedSet; - -/** - * @author Sindre Mehus - */ -public class OfflineMusicService implements MusicService { - private static final String TAG = OfflineMusicService.class.getSimpleName(); - private static final String ERRORMSG = "Not available in offline mode"; - private static final Random random = new Random(); - - @Override - public void ping(Context context, ProgressListener progressListener) throws Exception { - - } - - @Override - public boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception { - return true; - } - - @Override - public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List artists = new ArrayList(); - File root = FileUtil.getMusicDirectory(context); - for (File file : FileUtil.listFiles(root)) { - if (file.isDirectory()) { - Artist artist = new Artist(); - artist.setId(file.getPath()); - artist.setIndex(file.getName().substring(0, 1)); - artist.setName(file.getName()); - artists.add(artist); - } - } - - Indexes indexes = new Indexes(0L, Collections.emptyList(), artists); - indexes.sortChildren(context); - return indexes; - } - - @Override - public MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - return getMusicDirectory(id, artistName, refresh, context, progressListener, false); - } - private MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener, boolean isPodcast) throws Exception { - File dir = new File(id); - MusicDirectory result = new MusicDirectory(); - result.setName(dir.getName()); - - Set names = new HashSet(); - - for (File file : FileUtil.listMediaFiles(dir)) { - String name = getName(file); - if (name != null & !names.contains(name)) { - names.add(name); - result.addChild(createEntry(context, file, name, true, isPodcast)); - } - } - result.sortChildren(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_CUSTOM_SORT_ENABLED, true)); - return result; - } - - @Override - public MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - private String getName(File file) { - String name = file.getName(); - if (file.isDirectory()) { - return name; - } - - if (name.endsWith(".partial") || name.contains(".partial.") || name.equals(Constants.ALBUM_ART_FILE)) { - return null; - } - - name = name.replace(".complete", ""); - return FileUtil.getBaseName(name); - } - - private MusicDirectory.Entry createEntry(Context context, File file, String name) { - return createEntry(context, file, name, true); - } - private MusicDirectory.Entry createEntry(Context context, File file, String name, boolean load) { - return createEntry(context, file, name, load, false); - } - private MusicDirectory.Entry createEntry(Context context, File file, String name, boolean load, boolean isPodcast) { - MusicDirectory.Entry entry; - if(isPodcast) { - PodcastEpisode episode = new PodcastEpisode(); - episode.setStatus("completed"); - entry = episode; - } else { - entry = new MusicDirectory.Entry(); - } - entry.setDirectory(file.isDirectory()); - entry.setId(file.getPath()); - entry.setParent(file.getParent()); - entry.setSize(file.length()); - String root = FileUtil.getMusicDirectory(context).getPath(); - if(!file.getParentFile().getParentFile().getPath().equals(root)) { - entry.setGrandParent(file.getParentFile().getParent()); - } - entry.setPath(file.getPath().replaceFirst("^" + root + "/" , "")); - String title = name; - if (file.isFile()) { - File artistFolder = file.getParentFile().getParentFile(); - File albumFolder = file.getParentFile(); - if(artistFolder.getPath().equals(root)) { - entry.setArtist(albumFolder.getName()); - } else { - entry.setArtist(artistFolder.getName()); - } - entry.setAlbum(albumFolder.getName()); - - int index = name.indexOf('-'); - if(index != -1) { - try { - entry.setTrack(Integer.parseInt(name.substring(0, index))); - title = title.substring(index + 1); - } catch(Exception e) { - // Failed parseInt, just means track filled out - } - } - - if(load) { - entry.loadMetadata(file); - } - } - - entry.setTitle(title); - entry.setSuffix(FileUtil.getExtension(file.getName().replace(".complete", ""))); - - File albumArt = FileUtil.getAlbumArtFile(context, entry); - if (albumArt.exists()) { - entry.setCoverArt(albumArt.getPath()); - } - if(FileUtil.isVideoFile(file)) { - entry.setVideo(true); - } - return entry; - } - - @Override - public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, ProgressListener progressListener, SilentBackgroundTask task) throws Exception { - try { - return FileUtil.getAlbumArtBitmap(context, entry, size); - } catch(Exception e) { - return null; - } - } - - @Override - public HttpResponse getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public String getMusicUrl(Context context, MusicDirectory.Entry song, int maxBitrate) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public List getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void startRescan(Context context, ProgressListener listener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception { - List artists = new ArrayList(); - List albums = new ArrayList(); - List songs = new ArrayList(); - File root = FileUtil.getMusicDirectory(context); - int closeness = 0; - for (File artistFile : FileUtil.listFiles(root)) { - String artistName = artistFile.getName(); - if (artistFile.isDirectory()) { - if((closeness = matchCriteria(criteria, artistName)) > 0) { - Artist artist = new Artist(); - artist.setId(artistFile.getPath()); - artist.setIndex(artistFile.getName().substring(0, 1)); - artist.setName(artistName); - artist.setCloseness(closeness); - artists.add(artist); - } - - recursiveAlbumSearch(artistName, artistFile, criteria, context, albums, songs); - } - } - - Collections.sort(artists, new Comparator() { - public int compare(Artist lhs, Artist rhs) { - if(lhs.getCloseness() == rhs.getCloseness()) { - return 0; - } - else if(lhs.getCloseness() > rhs.getCloseness()) { - return -1; - } - else { - return 1; - } - } - }); - Collections.sort(albums, new Comparator() { - public int compare(MusicDirectory.Entry lhs, MusicDirectory.Entry rhs) { - if(lhs.getCloseness() == rhs.getCloseness()) { - return 0; - } - else if(lhs.getCloseness() > rhs.getCloseness()) { - return -1; - } - else { - return 1; - } - } - }); - Collections.sort(songs, new Comparator() { - public int compare(MusicDirectory.Entry lhs, MusicDirectory.Entry rhs) { - if(lhs.getCloseness() == rhs.getCloseness()) { - return 0; - } - else if(lhs.getCloseness() > rhs.getCloseness()) { - return -1; - } - else { - return 1; - } - } - }); - - return new SearchResult(artists, albums, songs); - } - - @Override - public MusicDirectory getStarredList(Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - private void recursiveAlbumSearch(String artistName, File file, SearchCritera criteria, Context context, List albums, List songs) { - int closeness; - for(File albumFile : FileUtil.listMediaFiles(file)) { - if(albumFile.isDirectory()) { - String albumName = getName(albumFile); - if((closeness = matchCriteria(criteria, albumName)) > 0) { - MusicDirectory.Entry album = createEntry(context, albumFile, albumName); - album.setArtist(artistName); - album.setCloseness(closeness); - albums.add(album); - } - - for(File songFile : FileUtil.listMediaFiles(albumFile)) { - String songName = getName(songFile); - if(songName == null) { - continue; - } - - if(songFile.isDirectory()) { - recursiveAlbumSearch(artistName, songFile, criteria, context, albums, songs); - } - else if((closeness = matchCriteria(criteria, songName)) > 0){ - MusicDirectory.Entry song = createEntry(context, albumFile, songName); - song.setArtist(artistName); - song.setAlbum(albumName); - song.setCloseness(closeness); - songs.add(song); - } - } - } - else { - String songName = getName(albumFile); - if((closeness = matchCriteria(criteria, songName)) > 0) { - MusicDirectory.Entry song = createEntry(context, albumFile, songName); - song.setArtist(artistName); - song.setAlbum(songName); - song.setCloseness(closeness); - songs.add(song); - } - } - } - } - private int matchCriteria(SearchCritera criteria, String name) { - String query = criteria.getQuery().toLowerCase(); - String[] queryParts = query.split(" "); - String[] nameParts = name.toLowerCase().split(" "); - - int closeness = 0; - for(String queryPart : queryParts) { - for(String namePart : nameParts) { - if(namePart.equals(queryPart)) { - closeness++; - } - } - } - - return closeness; - } - - @Override - public List getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List playlists = new ArrayList(); - File root = FileUtil.getPlaylistDirectory(context); - String lastServer = null; - boolean removeServer = true; - for (File folder : FileUtil.listFiles(root)) { - if(folder.isDirectory()) { - String server = folder.getName(); - SortedSet fileList = FileUtil.listFiles(folder); - for(File file: fileList) { - if(FileUtil.isPlaylistFile(file)) { - String id = file.getName(); - String filename = server + ": " + FileUtil.getBaseName(id); - Playlist playlist = new Playlist(server, filename); - playlists.add(playlist); - } - } - - if(!server.equals(lastServer) && fileList.size() > 0) { - if(lastServer != null) { - removeServer = false; - } - lastServer = server; - } - } else { - // Delete legacy playlist files - try { - folder.delete(); - } catch(Exception e) { - Log.w(TAG, "Failed to delete old playlist file: " + folder.getName()); - } - } - } - - if(removeServer) { - for(Playlist playlist: playlists) { - playlist.setName(playlist.getName().substring(playlist.getId().length() + 2)); - } - } - return playlists; - } - - @Override - public MusicDirectory getPlaylist(boolean refresh, String id, String name, Context context, ProgressListener progressListener) throws Exception { - DownloadService downloadService = DownloadService.getInstance(); - if (downloadService == null) { - return new MusicDirectory(); - } - - Reader reader = null; - BufferedReader buffer = null; - try { - int firstIndex = name.indexOf(id); - if(firstIndex != -1) { - name = name.substring(id.length() + 2); - } - - File playlistFile = FileUtil.getPlaylistFile(context, id, name); - reader = new FileReader(playlistFile); - buffer = new BufferedReader(reader); - - MusicDirectory playlist = new MusicDirectory(); - String line = buffer.readLine(); - if(!"#EXTM3U".equals(line)) return playlist; - - while( (line = buffer.readLine()) != null ){ - // No matter what, end file can't have .complete in it - line = line.replace(".complete", ""); - File entryFile = new File(line); - - // Don't add file to playlist if it doesn't exist as cached or pinned! - File checkFile = entryFile; - if(!checkFile.exists()) { - // If normal file doens't exist, check if .complete version does - checkFile = new File(entryFile.getParent(), FileUtil.getBaseName(entryFile.getName()) - + ".complete." + FileUtil.getExtension(entryFile.getName())); - } - - String entryName = getName(entryFile); - if(checkFile.exists() && entryName != null){ - playlist.addChild(createEntry(context, entryFile, entryName, false)); - } - } - - return playlist; - } finally { - Util.close(buffer); - Util.close(reader); - } - } - - @Override - public void createPlaylist(String id, String name, List entries, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void addToPlaylist(String id, List toAdd, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void removeFromPlaylist(String id, List toRemove, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void overwritePlaylist(String id, String name, int toRemove, List toAdd, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception { - if(!submission) { - return; - } - - SharedPreferences prefs = Util.getPreferences(context); - String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - - SharedPreferences offline = Util.getOfflineSync(context); - int scrobbles = offline.getInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); - scrobbles++; - SharedPreferences.Editor offlineEditor = offline.edit(); - - if(id.indexOf(cacheLocn) != -1) { - String scrobbleSearchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn); - offlineEditor.putString(Constants.OFFLINE_SCROBBLE_SEARCH + scrobbles, scrobbleSearchCriteria); - offlineEditor.remove(Constants.OFFLINE_SCROBBLE_ID + scrobbles); - } else { - offlineEditor.putString(Constants.OFFLINE_SCROBBLE_ID + scrobbles, id); - offlineEditor.remove(Constants.OFFLINE_SCROBBLE_SEARCH + scrobbles); - } - - offlineEditor.putLong(Constants.OFFLINE_SCROBBLE_TIME + scrobbles, System.currentTimeMillis()); - offlineEditor.putInt(Constants.OFFLINE_SCROBBLE_COUNT, scrobbles); - offlineEditor.commit(); - } - - @Override - public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public MusicDirectory getAlbumList(String type, String extra, int size, int offset, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public String getVideoUrl(int maxBitrate, Context context, String id) { - return null; - } - - @Override - public String getVideoStreamUrl(String format, int maxBitrate, Context context, String id) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public String getHlsUrl(String id, int bitRate, Context context) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public RemoteStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public RemoteStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public RemoteStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public RemoteStatus startJukebox(Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public RemoteStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public RemoteStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void setStarred(List entries, List artists, List albums, boolean starred, ProgressListener progressListener, Context context) throws Exception { - SharedPreferences prefs = Util.getPreferences(context); - String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - - SharedPreferences offline = Util.getOfflineSync(context); - int stars = offline.getInt(Constants.OFFLINE_STAR_COUNT, 0); - stars++; - SharedPreferences.Editor offlineEditor = offline.edit(); - - String id = entries.get(0).getId(); - if(id.indexOf(cacheLocn) != -1) { - String searchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn); - offlineEditor.putString(Constants.OFFLINE_STAR_SEARCH + stars, searchCriteria); - offlineEditor.remove(Constants.OFFLINE_STAR_ID + stars); - } else { - offlineEditor.putString(Constants.OFFLINE_STAR_ID + stars, id); - offlineEditor.remove(Constants.OFFLINE_STAR_SEARCH + stars); - } - - offlineEditor.putBoolean(Constants.OFFLINE_STAR_SETTING + stars, starred); - offlineEditor.putInt(Constants.OFFLINE_STAR_COUNT, stars); - offlineEditor.commit(); - } - - @Override - public List getShares(Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public List createShare(List ids, String description, Long expires, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public List getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public List getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public MusicDirectory getTopTrackSongs(String artist, int size, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception { - File root = FileUtil.getMusicDirectory(context); - List children = new LinkedList(); - listFilesRecursively(root, children); - MusicDirectory result = new MusicDirectory(); - - if (children.isEmpty()) { - return result; - } - for (int i = 0; i < size; i++) { - File file = children.get(random.nextInt(children.size())); - result.addChild(createEntry(context, file, getName(file))); - } - - return result; - } - - @Override - public String getCoverArtUrl(Context context, MusicDirectory.Entry entry) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public List getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List channels = new ArrayList(); - - File dir = FileUtil.getPodcastDirectory(context); - String line; - for(File file: dir.listFiles()) { - BufferedReader br = new BufferedReader(new FileReader(file)); - while ((line = br.readLine()) != null && !"".equals(line)) { - PodcastChannel channel = new PodcastChannel(); - channel.setId(line); - channel.setName(line); - channel.setStatus("completed"); - - if(FileUtil.getPodcastDirectory(context, channel).exists() && !channels.contains(channel)) { - channels.add(channel); - } - } - br.close(); - } - - return channels; - } - - @Override - public MusicDirectory getPodcastEpisodes(boolean refresh, String id, Context context, ProgressListener progressListener) throws Exception { - return getMusicDirectory(FileUtil.getPodcastDirectory(context, id).getPath(), null, false, context, progressListener, true); - } - - @Override - public void refreshPodcasts(Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void createPodcastChannel(String url, Context context, ProgressListener progressListener) throws Exception{ - throw new OfflineException(ERRORMSG); - } - - @Override - public void deletePodcastChannel(String id, Context context, ProgressListener progressListener) throws Exception{ - throw new OfflineException(ERRORMSG); - } - - @Override - public void downloadPodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{ - throw new OfflineException(ERRORMSG); - } - - @Override - public void deletePodcastEpisode(String id, String parent, ProgressListener progressListener, Context context) throws Exception{ - throw new OfflineException(ERRORMSG); - } - - @Override - public void setRating(MusicDirectory.Entry entry, int rating, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public MusicDirectory getBookmarks(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void createBookmark(MusicDirectory.Entry entry, int position, String comment, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void deleteBookmark(MusicDirectory.Entry entry, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public List getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void createUser(User user, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void updateUser(User user, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void changeEmail(String username, String email, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public Bitmap getAvatar(String username, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public ArtistInfo getArtistInfo(String id, boolean refresh, boolean allowNetwork, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public MusicDirectory getVideos(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public void savePlayQueue(List songs, MusicDirectory.Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception { - throw new OfflineException(ERRORMSG); - } - - @Override - public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ - throw new OfflineException(ERRORMSG); - } - - @Override - public void setInstance(Integer instance) throws Exception{ - throw new OfflineException(ERRORMSG); - } - - private void listFilesRecursively(File parent, List children) { - for (File file : FileUtil.listMediaFiles(parent)) { - if (file.isFile()) { - children.add(file); - } else { - listFilesRecursively(file, children); - } - } - } -} diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java deleted file mode 100644 index 459c8c9e..00000000 --- a/src/github/daneren2005/dsub/service/RESTMusicService.java +++ /dev/null @@ -1,1991 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.conn.params.ConnManagerParams; -import org.apache.http.conn.params.ConnPerRouteBean; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.scheme.SocketFactory; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; -import org.apache.http.message.BasicHeader; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.ExecutionContext; -import org.apache.http.protocol.HttpContext; - -import android.content.Context; -import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.os.Looper; -import android.util.Log; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.*; -import github.daneren2005.dsub.service.parser.AlbumListParser; -import github.daneren2005.dsub.service.parser.ArtistInfoParser; -import github.daneren2005.dsub.service.parser.BookmarkParser; -import github.daneren2005.dsub.service.parser.ChatMessageParser; -import github.daneren2005.dsub.service.parser.ErrorParser; -import github.daneren2005.dsub.service.parser.GenreParser; -import github.daneren2005.dsub.service.parser.IndexesParser; -import github.daneren2005.dsub.service.parser.JukeboxStatusParser; -import github.daneren2005.dsub.service.parser.LicenseParser; -import github.daneren2005.dsub.service.parser.LyricsParser; -import github.daneren2005.dsub.service.parser.MusicDirectoryParser; -import github.daneren2005.dsub.service.parser.MusicFoldersParser; -import github.daneren2005.dsub.service.parser.PlayQueueParser; -import github.daneren2005.dsub.service.parser.PlaylistParser; -import github.daneren2005.dsub.service.parser.PlaylistsParser; -import github.daneren2005.dsub.service.parser.PodcastChannelParser; -import github.daneren2005.dsub.service.parser.PodcastEntryParser; -import github.daneren2005.dsub.service.parser.RandomSongsParser; -import github.daneren2005.dsub.service.parser.ScanStatusParser; -import github.daneren2005.dsub.service.parser.SearchResult2Parser; -import github.daneren2005.dsub.service.parser.SearchResultParser; -import github.daneren2005.dsub.service.parser.ShareParser; -import github.daneren2005.dsub.service.parser.StarredListParser; -import github.daneren2005.dsub.service.parser.UserParser; -import github.daneren2005.dsub.service.parser.VideosParser; -import github.daneren2005.dsub.service.ssl.SSLSocketFactory; -import github.daneren2005.dsub.service.ssl.TrustSelfSignedStrategy; -import github.daneren2005.dsub.util.BackgroundTask; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.Util; -import java.io.*; -import java.util.zip.GZIPInputStream; - -/** - * @author Sindre Mehus - */ -public class RESTMusicService implements MusicService { - - private static final String TAG = RESTMusicService.class.getSimpleName(); - - private static final int SOCKET_CONNECT_TIMEOUT = 10 * 1000; - private static final int SOCKET_READ_TIMEOUT_DEFAULT = 10 * 1000; - private static final int SOCKET_READ_TIMEOUT_DOWNLOAD = 30 * 1000; - private static final int SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS = 60 * 1000; - private static final int SOCKET_READ_TIMEOUT_GET_PLAYLIST = 60 * 1000; - - // Allow 20 seconds extra timeout per MB offset. - private static final double TIMEOUT_MILLIS_PER_OFFSET_BYTE = 20000.0 / 1000000.0; - - private static final int HTTP_REQUEST_MAX_ATTEMPTS = 5; - private static final long REDIRECTION_CHECK_INTERVAL_MILLIS = 60L * 60L * 1000L; - - private final DefaultHttpClient httpClient; - private long redirectionLastChecked; - private int redirectionNetworkType = -1; - private String redirectFrom; - private String redirectTo; - private final ThreadSafeClientConnManager connManager; - private Integer instance; - - public RESTMusicService() { - - // Create and initialize default HTTP parameters - HttpParams params = new BasicHttpParams(); - ConnManagerParams.setMaxTotalConnections(params, 20); - ConnManagerParams.setMaxConnectionsPerRoute(params, new ConnPerRouteBean(20)); - HttpConnectionParams.setConnectionTimeout(params, SOCKET_CONNECT_TIMEOUT); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_DEFAULT); - - // Turn off stale checking. Our connections break all the time anyway, - // and it's not worth it to pay the penalty of checking every time. - HttpConnectionParams.setStaleCheckingEnabled(params, false); - - // Create and initialize scheme registry - SchemeRegistry schemeRegistry = new SchemeRegistry(); - schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - schemeRegistry.register(new Scheme("https", createSSLSocketFactory(), 443)); - - // Create an HttpClient with the ThreadSafeClientConnManager. - // This connection manager must be used if more than one thread will - // be using the HttpClient. - connManager = new ThreadSafeClientConnManager(params, schemeRegistry); - httpClient = new DefaultHttpClient(connManager, params); - } - - private SocketFactory createSSLSocketFactory() { - try { - return new SSLSocketFactory(new TrustSelfSignedStrategy(), SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); - } catch (Throwable x) { - Log.e(TAG, "Failed to create custom SSL socket factory, using default.", x); - return org.apache.http.conn.ssl.SSLSocketFactory.getSocketFactory(); - } - } - - @Override - public void ping(Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "ping", null); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public boolean isLicenseValid(Context context, ProgressListener progressListener) throws Exception { - - Reader reader = getReader(context, progressListener, "getLicense", null); - try { - ServerInfo serverInfo = new LicenseParser(context, getInstance(context)).parse(reader); - return serverInfo.isLicenseValid(); - } finally { - Util.close(reader); - } - } - - public List getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getMusicFolders", null); - try { - return new MusicFoldersParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public void startRescan(Context context, ProgressListener listener) throws Exception { - Reader reader = getReader(context, listener, "startRescan", null); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - - // Now check if still running - boolean done = false; - while(!done) { - reader = getReader(context, null, "scanstatus", null); - try { - boolean running = new ScanStatusParser(context, getInstance(context)).parse(reader, listener); - if(running) { - // Don't run system ragged trying to query too much - Thread.sleep(100L); - } else { - done = true; - } - } catch(Exception e) { - done = true; - } finally { - Util.close(reader); - } - } - } - - @Override - public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - List parameterNames = new ArrayList(); - List parameterValues = new ArrayList(); - - if (musicFolderId != null) { - parameterNames.add("musicFolderId"); - parameterValues.add(musicFolderId); - } - - Reader reader = getReader(context, progressListener, Util.isTagBrowsing(context, getInstance(context)) ? "getArtists" : "getIndexes", null, parameterNames, parameterValues); - try { - return new IndexesParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - SharedPreferences prefs = Util.getPreferences(context); - String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - if(cacheLocn != null && id.indexOf(cacheLocn) != -1) { - String search = Util.parseOfflineIDSearch(context, id, cacheLocn); - SearchCritera critera = new SearchCritera(search, 1, 1, 0); - SearchResult result = searchNew(critera, context, progressListener); - if(result.getArtists().size() == 1) { - id = result.getArtists().get(0).getId(); - } else if(result.getAlbums().size() == 1) { - id = result.getAlbums().get(0).getId(); - } - } - - MusicDirectory dir = null; - int index, start = 0; - while((index = id.indexOf(';', start)) != -1) { - MusicDirectory extra = getMusicDirectoryImpl(id.substring(start, index), name, refresh, context, progressListener); - if(dir == null) { - dir = extra; - } else { - dir.addChildren(extra.getChildren()); - } - - start = index + 1; - } - MusicDirectory extra = getMusicDirectoryImpl(id.substring(start), name, refresh, context, progressListener); - if(dir == null) { - dir = extra; - } else { - dir.addChildren(extra.getChildren()); - } - - // Apply another sort if we are chaining several together - if(dir != extra) { - dir.sortChildren(context, getInstance(context)); - } - - return dir; - } - - private MusicDirectory getMusicDirectoryImpl(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getMusicDirectory", null, "id", id); - try { - return new MusicDirectoryParser(context, getInstance(context)).parse(name, reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getArtist", null, "id", id); - try { - return new MusicDirectoryParser(context, getInstance(context)).parse(name, reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getAlbum", null, "id", id); - try { - return new MusicDirectoryParser(context, getInstance(context)).parse(name, reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public SearchResult search(SearchCritera critera, Context context, ProgressListener progressListener) throws Exception { - try { - return searchNew(critera, context, progressListener); - } catch (ServerTooOldException x) { - // Ensure backward compatibility with REST 1.3. - return searchOld(critera, context, progressListener); - } - } - - /** - * Search using the "search" REST method. - */ - private SearchResult searchOld(SearchCritera critera, Context context, ProgressListener progressListener) throws Exception { - List parameterNames = Arrays.asList("any", "songCount"); - List parameterValues = Arrays.asList(critera.getQuery(), critera.getSongCount()); - Reader reader = getReader(context, progressListener, "search", null, parameterNames, parameterValues); - try { - return new SearchResultParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - /** - * Search using the "search2" REST method, available in 1.4.0 and later. - */ - private SearchResult searchNew(SearchCritera critera, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.4", null); - - List parameterNames = Arrays.asList("query", "artistCount", "albumCount", "songCount"); - List parameterValues = Arrays.asList(critera.getQuery(), critera.getArtistCount(), - critera.getAlbumCount(), critera.getSongCount()); - Reader reader = getReader(context, progressListener, Util.isTagBrowsing(context, getInstance(context)) ? "search3" : "search2", null, parameterNames, parameterValues); - try { - return new SearchResult2Parser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getPlaylist(boolean refresh, String id, String name, Context context, ProgressListener progressListener) throws Exception { - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_PLAYLIST); - - Reader reader = getReader(context, progressListener, "getPlaylist", params, "id", id); - try { - return new PlaylistParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public List getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getPlaylists", null); - try { - return new PlaylistsParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public void createPlaylist(String id, String name, List entries, Context context, ProgressListener progressListener) throws Exception { - List parameterNames = new LinkedList(); - List parameterValues = new LinkedList(); - - if (id != null) { - parameterNames.add("playlistId"); - parameterValues.add(id); - } - if (name != null) { - parameterNames.add("name"); - parameterValues.add(name); - } - for (MusicDirectory.Entry entry : entries) { - parameterNames.add("songId"); - parameterValues.add(getOfflineSongId(entry.getId(), context, progressListener)); - } - - Reader reader = getReader(context, progressListener, "createPlaylist", null, parameterNames, parameterValues); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "deletePlaylist", null, "id", id); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void addToPlaylist(String id, List toAdd, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Updating playlists is not supported."); - List names = new ArrayList(); - List values = new ArrayList(); - names.add("playlistId"); - values.add(id); - for(MusicDirectory.Entry song: toAdd) { - names.add("songIdToAdd"); - values.add(getOfflineSongId(song.getId(), context, progressListener)); - } - Reader reader = getReader(context, progressListener, "updatePlaylist", null, names, values); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void removeFromPlaylist(String id, List toRemove, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Updating playlists is not supported."); - List names = new ArrayList(); - List values = new ArrayList(); - names.add("playlistId"); - values.add(id); - for(Integer song: toRemove) { - names.add("songIndexToRemove"); - values.add(song); - } - Reader reader = getReader(context, progressListener, "updatePlaylist", null, names, values); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void overwritePlaylist(String id, String name, int toRemove, List toAdd, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Updating playlists is not supported."); - List names = new ArrayList(); - List values = new ArrayList(); - names.add("playlistId"); - values.add(id); - names.add("name"); - values.add(name); - for(MusicDirectory.Entry song: toAdd) { - names.add("songIdToAdd"); - values.add(song.getId()); - } - for(int i = 0; i < toRemove; i++) { - names.add("songIndexToRemove"); - values.add(i); - } - Reader reader = getReader(context, progressListener, "updatePlaylist", null, names, values); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Updating playlists is not supported."); - Reader reader = getReader(context, progressListener, "updatePlaylist", null, Arrays.asList("playlistId", "name", "comment", "public"), Arrays.asList(id, name, comment, pub)); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public Lyrics getLyrics(String artist, String title, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getLyrics", null, Arrays.asList("artist", "title"), Arrays.asList(artist, title)); - try { - return new LyricsParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception { - id = getOfflineSongId(id, context, progressListener); - scrobble(id, submission, 0, context, progressListener); - } - - public void scrobble(String id, boolean submission, long time, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.5", "Scrobbling not supported."); - Reader reader; - if(time > 0){ - checkServerVersion(context, "1.8", "Scrobbling with a time not supported."); - reader = getReader(context, progressListener, "scrobble", null, Arrays.asList("id", "submission", "time"), Arrays.asList(id, submission, time)); - } - else - reader = getReader(context, progressListener, "scrobble", null, Arrays.asList("id", "submission"), Arrays.asList(id, submission)); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception { - List names = new ArrayList(); - List values = new ArrayList(); - - names.add("type"); - values.add(type); - names.add("size"); - values.add(size); - names.add("offset"); - values.add(offset); - - // Add folder if it was set and is non null - int instance = getInstance(context); - if(Util.getAlbumListsPerFolder(context, instance)) { - String folderId = Util.getSelectedMusicFolderId(context, instance); - if(folderId != null) { - names.add("musicFolderId"); - values.add(folderId); - } - } - - Reader reader = getReader(context, progressListener, Util.isTagBrowsing(context, getInstance(context)) ? "getAlbumList2" : "getAlbumList", - null, names, values, true); - try { - return new AlbumListParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getAlbumList(String type, String extra, int size, int offset, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.10.1", "This type of album list is not supported"); - - List names = new ArrayList(); - List values = new ArrayList(); - - names.add("size"); - names.add("offset"); - - values.add(size); - values.add(offset); - - if("genres".equals(type)) { - names.add("type"); - values.add("byGenre"); - - names.add("genre"); - values.add(extra); - } else if("years".equals(type)) { - names.add("type"); - values.add("byYear"); - - names.add("fromYear"); - names.add("toYear"); - - int decade = Integer.parseInt(extra); - values.add(decade); - values.add(decade + 10); - } - - // Add folder if it was set and is non null - int instance = getInstance(context); - if(Util.getAlbumListsPerFolder(context, instance)) { - String folderId = Util.getSelectedMusicFolderId(context, instance); - if(folderId != null) { - names.add("musicFolderId"); - values.add(folderId); - } - } - - Reader reader = getReader(context, progressListener, Util.isTagBrowsing(context, instance) ? "getAlbumList2" : "getAlbumList", null, names, values, true); - try { - return new AlbumListParser(context, instance).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.11", "Artist radio is not supported"); - - List names = new ArrayList(); - List values = new ArrayList(); - - names.add("id"); - names.add("count"); - - values.add(artistId); - values.add(size); - - int instance = getInstance(context); - String method; - if(ServerInfo.isMadsonic(context, instance)) { - method = "getPandoraSongs"; - } else { - if (Util.isTagBrowsing(context, instance)) { - method = "getSimilarSongs2"; - } else { - method = "getSimilarSongs"; - } - } - - Reader reader = getReader(context, progressListener, method, null, names, values); - try { - return new RandomSongsParser(context, instance).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getStarredList(Context context, ProgressListener progressListener) throws Exception { - List names = new ArrayList(); - List values = new ArrayList(); - - // Add folder if it was set and is non null - int instance = getInstance(context); - if(Util.getAlbumListsPerFolder(context, instance)) { - String folderId = Util.getSelectedMusicFolderId(context, instance); - if(folderId != null) { - names.add("musicFolderId"); - values.add(folderId); - } - } - - Reader reader = getReader(context, progressListener, Util.isTagBrowsing(context, instance) ? "getStarred2" : "getStarred", null, names, values, true); - try { - return new StarredListParser(context, instance).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getRandomSongs(int size, String musicFolderId, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception { - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); - - List names = new ArrayList(); - List values = new ArrayList(); - - names.add("size"); - values.add(size); - - if (musicFolderId != null && !"".equals(musicFolderId) && !Util.isTagBrowsing(context, getInstance(context))) { - names.add("musicFolderId"); - values.add(musicFolderId); - } - if(genre != null && !"".equals(genre)) { - names.add("genre"); - values.add(genre); - } - if(startYear != null && !"".equals(startYear)) { - names.add("fromYear"); - values.add(startYear); - } - if(endYear != null && !"".equals(endYear)) { - names.add("toYear"); - values.add(endYear); - } - - Reader reader = getReader(context, progressListener, "getRandomSongs", params, names, values); - try { - return new RandomSongsParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - private void checkServerVersion(Context context, String version, String text) throws ServerTooOldException { - Version serverVersion = ServerInfo.getServerVersion(context); - Version requiredVersion = new Version(version); - boolean ok = serverVersion == null || serverVersion.compareTo(requiredVersion) >= 0; - - if (!ok) { - throw new ServerTooOldException(text, serverVersion, requiredVersion); - } - } - - @Override - public String getCoverArtUrl(Context context, MusicDirectory.Entry entry) throws Exception { - StringBuilder builder = new StringBuilder(getRestUrl(context, "getCoverArt")); - builder.append("&id=").append(entry.getCoverArt()); - String url = builder.toString(); - url = Util.replaceInternalUrl(context, url); - url = rewriteUrlWithRedirect(context, url); - return url; - } - - @Override - public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, ProgressListener progressListener, SilentBackgroundTask task) throws Exception { - - // Synchronize on the entry so that we don't download concurrently for the same song. - synchronized (entry) { - - // Use cached file, if existing. - Bitmap bitmap = FileUtil.getAlbumArtBitmap(context, entry, size); - if (bitmap != null) { - return bitmap; - } - - String url = getRestUrl(context, "getCoverArt"); - - InputStream in = null; - try { - List parameterNames = Arrays.asList("id"); - List parameterValues = Arrays.asList(entry.getCoverArt()); - HttpEntity entity = getEntityForURL(context, url, null, parameterNames, parameterValues, progressListener, task); - - in = entity.getContent(); - Header contentEncoding = entity.getContentEncoding(); - if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) { - in = new GZIPInputStream(in); - } - - // If content type is XML, an error occured. Get it. - String contentType = Util.getContentType(entity); - if (contentType != null && (contentType.startsWith("text/xml") || contentType.startsWith("text/html"))) { - new ErrorParser(context, getInstance(context)).parse(new InputStreamReader(in, Constants.UTF_8)); - return null; // Never reached. - } - - byte[] bytes = Util.toByteArray(in); - - // Handle case where partial was downloaded before being cancelled - if(task != null && task.isCancelled()) { - return null; - } - - OutputStream out = null; - try { - out = new FileOutputStream(FileUtil.getAlbumArtFile(context, entry)); - out.write(bytes); - } finally { - Util.close(out); - } - - // Size == 0 -> only want to download - if(size == 0) { - return null; - } else { - return FileUtil.getSampledBitmap(bytes, size); - } - } finally { - Util.close(in); - } - } - } - - @Override - public HttpResponse getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception { - - String url = getRestUrl(context, "stream"); - - // Set socket read timeout. Note: The timeout increases as the offset gets larger. This is - // to avoid the thrashing effect seen when offset is combined with transcoding/downsampling on the server. - // In that case, the server uses a long time before sending any data, causing the client to time out. - HttpParams params = new BasicHttpParams(); - int timeout = (int) (SOCKET_READ_TIMEOUT_DOWNLOAD + offset * TIMEOUT_MILLIS_PER_OFFSET_BYTE); - HttpConnectionParams.setSoTimeout(params, timeout); - - // Add "Range" header if offset is given. - List
headers = new ArrayList
(); - if (offset > 0) { - headers.add(new BasicHeader("Range", "bytes=" + offset + "-")); - } - - List parameterNames = new ArrayList(); - parameterNames.add("id"); - parameterNames.add("maxBitRate"); - - List parameterValues = new ArrayList(); - parameterValues.add(song.getId()); - parameterValues.add(maxBitrate); - - // If video specify what format to download - if(song.isVideo()) { - String videoPlayerType = Util.getVideoPlayerType(context); - if("hls".equals(videoPlayerType)) { - // HLS should be able to transcode to mp4 automatically - parameterNames.add("format"); - parameterValues.add("mp4"); - - parameterNames.add("hls"); - parameterValues.add("true"); - } else if("raw".equals(videoPlayerType)) { - // Download the original video without any transcoding - parameterNames.add("format"); - parameterValues.add("raw"); - } - } - HttpResponse response = getResponseForURL(context, url, params, parameterNames, parameterValues, headers, null, task, false); - - // If content type is XML, an error occurred. Get it. - String contentType = Util.getContentType(response.getEntity()); - if (contentType != null && (contentType.startsWith("text/xml") || contentType.startsWith("text/html"))) { - InputStream in = response.getEntity().getContent(); - Header contentEncoding = response.getEntity().getContentEncoding(); - if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) { - in = new GZIPInputStream(in); - } - try { - new ErrorParser(context, getInstance(context)).parse(new InputStreamReader(in, Constants.UTF_8)); - } finally { - Util.close(in); - } - } - - return response; - } - - @Override - public String getMusicUrl(Context context, MusicDirectory.Entry song, int maxBitrate) throws Exception { - StringBuilder builder = new StringBuilder(getRestUrl(context, "stream")); - builder.append("&id=").append(song.getId()); - - // If we are doing mp3 to mp3, just specify raw so that stuff works better - if("mp3".equals(song.getSuffix()) && (song.getTranscodedSuffix() == null || "mp3".equals(song.getTranscodedSuffix())) && ServerInfo.checkServerVersion(context, "1.9", getInstance(context))) { - builder.append("&format=raw"); - builder.append("&estimateContentLength=true"); - } else { - builder.append("&maxBitRate=").append(maxBitrate); - } - - String url = builder.toString(); - url = Util.replaceInternalUrl(context, url); - url = rewriteUrlWithRedirect(context, url); - Log.i(TAG, "Using music URL: " + stripUrlInfo(url)); - return url; - } - - @Override - public String getVideoUrl(int maxBitrate, Context context, String id) { - StringBuilder builder = new StringBuilder(getRestUrl(context, "videoPlayer")); - builder.append("&id=").append(id); - builder.append("&maxBitRate=").append(maxBitrate); - builder.append("&autoplay=true"); - - String url = rewriteUrlWithRedirect(context, builder.toString()); - Log.i(TAG, "Using video URL: " + stripUrlInfo(url)); - return url; - } - - @Override - public String getVideoStreamUrl(String format, int maxBitrate, Context context, String id) throws Exception { - StringBuilder builder = new StringBuilder(getRestUrl(context, "stream")); - builder.append("&id=").append(id); - if(!"raw".equals(format)) { - checkServerVersion(context, "1.9", "Video streaming not supported."); - builder.append("&maxBitRate=").append(maxBitrate); - } - builder.append("&format=").append(format); - - String url = rewriteUrlWithRedirect(context, builder.toString()); - Log.i(TAG, "Using video URL: " + stripUrlInfo(url)); - return url; - } - - @Override - public String getHlsUrl(String id, int bitRate, Context context) throws Exception { - checkServerVersion(context, "1.9", "HLS video streaming not supported."); - - StringBuilder builder = new StringBuilder(getRestUrl(context, "hls")); - builder.append("&id=").append(id); - if(bitRate > 0) { - builder.append("&bitRate=").append(bitRate); - } - - String url = rewriteUrlWithRedirect(context, builder.toString()); - Log.i(TAG, "Using hls URL: " + stripUrlInfo(url)); - return url; - } - - @Override - public RemoteStatus updateJukeboxPlaylist(List ids, Context context, ProgressListener progressListener) throws Exception { - int n = ids.size(); - List parameterNames = new ArrayList(n + 1); - parameterNames.add("action"); - for (int i = 0; i < n; i++) { - parameterNames.add("id"); - } - List parameterValues = new ArrayList(); - parameterValues.add("set"); - parameterValues.addAll(ids); - - return executeJukeboxCommand(context, progressListener, parameterNames, parameterValues); - } - - @Override - public RemoteStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception { - List parameterNames = Arrays.asList("action", "index", "offset"); - List parameterValues = Arrays.asList("skip", index, offsetSeconds); - return executeJukeboxCommand(context, progressListener, parameterNames, parameterValues); - } - - @Override - public RemoteStatus stopJukebox(Context context, ProgressListener progressListener) throws Exception { - return executeJukeboxCommand(context, progressListener, Arrays.asList("action"), Arrays.asList("stop")); - } - - @Override - public RemoteStatus startJukebox(Context context, ProgressListener progressListener) throws Exception { - return executeJukeboxCommand(context, progressListener, Arrays.asList("action"), Arrays.asList("start")); - } - - @Override - public RemoteStatus getJukeboxStatus(Context context, ProgressListener progressListener) throws Exception { - return executeJukeboxCommand(context, progressListener, Arrays.asList("action"), Arrays.asList("status")); - } - - @Override - public RemoteStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception { - List parameterNames = Arrays.asList("action", "gain"); - List parameterValues = Arrays.asList("setGain", gain); - return executeJukeboxCommand(context, progressListener, parameterNames, parameterValues); - - } - - private RemoteStatus executeJukeboxCommand(Context context, ProgressListener progressListener, List parameterNames, List parameterValues) throws Exception { - checkServerVersion(context, "1.7", "Jukebox not supported."); - Reader reader = getReader(context, progressListener, "jukeboxControl", null, parameterNames, parameterValues); - try { - return new JukeboxStatusParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void setStarred(List entries, List artists, List albums, boolean starred, ProgressListener progressListener, Context context) throws Exception { - checkServerVersion(context, "1.8", "Starring is not supported."); - - List names = new ArrayList(); - List values = new ArrayList(); - - if(entries != null && entries.size() > 0) { - if(entries.size() > 1) { - for (MusicDirectory.Entry entry : entries) { - names.add("id"); - values.add(entry.getId()); - } - } else { - names.add("id"); - values.add(getOfflineSongId(entries.get(0).getId(), context, progressListener)); - } - } - if(artists != null && artists.size() > 0) { - for (MusicDirectory.Entry artist : artists) { - names.add("artistId"); - values.add(artist.getId()); - } - } - if(albums != null && albums.size() > 0) { - for (MusicDirectory.Entry album : albums) { - names.add("albumId"); - values.add(album.getId()); - } - } - - Reader reader = getReader(context, progressListener, starred ? "star" : "unstar", null, names, values); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public List getShares(Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.6", "Shares not supported."); - - Reader reader = getReader(context, progressListener, "getShares", null); - try { - return new ShareParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public List createShare(List ids, String description, Long expires, Context context, ProgressListener progressListener) throws Exception { - List parameterNames = new LinkedList(); - List parameterValues = new LinkedList(); - - for (String id : ids) { - parameterNames.add("id"); - parameterValues.add(id); - } - - if (description != null) { - parameterNames.add("description"); - parameterValues.add(description); - } - - if (expires > 0) { - parameterNames.add("expires"); - parameterValues.add(expires); - } - - Reader reader = getReader(context, progressListener, "createShare", null, parameterNames, parameterValues); - try { - return new ShareParser(context, getInstance(context)).parse(reader, progressListener); - } - finally { - Util.close(reader); - } - } - - @Override - public void deleteShare(String id, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.6", "Shares not supported."); - - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); - - List parameterNames = new ArrayList(); - List parameterValues = new ArrayList(); - - parameterNames.add("id"); - parameterValues.add(id); - - Reader reader = getReader(context, progressListener, "deleteShare", params, parameterNames, parameterValues); - - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } - finally { - Util.close(reader); - } - } - - @Override - public void updateShare(String id, String description, Long expires, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.6", "Updating share not supported."); - - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); - - List parameterNames = new ArrayList(); - List parameterValues = new ArrayList(); - - parameterNames.add("id"); - parameterValues.add(id); - - if (description != null) { - parameterNames.add("description"); - parameterValues.add(description); - } - - parameterNames.add("expires"); - parameterValues.add(expires); - - Reader reader = getReader(context, progressListener, "updateShare", params, parameterNames, parameterValues); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } - finally { - Util.close(reader); - } - } - - @Override - public List getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.2", "Chat not supported."); - - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); - - List parameterNames = new ArrayList(); - List parameterValues = new ArrayList(); - - parameterNames.add("since"); - parameterValues.add(since); - - Reader reader = getReader(context, progressListener, "getChatMessages", params, parameterNames, parameterValues); - - try { - return new ChatMessageParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.2", "Chat not supported."); - - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); - - List parameterNames = new ArrayList(); - List parameterValues = new ArrayList(); - - parameterNames.add("message"); - parameterValues.add(message); - - Reader reader = getReader(context, progressListener, "addChatMessage", params, parameterNames, parameterValues); - - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public List getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Genres not supported."); - - Reader reader = getReader(context, progressListener, "getGenres", null); - try { - return new GenreParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Genres not supported."); - - HttpParams params = new BasicHttpParams(); - HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS); - - List parameterNames = new ArrayList(); - List parameterValues = new ArrayList(); - - parameterNames.add("genre"); - parameterValues.add(genre); - parameterNames.add("count"); - parameterValues.add(count); - parameterNames.add("offset"); - parameterValues.add(offset); - - // Add folder if it was set and is non null - int instance = getInstance(context); - if(Util.getAlbumListsPerFolder(context, instance)) { - String folderId = Util.getSelectedMusicFolderId(context, instance); - if(folderId != null) { - parameterNames.add("musicFolderId"); - parameterValues.add(folderId); - } - } - - Reader reader = getReader(context, progressListener, "getSongsByGenre", params, parameterNames, parameterValues, true); - try { - return new RandomSongsParser(context, instance).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getTopTrackSongs(String artist, int size, Context context, ProgressListener progressListener) throws Exception { - List parameterNames = new ArrayList(); - List parameterValues = new ArrayList(); - - parameterNames.add("artist"); - parameterValues.add(artist); - parameterNames.add("size"); - parameterValues.add(size); - - Reader reader = getReader(context, progressListener, "getTopTrackSongs", null, parameterNames, parameterValues); - try { - return new RandomSongsParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public List getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.6", "Podcasts not supported."); - - Reader reader = getReader(context, progressListener, "getPodcasts", null, Arrays.asList("includeEpisodes"), Arrays.asList("false")); - try { - List channels = new PodcastChannelParser(context, getInstance(context)).parse(reader, progressListener); - - String content = ""; - for(PodcastChannel channel: channels) { - content += channel.getName() + "\n"; - } - - File file = FileUtil.getPodcastFile(context, Util.getServerName(context, getInstance(context))); - BufferedWriter bw = new BufferedWriter(new FileWriter(file)); - bw.write(content); - bw.close(); - - return channels; - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getPodcastEpisodes(boolean refresh, String id, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getPodcasts", null, Arrays.asList("id"), Arrays.asList(id)); - try { - return new PodcastEntryParser(context, getInstance(context)).parse(id, reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public void refreshPodcasts(Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Refresh podcasts not supported."); - - Reader reader = getReader(context, progressListener, "refreshPodcasts", null); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void createPodcastChannel(String url, Context context, ProgressListener progressListener) throws Exception{ - checkServerVersion(context, "1.9", "Creating podcasts not supported."); - - Reader reader = getReader(context, progressListener, "createPodcastChannel", null, "url", url); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void deletePodcastChannel(String id, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Deleting podcasts not supported."); - - Reader reader = getReader(context, progressListener, "deletePodcastChannel", null, "id", id); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void downloadPodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{ - checkServerVersion(context, "1.9", "Downloading podcasts not supported."); - - Reader reader = getReader(context, progressListener, "downloadPodcastEpisode", null, "id", id); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void deletePodcastEpisode(String id, String parent, ProgressListener progressListener, Context context) throws Exception{ - checkServerVersion(context, "1.9", "Deleting podcasts not supported."); - - Reader reader = getReader(context, progressListener, "deletePodcastEpisode", null, "id", id); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void setRating(MusicDirectory.Entry entry, int rating, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.6", "Setting ratings not supported."); - - Reader reader = getReader(context, progressListener, "setRating", null, Arrays.asList("id", "rating"), Arrays.asList(entry.getId(), rating)); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public MusicDirectory getBookmarks(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Bookmarks not supported."); - - Reader reader = getReader(context, progressListener, "getBookmarks", null); - try { - return new BookmarkParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public void createBookmark(MusicDirectory.Entry entry, int position, String comment, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Creating bookmarks not supported."); - - Reader reader = getReader(context, progressListener, "createBookmark", null, Arrays.asList("id", "position", "comment"), Arrays.asList(entry.getId(), position, comment)); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void deleteBookmark(MusicDirectory.Entry entry, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.9", "Deleting bookmarks not supported."); - - Reader reader = getReader(context, progressListener, "deleteBookmark", null, Arrays.asList("id"), Arrays.asList(entry.getId())); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getUser", null, Arrays.asList("username"), Arrays.asList(username)); - try { - List users = new UserParser(context, getInstance(context)).parse(reader, progressListener); - if(users.size() > 0) { - // Should only have returned one anyways - return users.get(0); - } else { - return null; - } - } finally { - Util.close(reader); - } - } - - @Override - public List getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.8", "Getting user list is not supported"); - - Reader reader = getReader(context, progressListener, "getUsers", null); - try { - return new UserParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public void createUser(User user, Context context, ProgressListener progressListener) throws Exception { - List names = new ArrayList(); - List values = new ArrayList(); - - names.add("username"); - values.add(user.getUsername()); - names.add("email"); - values.add(user.getEmail()); - names.add("password"); - values.add(user.getPassword()); - - for(User.Setting setting: user.getSettings()) { - names.add(setting.getName()); - values.add(setting.getValue()); - } - - Reader reader = getReader(context, progressListener, "createUser", null, names, values); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void updateUser(User user, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.10", "Updating user is not supported"); - - List names = new ArrayList(); - List values = new ArrayList(); - - names.add("username"); - values.add(user.getUsername()); - - for(User.Setting setting: user.getSettings()) { - if(setting.getName().indexOf("Role") != -1) { - names.add(setting.getName()); - values.add(setting.getValue()); - } - } - - Reader reader = getReader(context, progressListener, "updateUser", null, names, values); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "deleteUser", null, Arrays.asList("username"), Arrays.asList(username)); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void changeEmail(String username, String email, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "updateUser", null, Arrays.asList("username", "email"), Arrays.asList(username, email)); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "changePassword", null, Arrays.asList("username", "password"), Arrays.asList(username, password)); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public Bitmap getAvatar(String username, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception { - // Return silently if server is too old - if (!ServerInfo.checkServerVersion(context, "1.8")) { - return null; - } - - // Synchronize on the username so that we don't download concurrently for - // the same user. - synchronized (username) { - // Use cached file, if existing. - Bitmap bitmap = FileUtil.getAvatarBitmap(context, username, size); - if(bitmap != null) { - return bitmap; - } - - String url = Util.getRestUrl(context, "getAvatar"); - InputStream in = null; - try - { - List parameterNames; - List parameterValues; - - parameterNames = Collections.singletonList("username"); - parameterValues = Arrays.asList(username); - - HttpEntity entity = getEntityForURL(context, url, null, parameterNames, parameterValues, progressListener, task); - in = entity.getContent(); - Header contentEncoding = entity.getContentEncoding(); - if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) { - in = new GZIPInputStream(in); - } - - // If content type is XML, an error occurred. Get it. - String contentType = Util.getContentType(entity); - if (contentType != null && (contentType.startsWith("text/xml") || contentType.startsWith("text/html"))) { - new ErrorParser(context, getInstance(context)).parse(new InputStreamReader(in, Constants.UTF_8)); - return null; // Never reached. - } - - byte[] bytes = Util.toByteArray(in); - if(task != null && task.isCancelled()) { - // Handle case where partial is downloaded and cancelled - return null; - } - - OutputStream out = null; - try { - out = new FileOutputStream(FileUtil.getAvatarFile(context, username)); - out.write(bytes); - } finally { - Util.close(out); - } - - return FileUtil.getSampledBitmap(bytes, size, false); - } - finally { - Util.close(in); - } - } - } - - @Override - public ArtistInfo getArtistInfo(String id, boolean refresh, boolean allowNetwork, Context context, ProgressListener progressListener) throws Exception { - checkServerVersion(context, "1.11", "Getting artist info is not supported"); - - Reader reader = getReader(context, progressListener, Util.isTagBrowsing(context, getInstance(context)) ? "getArtistInfo2" : "getArtistInfo", null, Arrays.asList("id", "includeNotPresent"), Arrays.asList(id, "true")); - try { - return new ArtistInfoParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception { - // Synchronize on the url so that we don't download concurrently - synchronized (url) { - // Use cached file, if existing. - Bitmap bitmap = FileUtil.getMiscBitmap(context, url, size); - if(bitmap != null) { - return bitmap; - } - - InputStream in = null; - try { - HttpEntity entity = getEntityForURL(context, url, null, null, null, progressListener, task); - in = entity.getContent(); - Header contentEncoding = entity.getContentEncoding(); - if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) { - in = new GZIPInputStream(in); - } - - // If content type is XML, an error occurred. Get it. - String contentType = Util.getContentType(entity); - if (contentType != null && (contentType.startsWith("text/xml") || contentType.startsWith("text/html"))) { - new ErrorParser(context, getInstance(context)).parse(new InputStreamReader(in, Constants.UTF_8)); - return null; // Never reached. - } - - byte[] bytes = Util.toByteArray(in); - if(task != null && task.isCancelled()) { - // Handle case where partial is downloaded and cancelled - return null; - } - - OutputStream out = null; - try { - out = new FileOutputStream(FileUtil.getMiscFile(context, url)); - out.write(bytes); - } finally { - Util.close(out); - } - - return FileUtil.getSampledBitmap(bytes, size, false); - } - finally { - Util.close(in); - } - } - } - - @Override - public MusicDirectory getVideos(boolean refresh, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getVideos", null, true); - try { - return new VideosParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public void savePlayQueue(List songs, MusicDirectory.Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception { - List parameterNames = new LinkedList(); - List parameterValues = new LinkedList(); - - for(MusicDirectory.Entry song: songs) { - parameterNames.add("id"); - parameterValues.add(song.getId()); - } - - parameterNames.add("current"); - parameterValues.add(currentPlaying.getId()); - - parameterNames.add("position"); - parameterValues.add(position); - - Reader reader = getReader(context, progressListener, "savePlayQueue", null, parameterNames, parameterValues); - try { - new ErrorParser(context, getInstance(context)).parse(reader); - } finally { - Util.close(reader); - } - } - - @Override - public PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "getPlayQueue", null); - try { - return new PlayQueueParser(context, getInstance(context)).parse(reader, progressListener); - } finally { - Util.close(reader); - } - } - - @Override - public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ - return processOfflineScrobbles(context, progressListener) + processOfflineStars(context, progressListener); - } - - public int processOfflineScrobbles(final Context context, final ProgressListener progressListener) throws Exception { - SharedPreferences offline = Util.getOfflineSync(context); - SharedPreferences.Editor offlineEditor = offline.edit(); - int count = offline.getInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); - int retry = 0; - for(int i = 1; i <= count; i++) { - String id = offline.getString(Constants.OFFLINE_SCROBBLE_ID + i, null); - long time = offline.getLong(Constants.OFFLINE_SCROBBLE_TIME + i, 0); - if(id != null) { - scrobble(id, true, time, context, progressListener); - } else { - String search = offline.getString(Constants.OFFLINE_SCROBBLE_SEARCH + i, ""); - try{ - SearchCritera critera = new SearchCritera(search, 0, 0, 1); - SearchResult result = searchNew(critera, context, progressListener); - if(result.getSongs().size() == 1){ - Log.i(TAG, "Query '" + search + "' returned song " + result.getSongs().get(0).getTitle() + " by " + result.getSongs().get(0).getArtist() + " with id " + result.getSongs().get(0).getId()); - Log.i(TAG, "Scrobbling " + result.getSongs().get(0).getId() + " with time " + time); - scrobble(result.getSongs().get(0).getId(), true, time, context, progressListener); - } - else{ - throw new Exception("Song not found on server"); - } - } - catch(Exception e){ - Log.e(TAG, e.toString()); - retry++; - } - } - } - - offlineEditor.putInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); - offlineEditor.commit(); - - return count - retry; - } - - public int processOfflineStars(final Context context, final ProgressListener progressListener) throws Exception { - SharedPreferences offline = Util.getOfflineSync(context); - SharedPreferences.Editor offlineEditor = offline.edit(); - int count = offline.getInt(Constants.OFFLINE_STAR_COUNT, 0); - int retry = 0; - for(int i = 1; i <= count; i++) { - String id = offline.getString(Constants.OFFLINE_STAR_ID + i, null); - boolean starred = offline.getBoolean(Constants.OFFLINE_STAR_SETTING + i, false); - if(id != null) { - setStarred(Arrays.asList(new MusicDirectory.Entry(id)), null, null, starred, progressListener, context); - } else { - String search = offline.getString(Constants.OFFLINE_STAR_SEARCH + i, ""); - try{ - SearchCritera critera = new SearchCritera(search, 0, 1, 1); - SearchResult result = searchNew(critera, context, progressListener); - if(result.getSongs().size() == 1) { - MusicDirectory.Entry song = result.getSongs().get(0); - Log.i(TAG, "Query '" + search + "' returned song " + song.getTitle() + " by " + song.getArtist() + " with id " + song.getId()); - setStarred(Arrays.asList(song), null, null, starred, progressListener, context); - } else if(result.getAlbums().size() == 1) { - MusicDirectory.Entry album = result.getAlbums().get(0); - Log.i(TAG, "Query '" + search + "' returned album " + album.getTitle() + " by " + album.getArtist() + " with id " + album.getId()); - if(Util.isTagBrowsing(context, getInstance(context))) { - setStarred(null, null, Arrays.asList(album), starred, progressListener, context); - } else { - setStarred(Arrays.asList(album), null, null, starred, progressListener, context); - } - } - else { - throw new Exception("Song not found on server"); - } - } - catch(Exception e) { - Log.e(TAG, e.toString()); - retry++; - } - } - } - - offlineEditor.putInt(Constants.OFFLINE_STAR_COUNT, 0); - offlineEditor.commit(); - - return count - retry; - } - - private String getOfflineSongId(String id, Context context, ProgressListener progressListener) throws Exception { - SharedPreferences prefs = Util.getPreferences(context); - String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); - if(cacheLocn != null && id.indexOf(cacheLocn) != -1) { - String searchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn); - SearchCritera critera = new SearchCritera(searchCriteria, 0, 0, 1); - SearchResult result = searchNew(critera, context, progressListener); - if(result.getSongs().size() == 1){ - id = result.getSongs().get(0).getId(); - } - } - - return id; - } - - @Override - public void setInstance(Integer instance) throws Exception { - this.instance = instance; - } - - private Reader getReader(Context context, ProgressListener progressListener, String method, HttpParams requestParams) throws Exception { - return getReader(context, progressListener, method, requestParams, false); - } - private Reader getReader(Context context, ProgressListener progressListener, String method, HttpParams requestParams, boolean throwsError) throws Exception { - return getReader(context, progressListener, method, requestParams, Collections.emptyList(), Collections.emptyList(), throwsError); - } - - private Reader getReader(Context context, ProgressListener progressListener, String method, - HttpParams requestParams, String parameterName, Object parameterValue) throws Exception { - return getReader(context, progressListener, method, requestParams, Arrays.asList(parameterName), Arrays.asList(parameterValue)); - } - - private Reader getReader(Context context, ProgressListener progressListener, String method, - HttpParams requestParams, List parameterNames, List parameterValues) throws Exception { - return getReader(context, progressListener, method, requestParams, parameterNames, parameterValues, false); - } - private Reader getReader(Context context, ProgressListener progressListener, String method, - HttpParams requestParams, List parameterNames, List parameterValues, boolean throwErrors) throws Exception { - - if (progressListener != null) { - progressListener.updateProgress(R.string.service_connecting); - } - - String url = getRestUrl(context, method); - return getReaderForURL(context, url, requestParams, parameterNames, parameterValues, progressListener, throwErrors); - } - - private Reader getReaderForURL(Context context, String url, HttpParams requestParams, List parameterNames, - List parameterValues, ProgressListener progressListener) throws Exception { - return getReaderForURL(context, url, requestParams, parameterNames, parameterValues, progressListener, true); - } - private Reader getReaderForURL(Context context, String url, HttpParams requestParams, List parameterNames, - List parameterValues, ProgressListener progressListener, boolean throwErrors) throws Exception { - HttpEntity entity = getEntityForURL(context, url, requestParams, parameterNames, parameterValues, progressListener, throwErrors); - if (entity == null) { - throw new RuntimeException("No entity received for URL " + url); - } - - InputStream in = entity.getContent(); - Header contentEncoding = entity.getContentEncoding(); - if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) { - in = new GZIPInputStream(in); - } - return new InputStreamReader(in, Constants.UTF_8); - } - - private HttpEntity getEntityForURL(Context context, String url, HttpParams requestParams, List parameterNames, - List parameterValues, ProgressListener progressListener, boolean throwErrors) throws Exception { - - return getEntityForURL(context, url, requestParams, parameterNames, parameterValues, progressListener, null, throwErrors); - } - - private HttpEntity getEntityForURL(Context context, String url, HttpParams requestParams, List parameterNames, - List parameterValues, ProgressListener progressListener, SilentBackgroundTask task) throws Exception { - return getResponseForURL(context, url, requestParams, parameterNames, parameterValues, null, progressListener, task, false).getEntity(); - } - private HttpEntity getEntityForURL(Context context, String url, HttpParams requestParams, List parameterNames, - List parameterValues, ProgressListener progressListener, SilentBackgroundTask task, boolean throwsError) throws Exception { - return getResponseForURL(context, url, requestParams, parameterNames, parameterValues, null, progressListener, task, throwsError).getEntity(); - } - - private HttpResponse getResponseForURL(Context context, String url, HttpParams requestParams, - List parameterNames, List parameterValues, - List
headers, ProgressListener progressListener, SilentBackgroundTask task, boolean throwsErrors) throws Exception { - // If not too many parameters, extract them to the URL rather than relying on the HTTP POST request being - // received intact. Remember, HTTP POST requests are converted to GET requests during HTTP redirects, thus - // loosing its entity. - if (parameterNames != null && parameterNames.size() < 10) { - StringBuilder builder = new StringBuilder(url); - for (int i = 0; i < parameterNames.size(); i++) { - builder.append("&").append(parameterNames.get(i)).append("="); - String part = URLEncoder.encode(String.valueOf(parameterValues.get(i)), "UTF-8"); - part = part.replaceAll("\\%27", "'"); - builder.append(part); - } - url = builder.toString(); - parameterNames = null; - parameterValues = null; - } - - String rewrittenUrl = rewriteUrlWithRedirect(context, url); - return executeWithRetry(context, rewrittenUrl, url, requestParams, parameterNames, parameterValues, headers, progressListener, task, throwsErrors); - } - - private HttpResponse executeWithRetry(final Context context, String url, String originalUrl, HttpParams requestParams, - List parameterNames, List parameterValues, - List
headers, ProgressListener progressListener, SilentBackgroundTask task, boolean throwErrors) throws Exception { - // Strip out sensitive information from log - if(url.indexOf("scanstatus") == -1) { - Log.i(TAG, stripUrlInfo(url)); - } - - SharedPreferences prefs = Util.getPreferences(context); - int networkTimeout = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_NETWORK_TIMEOUT, "15000")); - HttpParams newParams = httpClient.getParams(); - HttpConnectionParams.setSoTimeout(newParams, networkTimeout); - httpClient.setParams(newParams); - - final AtomicReference isCancelled = new AtomicReference(false); - int attempts = 0; - while (true) { - attempts++; - HttpContext httpContext = new BasicHttpContext(); - final HttpPost request = new HttpPost(url); - - if (task != null) { - // Attempt to abort the HTTP request if the task is cancelled. - task.setOnCancelListener(new BackgroundTask.OnCancelListener() { - @Override - public void onCancel() { - try { - isCancelled.set(true); - if(Thread.currentThread() == Looper.getMainLooper().getThread()) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - request.abort(); - return null; - } - }.execute(); - } else { - request.abort(); - } - } catch(Exception e) { - Log.e(TAG, "Failed to stop http task", e); - } - } - }); - } - - if (parameterNames != null) { - List params = new ArrayList(); - for (int i = 0; i < parameterNames.size(); i++) { - params.add(new BasicNameValuePair(parameterNames.get(i), String.valueOf(parameterValues.get(i)))); - } - request.setEntity(new UrlEncodedFormEntity(params, Constants.UTF_8)); - } - - if (requestParams != null) { - request.setParams(requestParams); - } - - if (headers != null) { - for (Header header : headers) { - request.addHeader(header); - } - } - if(url.indexOf("getCoverArt") == -1 && url.indexOf("stream") == -1 && url.indexOf("getAvatar") == -1) { - request.addHeader("Accept-Encoding", "gzip"); - } - - // Set credentials to get through apache proxies that require authentication. - int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); - String username = prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null); - String password = prefs.getString(Constants.PREFERENCES_KEY_PASSWORD + instance, null); - httpClient.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), - new UsernamePasswordCredentials(username, password)); - - try { - HttpResponse response = httpClient.execute(request, httpContext); - detectRedirect(originalUrl, context, httpContext); - return response; - } catch (IOException x) { - request.abort(); - if (attempts >= HTTP_REQUEST_MAX_ATTEMPTS || isCancelled.get() || throwErrors) { - throw x; - } - if (progressListener != null) { - String msg = context.getResources().getString(R.string.music_service_retry, attempts, HTTP_REQUEST_MAX_ATTEMPTS - 1); - progressListener.updateProgress(msg); - } - Log.w(TAG, "Got IOException " + x + " (" + attempts + "), will retry"); - increaseTimeouts(requestParams); - Thread.sleep(2000L); - } - } - } - - private void increaseTimeouts(HttpParams requestParams) { - if (requestParams != null) { - int connectTimeout = HttpConnectionParams.getConnectionTimeout(requestParams); - if (connectTimeout != 0) { - HttpConnectionParams.setConnectionTimeout(requestParams, (int) (connectTimeout * 1.3F)); - } - int readTimeout = HttpConnectionParams.getSoTimeout(requestParams); - if (readTimeout != 0) { - HttpConnectionParams.setSoTimeout(requestParams, (int) (readTimeout * 1.5F)); - } - } - } - - private void detectRedirect(String originalUrl, Context context, HttpContext httpContext) throws Exception { - HttpUriRequest request = (HttpUriRequest) httpContext.getAttribute(ExecutionContext.HTTP_REQUEST); - HttpHost host = (HttpHost) httpContext.getAttribute(ExecutionContext.HTTP_TARGET_HOST); - - // Sometimes the request doesn't contain the "http://host" part - String redirectedUrl; - if (request.getURI().getScheme() == null) { - redirectedUrl = host.toURI() + request.getURI(); - } else { - redirectedUrl = request.getURI().toString(); - } - - if(redirectedUrl != null && "http://subsonic.org/pages/".equals(redirectedUrl)) { - throw new Exception("Invalid url, redirects to http://subsonic.org/pages/"); - } - - int fromIndex = originalUrl.indexOf("/rest/"); - int toIndex = redirectedUrl.indexOf("/rest/"); - if(fromIndex != -1 && toIndex != -1 && !Util.equals(originalUrl, redirectedUrl)) { - redirectFrom = originalUrl.substring(0, fromIndex); - redirectTo = redirectedUrl.substring(0, toIndex); - - if (redirectFrom.compareTo(redirectTo) != 0) { - Log.i(TAG, redirectFrom + " redirects to " + redirectTo); - } - redirectionLastChecked = System.currentTimeMillis(); - redirectionNetworkType = getCurrentNetworkType(context); - } - } - - private String rewriteUrlWithRedirect(Context context, String url) { - - // Only cache for a certain time. - if (System.currentTimeMillis() - redirectionLastChecked > REDIRECTION_CHECK_INTERVAL_MILLIS) { - return url; - } - - // Ignore cache if network type has changed. - if (redirectionNetworkType != getCurrentNetworkType(context)) { - return url; - } - - if (redirectFrom == null || redirectTo == null) { - return url; - } - - return url.replace(redirectFrom, redirectTo); - } - - private String stripUrlInfo(String url) { - return url.substring(0, url.indexOf("?u=") + 1) + url.substring(url.indexOf("&v=") + 1); - } - - private int getCurrentNetworkType(Context context) { - ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = manager.getActiveNetworkInfo(); - return networkInfo == null ? -1 : networkInfo.getType(); - } - - public int getInstance(Context context) { - if(instance == null) { - return Util.getActiveServer(context); - } else { - return instance; - } - } - public String getRestUrl(Context context, String method) { - return getRestUrl(context, method, true); - } - public String getRestUrl(Context context, String method, boolean allowAltAddress) { - if(instance == null) { - return Util.getRestUrl(context, method, allowAltAddress); - } else { - return Util.getRestUrl(context, method, instance, allowAltAddress); - } - } - - public HttpClient getHttpClient() { - return httpClient; - } -} diff --git a/src/github/daneren2005/dsub/service/RemoteController.java b/src/github/daneren2005/dsub/service/RemoteController.java deleted file mode 100644 index cac28c09..00000000 --- a/src/github/daneren2005/dsub/service/RemoteController.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus -*/ - -package github.daneren2005.dsub.service; - -import android.content.Context; -import android.util.Log; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ProgressBar; -import android.widget.Toast; - -import java.util.Iterator; -import java.util.concurrent.LinkedBlockingQueue; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.RemoteStatus; -import github.daneren2005.serverproxy.WebProxy; - -public abstract class RemoteController { - private static final String TAG = RemoteController.class.getSimpleName(); - protected DownloadService downloadService; - protected boolean nextSupported = false; - - public abstract void create(boolean playing, int seconds); - public abstract void start(); - public abstract void stop(); - public abstract void shutdown(); - - public abstract void updatePlaylist(); - public abstract void changePosition(int seconds); - public abstract void changeTrack(int index, DownloadFile song); - // Really is abstract, just don't want to require RemoteController's support it - public void changeNextTrack(DownloadFile song) { - - }; - public boolean isNextSupported() { - return this.nextSupported; - } - public abstract void setVolume(int volume); - public abstract void updateVolume(boolean up); - public abstract double getVolume(); - public boolean isSeekable() { - return true; - } - - public abstract int getRemotePosition(); - public int getRemoteDuration() { - return 0; - } - - protected abstract class RemoteTask { - abstract RemoteStatus execute() throws Exception; - - @Override - public String toString() { - return getClass().getSimpleName(); - } - } - - protected static class TaskQueue { - private final LinkedBlockingQueue queue = new LinkedBlockingQueue(); - - void add(RemoteTask jukeboxTask) { - queue.add(jukeboxTask); - } - - RemoteTask take() throws InterruptedException { - return queue.take(); - } - - void remove(Class clazz) { - try { - Iterator iterator = queue.iterator(); - while (iterator.hasNext()) { - RemoteTask task = iterator.next(); - if (clazz.equals(task.getClass())) { - iterator.remove(); - } - } - } catch (Throwable x) { - Log.w(TAG, "Failed to clean-up task queue.", x); - } - } - - void clear() { - queue.clear(); - } - } - - protected WebProxy createWebProxy() { - MusicService musicService = MusicServiceFactory.getMusicService(downloadService); - if(musicService instanceof CachedMusicService) { - return new WebProxy(downloadService, ((CachedMusicService)musicService).getMusicService().getHttpClient()); - } else { - return new WebProxy(downloadService); - } - } -} diff --git a/src/github/daneren2005/dsub/service/Scrobbler.java b/src/github/daneren2005/dsub/service/Scrobbler.java deleted file mode 100644 index 1f8538c9..00000000 --- a/src/github/daneren2005/dsub/service/Scrobbler.java +++ /dev/null @@ -1,85 +0,0 @@ -package github.daneren2005.dsub.service; - -import android.content.Context; -import android.util.Log; - -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.Util; - -/** - * Scrobbles played songs to Last.fm. - * - * @author Sindre Mehus - * @version $Id$ - */ -public class Scrobbler { - private static final String TAG = Scrobbler.class.getSimpleName(); - private static final int FOUR_MINUTES = 4 * 60 * 1000; - - private String lastSubmission; - private String lastNowPlaying; - - public void conditionalScrobble(Context context, DownloadFile song, int playerPosition, int duration) { - // More than 4 minutes - if(playerPosition > FOUR_MINUTES) { - scrobble(context, song, true); - } - // More than 50% played - else if(duration > 0 && playerPosition > (duration / 2)) { - scrobble(context, song, true); - } - } - - public void scrobble(final Context context, final DownloadFile song, final boolean submission) { - if (song == null || !Util.isScrobblingEnabled(context)) { - return; - } - - // Ignore if online with no network access - if(!Util.isOffline(context) && !Util.isNetworkConnected(context)) { - return; - } - - // Ignore podcasts - if(song.getSong() instanceof PodcastEpisode) { - return; - } - - // Ignore songs which are under 30 seconds per Last.FM guidelines - Integer duration = song.getSong().getDuration(); - if(duration != null && duration > 0 && duration < 30) { - return; - } - - final String id = song.getSong().getId(); - - // Avoid duplicate registrations. - if (submission && id.equals(lastSubmission)) { - return; - } - if (!submission && id.equals(lastNowPlaying)) { - return; - } - - if (submission) { - lastSubmission = id; - } else { - lastNowPlaying = id; - } - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() { - MusicService service = MusicServiceFactory.getMusicService(context); - try { - service.scrobble(id, submission, context, null); - Log.i(TAG, "Scrobbled '" + (submission ? "submission" : "now playing") + "' for " + song); - } catch (Exception x) { - Log.i(TAG, "Failed to scrobble'" + (submission ? "submission" : "now playing") + "' for " + song, x); - } - return null; - } - }.execute(); - } -} diff --git a/src/github/daneren2005/dsub/service/ServerTooOldException.java b/src/github/daneren2005/dsub/service/ServerTooOldException.java deleted file mode 100644 index e4a951de..00000000 --- a/src/github/daneren2005/dsub/service/ServerTooOldException.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service; - -import github.daneren2005.dsub.domain.Version; - -/** - * Thrown if the REST API version implemented by the server is too old. - * - * @author Sindre Mehus - * @version $Id$ - */ -public class ServerTooOldException extends Exception { - - private final String text; - private final Version serverVersion; - private final Version requiredVersion; - - public ServerTooOldException(String text, Version serverVersion, Version requiredVersion) { - this.text = text; - this.serverVersion = serverVersion; - this.requiredVersion = requiredVersion; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (text != null) { - builder.append(text).append(" "); - } - builder.append("Server API version too old. "); - builder.append("Requires server version ") - .append(requiredVersion.getVersion()) - .append(", but it is version ") - .append(serverVersion.getVersion()) - .append("."); - return builder.toString(); - } - - @Override - public String getMessage() { - return this.toString(); - } -} diff --git a/src/github/daneren2005/dsub/service/parser/AbstractParser.java b/src/github/daneren2005/dsub/service/parser/AbstractParser.java deleted file mode 100644 index bc5d2199..00000000 --- a/src/github/daneren2005/dsub/service/parser/AbstractParser.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import java.io.Reader; - -import org.xmlpull.v1.XmlPullParser; - -import android.content.Context; -import android.util.Xml; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.domain.Version; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.Util; - -/** - * @author Sindre Mehus - */ -public abstract class AbstractParser { - - protected final Context context; - protected final int instance; - private XmlPullParser parser; - private boolean rootElementFound; - - public AbstractParser(Context context, int instance) { - this.context = context; - this.instance = instance; - } - - protected Context getContext() { - return context; - } - - protected void handleError() throws Exception { - int code = getInteger("code"); - String message; - switch (code) { - case 0: - message = context.getResources().getString(R.string.parser_server_error, get("message")); - break; - case 20: - message = context.getResources().getString(R.string.parser_upgrade_client); - break; - case 30: - message = context.getResources().getString(R.string.parser_upgrade_server); - break; - case 40: - message = context.getResources().getString(R.string.parser_not_authenticated); - break; - case 50: - message = context.getResources().getString(R.string.parser_not_authorized); - break; - default: - message = get("message"); - break; - } - throw new SubsonicRESTException(code, message); - } - - protected void updateProgress(ProgressListener progressListener, int messageId) { - if (progressListener != null) { - progressListener.updateProgress(messageId); - } - } - - protected void updateProgress(ProgressListener progressListener, String message) { - if (progressListener != null) { - progressListener.updateProgress(message); - } - } - - protected String getText() { - return parser.getText(); - } - - protected String get(String name) { - return parser.getAttributeValue(null, name); - } - - protected boolean getBoolean(String name) { - return "true".equals(get(name)); - } - - protected Integer getInteger(String name) { - String s = get(name); - return s == null ? null : Integer.valueOf(s); - } - - protected Long getLong(String name) { - String s = get(name); - return s == null ? null : Long.valueOf(s); - } - - protected Float getFloat(String name) { - String s = get(name); - return s == null ? null : Float.valueOf(s); - } - - protected void init(Reader reader) throws Exception { - parser = Xml.newPullParser(); - parser.setInput(reader); - rootElementFound = false; - } - - protected int nextParseEvent() throws Exception { - return parser.next(); - } - - protected String getElementName() { - String name = parser.getName(); - if ("subsonic-response".equals(name)) { - rootElementFound = true; - String version = get("version"); - if (version != null) { - ServerInfo server = new ServerInfo(); - server.setRestVersion(new Version(version)); - - if("madsonic".equals(get("type"))) { - server.setRestType(ServerInfo.TYPE_MADSONIC); - } - server.saveServerInfo(context, instance); - } - } - return name; - } - - protected void validate() throws Exception { - if (!rootElementFound) { - throw new Exception(context.getResources().getString(R.string.background_task_parse_error)); - } - } -} diff --git a/src/github/daneren2005/dsub/service/parser/AlbumListParser.java b/src/github/daneren2005/dsub/service/parser/AlbumListParser.java deleted file mode 100644 index 773c241b..00000000 --- a/src/github/daneren2005/dsub/service/parser/AlbumListParser.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ProgressListener; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; - -/** - * @author Sindre Mehus - */ -public class AlbumListParser extends MusicDirectoryEntryParser { - - public AlbumListParser(Context context, int instance) { - super(context, instance); - } - - public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - MusicDirectory dir = new MusicDirectory(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("album".equals(name)) { - MusicDirectory.Entry entry = parseEntry(""); - entry.setDirectory(true); - dir.addChild(entry); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return dir; - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/ArtistInfoParser.java b/src/github/daneren2005/dsub/service/parser/ArtistInfoParser.java deleted file mode 100644 index 5c3d2412..00000000 --- a/src/github/daneren2005/dsub/service/parser/ArtistInfoParser.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import android.util.Log; - -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.ArtistInfo; -import github.daneren2005.dsub.util.ProgressListener; - -public class ArtistInfoParser extends AbstractParser { - private static final String TAG = ArtistInfo.class.getSimpleName(); - - public ArtistInfoParser(Context context, int instance) { - super(context, instance); - } - - public ArtistInfo parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - ArtistInfo info = new ArtistInfo(); - List artists = new ArrayList(); - List missingArtists = new ArrayList(); - - String tagName = null; - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - tagName = getElementName(); - if ("similarArtist".equals(tagName)) { - String id = get("id"); - if(id.equals("-1")) { - missingArtists.add(get("name")); - } else { - Artist artist = new Artist(); - artist.setId(id); - artist.setName(get("name")); - artist.setStarred(get("starred") != null); - artists.add(artist); - } - } else if ("error".equals(tagName)) { - handleError(); - } - } else if(eventType == XmlPullParser.TEXT) { - if ("biography".equals(tagName) && info.getBiography() == null) { - info.setBiography(getText()); - } else if ("musicBrainzId".equals(tagName) && info.getMusicBrainzId() == null) { - info.setMusicBrainzId(getText()); - } else if ("lastFmUrl".equals(tagName) && info.getLastFMUrl() == null) { - info.setLastFMUrl(getText()); - } else if ("largeImageUrl".equals(tagName) && info.getImageUrl() == null) { - info.setImageUrl(getText()); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - info.setSimilarArtists(artists); - info.setMissingArtists(missingArtists); - return info; - } -} diff --git a/src/github/daneren2005/dsub/service/parser/BookmarkParser.java b/src/github/daneren2005/dsub/service/parser/BookmarkParser.java deleted file mode 100644 index 8e04749c..00000000 --- a/src/github/daneren2005/dsub/service/parser/BookmarkParser.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2013 (C) Scott Jackson -*/ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Bookmark; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.util.ProgressListener; -import org.xmlpull.v1.XmlPullParser; -import java.io.Reader; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; - -/** - * @author Scott Jackson - */ -public class BookmarkParser extends MusicDirectoryEntryParser { - public BookmarkParser(Context context, int instance) { - super(context, instance); - } - - public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - List bookmarks = new ArrayList(); - Bookmark bookmark = null; - int eventType; - - boolean isDateNormalized = ServerInfo.checkServerVersion(context, "1.11"); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH); - if(isDateNormalized) { - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - } - - do { - eventType = nextParseEvent(); - - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - - if ("bookmark".equals(name)) { - bookmark = new Bookmark(); - - try { - bookmark.setCreated(dateFormat.parse(get("created"))); - } catch (Exception e) { - bookmark.setCreated((Date) null); - } - - try { - bookmark.setChanged(dateFormat.parse(get("changed"))); - } catch (Exception e) { - bookmark.setChanged((Date) null); - } - - bookmark.setComment(get("comment")); - bookmark.setPosition(getInteger("position")); - bookmark.setUsername(get("username")); - } else if ("entry".equals(name)) { - MusicDirectory.Entry entry = parseEntry(null); - // Work around for bookmarks showing entry with a track when podcast listings don't - if("podcast".equals(get("type"))) { - entry.setTrack(null); - } - entry.setBookmark(bookmark); - bookmarks.add(entry); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return new MusicDirectory(bookmarks); - } -} diff --git a/src/github/daneren2005/dsub/service/parser/ChatMessageParser.java b/src/github/daneren2005/dsub/service/parser/ChatMessageParser.java deleted file mode 100644 index 2692d42b..00000000 --- a/src/github/daneren2005/dsub/service/parser/ChatMessageParser.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.ChatMessage; -import github.daneren2005.dsub.util.ProgressListener; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Joshua Bahnsen - */ -public class ChatMessageParser extends AbstractParser { - - public ChatMessageParser(Context context, int instance) { - super(context, instance); - } - - public List parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - List result = new ArrayList(); - int eventType; - - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("chatMessage".equals(name)) { - ChatMessage chatMessage = new ChatMessage(); - chatMessage.setUsername(get("username")); - chatMessage.setTime(getLong("time")); - chatMessage.setMessage(get("message")); - result.add(chatMessage); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return result; - } -} diff --git a/src/github/daneren2005/dsub/service/parser/ErrorParser.java b/src/github/daneren2005/dsub/service/parser/ErrorParser.java deleted file mode 100644 index afb05928..00000000 --- a/src/github/daneren2005/dsub/service/parser/ErrorParser.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; - -/** - * @author Sindre Mehus - */ -public class ErrorParser extends AbstractParser { - - public ErrorParser(Context context, int instance) { - super(context, instance); - } - - public void parse(Reader reader) throws Exception { - - init(reader); - - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG && "error".equals(getElementName())) { - handleError(); - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/GenreParser.java b/src/github/daneren2005/dsub/service/parser/GenreParser.java deleted file mode 100644 index a9860f84..00000000 --- a/src/github/daneren2005/dsub/service/parser/GenreParser.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import android.text.Html; -import android.util.Log; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.util.ProgressListener; - -import org.xmlpull.v1.XmlPullParser; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Joshua Bahnsen - */ -public class GenreParser extends AbstractParser { - private static final String TAG = GenreParser.class.getSimpleName(); - - public GenreParser(Context context, int instance) { - super(context, instance); - } - - public List parse(Reader reader, ProgressListener progressListener) throws Exception { - List result = new ArrayList(); - StringReader sr = null; - - try { - BufferedReader br = new BufferedReader(reader); - String xml = null; - String line = null; - - while ((line = br.readLine()) != null) { - if (xml == null) { - xml = line; - } else { - xml += line; - } - } - br.close(); - - // Replace double escaped ampersand (&apos;) - xml = xml.replaceAll("(?:&)(amp;|lt;|gt;|#37;|apos;)", "&$1"); - - // Replace unescaped ampersand - xml = xml.replaceAll("&(?!amp;|lt;|gt;|#37;|apos;)", "&"); - - // Replace unescaped percent symbol - // No replacements for <> at this time - xml = xml.replaceAll("%", "%"); - - xml = xml.replaceAll("'", "'"); - - sr = new StringReader(xml); - } catch (IOException ioe) { - Log.e(TAG, "Error parsing Genre XML", ioe); - } - - if (sr == null) { - Log.w(TAG, "Unable to parse Genre XML, returning empty list"); - return result; - } - - init(sr); - - Genre genre = null; - - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("genre".equals(name)) { - genre = new Genre(); - genre.setSongCount(getInteger("songCount")); - genre.setAlbumCount(getInteger("albumCount")); - } else if ("error".equals(name)) { - handleError(); - } else { - genre = null; - } - } else if (eventType == XmlPullParser.TEXT) { - if (genre != null) { - String value = getText(); - if (genre != null) { - genre.setName(Html.fromHtml(value).toString()); - genre.setIndex(value.substring(0, 1)); - result.add(genre); - genre = null; - } - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return Genre.GenreComparator.sort(result); - } -} diff --git a/src/github/daneren2005/dsub/service/parser/IndexesParser.java b/src/github/daneren2005/dsub/service/parser/IndexesParser.java deleted file mode 100644 index 0ac86476..00000000 --- a/src/github/daneren2005/dsub/service/parser/IndexesParser.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import java.io.Reader; -import java.util.HashMap; -import java.util.List; -import java.util.ArrayList; -import java.util.Map; - -import org.xmlpull.v1.XmlPullParser; - -import android.content.Context; -import android.content.SharedPreferences; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ProgressListener; -import android.util.Log; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; - -/** - * @author Sindre Mehus - */ -public class IndexesParser extends MusicDirectoryEntryParser { - private static final String TAG = IndexesParser.class.getSimpleName(); - - public IndexesParser(Context context, int instance) { - super(context, instance); - } - - public Indexes parse(Reader reader, ProgressListener progressListener) throws Exception { - long t0 = System.currentTimeMillis(); - init(reader); - - List artists = new ArrayList(); - List shortcuts = new ArrayList(); - List entries = new ArrayList(); - Long lastModified = null; - int eventType; - String index = "#"; - String ignoredArticles = null; - boolean changed = false; - Map artistList = new HashMap(); - - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("indexes".equals(name) || "artists".equals(name)) { - changed = true; - lastModified = getLong("lastModified"); - ignoredArticles = get("ignoredArticles"); - } else if ("index".equals(name)) { - index = get("name"); - - } else if ("artist".equals(name)) { - Artist artist = new Artist(); - artist.setId(get("id")); - artist.setName(get("name")); - artist.setIndex(index); - artist.setStarred(get("starred") != null); - - // Combine the id's for the two artists - if(artistList.containsKey(artist.getName())) { - Artist originalArtist = artistList.get(artist.getName()); - if(originalArtist.isStarred()) { - artist.setStarred(true); - } - originalArtist.setId(originalArtist.getId() + ";" + artist.getId()); - } else { - artistList.put(artist.getName(), artist); - artists.add(artist); - } - - if (artists.size() % 10 == 0) { - String msg = getContext().getResources().getString(R.string.parser_artist_count, artists.size()); - updateProgress(progressListener, msg); - } - } else if ("shortcut".equals(name)) { - Artist shortcut = new Artist(); - shortcut.setId(get("id")); - shortcut.setName(get("name")); - shortcut.setIndex("*"); - shortcut.setStarred(get("starred") != null); - shortcuts.add(shortcut); - } else if("child".equals(name)) { - MusicDirectory.Entry entry = parseEntry(""); - entries.add(entry); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - if(ignoredArticles != null) { - SharedPreferences.Editor prefs = Util.getPreferences(context).edit(); - prefs.putString(Constants.CACHE_KEY_IGNORE, ignoredArticles); - prefs.commit(); - } - - if (!changed) { - return null; - } - - long t1 = System.currentTimeMillis(); - Log.d(TAG, "Got " + artists.size() + " artist(s) in " + (t1 - t0) + "ms."); - - String msg = getContext().getResources().getString(R.string.parser_artist_count, artists.size()); - updateProgress(progressListener, msg); - - return new Indexes(lastModified == null ? 0L : lastModified, shortcuts, artists, entries); - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/JukeboxStatusParser.java b/src/github/daneren2005/dsub/service/parser/JukeboxStatusParser.java deleted file mode 100644 index 95529635..00000000 --- a/src/github/daneren2005/dsub/service/parser/JukeboxStatusParser.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import java.io.Reader; - -import org.xmlpull.v1.XmlPullParser; - -import android.content.Context; -import github.daneren2005.dsub.domain.RemoteStatus; - -/** - * @author Sindre Mehus - */ -public class JukeboxStatusParser extends AbstractParser { - - public JukeboxStatusParser(Context context, int instance) { - super(context, instance); - } - - public RemoteStatus parse(Reader reader) throws Exception { - - init(reader); - - RemoteStatus jukeboxStatus = new RemoteStatus(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("jukeboxPlaylist".equals(name) || "jukeboxStatus".equals(name)) { - jukeboxStatus.setPositionSeconds(getInteger("position")); - jukeboxStatus.setCurrentIndex(getInteger("currentIndex")); - jukeboxStatus.setPlaying(getBoolean("playing")); - jukeboxStatus.setGain(getFloat("gain")); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return jukeboxStatus; - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/LicenseParser.java b/src/github/daneren2005/dsub/service/parser/LicenseParser.java deleted file mode 100644 index 78790062..00000000 --- a/src/github/daneren2005/dsub/service/parser/LicenseParser.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; - -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.domain.Version; - -/** - * @author Sindre Mehus - */ -public class LicenseParser extends AbstractParser { - - public LicenseParser(Context context, int instance) { - super(context, instance); - } - - public ServerInfo parse(Reader reader) throws Exception { - - init(reader); - - ServerInfo serverInfo = new ServerInfo(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("subsonic-response".equals(name)) { - serverInfo.setRestVersion(new Version(get("version"))); - } else if ("license".equals(name)) { - serverInfo.setLicenseValid(getBoolean("valid")); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return serverInfo; - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/LyricsParser.java b/src/github/daneren2005/dsub/service/parser/LyricsParser.java deleted file mode 100644 index e7ce7a4b..00000000 --- a/src/github/daneren2005/dsub/service/parser/LyricsParser.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Lyrics; -import github.daneren2005.dsub.util.ProgressListener; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; - -/** - * @author Sindre Mehus - */ -public class LyricsParser extends AbstractParser { - - public LyricsParser(Context context, int instance) { - super(context, instance); - } - - public Lyrics parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - Lyrics lyrics = null; - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("lyrics".equals(name)) { - lyrics = new Lyrics(); - lyrics.setArtist(get("artist")); - lyrics.setTitle(get("title")); - } else if ("error".equals(name)) { - handleError(); - } - } else if (eventType == XmlPullParser.TEXT) { - if (lyrics != null && lyrics.getText() == null) { - lyrics.setText(getText()); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - return lyrics; - } -} diff --git a/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java b/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java deleted file mode 100644 index 9542324e..00000000 --- a/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; - -import github.daneren2005.dsub.domain.Bookmark; -import github.daneren2005.dsub.domain.MusicDirectory; - -/** - * @author Sindre Mehus - */ -public class MusicDirectoryEntryParser extends AbstractParser { - public MusicDirectoryEntryParser(Context context, int instance) { - super(context, instance); - } - - protected MusicDirectory.Entry parseEntry(String artist) { - MusicDirectory.Entry entry = new MusicDirectory.Entry(); - entry.setId(get("id")); - entry.setParent(get("parent")); - entry.setArtistId(get("artistId")); - entry.setTitle(get("title")); - if(entry.getTitle() == null) { - entry.setTitle(get("name")); - } - entry.setDirectory(getBoolean("isDir")); - entry.setCoverArt(get("coverArt")); - entry.setArtist(get("artist")); - entry.setStarred(get("starred") != null); - entry.setYear(getInteger("year")); - entry.setGenre(get("genre")); - entry.setAlbum(get("album")); - entry.setRating(getInteger("userRating")); - - if (!entry.isDirectory()) { - entry.setAlbumId(get("albumId")); - entry.setTrack(getInteger("track")); - entry.setContentType(get("contentType")); - entry.setSuffix(get("suffix")); - entry.setTranscodedContentType(get("transcodedContentType")); - entry.setTranscodedSuffix(get("transcodedSuffix")); - entry.setSize(getLong("size")); - entry.setDuration(getInteger("duration")); - entry.setBitRate(getInteger("bitRate")); - entry.setPath(get("path")); - entry.setVideo(getBoolean("isVideo")); - entry.setDiscNumber(getInteger("discNumber")); - - Integer bookmark = getInteger("bookmarkPosition"); - if(bookmark != null) { - entry.setBookmark(new Bookmark(bookmark)); - } - - String type = get("type"); - if("podcast".equals(type)) { - entry.setType(MusicDirectory.Entry.TYPE_PODCAST); - } else if("audiobook".equals(type) || (entry.getGenre() != null && "audiobook".equals(entry.getGenre().toLowerCase()))) { - entry.setType(MusicDirectory.Entry.TYPE_AUDIO_BOOK); - } - } else if(!"".equals(artist)) { - entry.setPath(artist + "/" + entry.getTitle()); - } - return entry; - } - - protected MusicDirectory.Entry parseArtist() { - MusicDirectory.Entry entry = new MusicDirectory.Entry(); - - entry.setId(get("id")); - entry.setTitle(get("name")); - entry.setPath(entry.getTitle()); - entry.setStarred(true); - entry.setDirectory(true); - - return entry; - } -} diff --git a/src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java b/src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java deleted file mode 100644 index a786bceb..00000000 --- a/src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import android.util.Log; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.Util; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; -import java.util.HashMap; -import java.util.Map; - -import static github.daneren2005.dsub.domain.MusicDirectory.*; - -/** - * @author Sindre Mehus - */ -public class MusicDirectoryParser extends MusicDirectoryEntryParser { - - private static final String TAG = MusicDirectoryParser.class.getSimpleName(); - - public MusicDirectoryParser(Context context, int instance) { - super(context, instance); - } - - public MusicDirectory parse(String artist, Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - MusicDirectory dir = new MusicDirectory(); - int eventType; - boolean isArtist = false; - boolean checkForDuplicates = Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_RENAME_DUPLICATES, true); - Map titleMap = new HashMap(); - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("child".equals(name) || "song".equals(name) || "video".equals(name)) { - Entry entry = parseEntry(artist); - entry.setGrandParent(dir.getParent()); - - // Only check for songs - if(checkForDuplicates && !entry.isDirectory()) { - // Check if duplicates - Entry duplicate = titleMap.get(entry.getTitle()); - if (duplicate != null) { - // Check if the first already has been rebased or not - if (duplicate.getTitle().equals(entry.getTitle())) { - duplicate.rebaseTitleOffPath(); - } - - // Rebase if this is the second instance of this title found - entry.rebaseTitleOffPath(); - } else { - titleMap.put(entry.getTitle(), entry); - } - } - - dir.addChild(entry); - } else if ("directory".equals(name) || "artist".equals(name) || ("album".equals(name) && !isArtist)) { - dir.setName(get("name")); - dir.setId(get("id")); - if(Util.isTagBrowsing(context, instance)) { - dir.setParent(get("artistId")); - } else { - dir.setParent(get("parent")); - } - isArtist = true; - } else if("album".equals(name)) { - Entry entry = parseEntry(artist); - entry.setDirectory(true); - dir.addChild(entry); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - // Only apply sorting on server version 4.7 and greater, where disc is supported - dir.sortChildren(context, instance); - - return dir; - } -} diff --git a/src/github/daneren2005/dsub/service/parser/MusicFoldersParser.java b/src/github/daneren2005/dsub/service/parser/MusicFoldersParser.java deleted file mode 100644 index a525084e..00000000 --- a/src/github/daneren2005/dsub/service/parser/MusicFoldersParser.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; - -import org.xmlpull.v1.XmlPullParser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicFolder; -import github.daneren2005.dsub.util.ProgressListener; - -/** - * @author Sindre Mehus - */ -public class MusicFoldersParser extends AbstractParser { - - public MusicFoldersParser(Context context, int instance) { - super(context, instance); - } - - public List parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - List result = new ArrayList(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String tag = getElementName(); - if ("musicFolder".equals(tag)) { - String id = get("id"); - String name = get("name"); - result.add(new MusicFolder(id, name)); - } else if ("error".equals(tag)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return result; - } - -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/PlayQueueParser.java b/src/github/daneren2005/dsub/service/parser/PlayQueueParser.java deleted file mode 100644 index ec161d2b..00000000 --- a/src/github/daneren2005/dsub/service/parser/PlayQueueParser.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2015 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.service.parser; - -import android.content.Context; - -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Locale; -import java.util.TimeZone; - -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerQueue; -import github.daneren2005.dsub.util.ProgressListener; - -public class PlayQueueParser extends MusicDirectoryEntryParser { - private static final String TAG = PlayQueueParser.class.getSimpleName(); - - public PlayQueueParser(Context context, int instance) { - super(context, instance); - } - - public PlayerQueue parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - PlayerQueue state = new PlayerQueue(); - String currentId = null; - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if("playQueue".equals(name)) { - currentId = get("current"); - state.currentPlayingPosition = getInteger("position"); - try { - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - state.changed = dateFormat.parse(get("changed")); - } catch (ParseException e) { - state.changed = null; - } - } else if ("entry".equals(name)) { - MusicDirectory.Entry entry = parseEntry(""); - // Only add songs - if(!entry.isVideo()) { - state.songs.add(entry); - } - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - if(currentId != null) { - for (MusicDirectory.Entry entry : state.songs) { - if (entry.getId().equals(currentId)) { - state.currentPlayingIndex = state.songs.indexOf(entry); - } - } - } else { - state.currentPlayingIndex = 0; - state.currentPlayingPosition = 0; - } - - validate(); - return state; - } -} diff --git a/src/github/daneren2005/dsub/service/parser/PlaylistParser.java b/src/github/daneren2005/dsub/service/parser/PlaylistParser.java deleted file mode 100644 index 5bb07dfd..00000000 --- a/src/github/daneren2005/dsub/service/parser/PlaylistParser.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ProgressListener; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; - -/** - * @author Sindre Mehus - */ -public class PlaylistParser extends MusicDirectoryEntryParser { - - public PlaylistParser(Context context, int instance) { - super(context, instance); - } - - public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - MusicDirectory dir = new MusicDirectory(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("entry".equals(name)) { - dir.addChild(parseEntry("")); - } else if ("error".equals(name)) { - handleError(); - } else if ("playlist".equals(name)) { - dir.setName(get("name")); - dir.setId(get("id")); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return dir; - } - -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/PlaylistsParser.java b/src/github/daneren2005/dsub/service/parser/PlaylistsParser.java deleted file mode 100644 index 6f01d510..00000000 --- a/src/github/daneren2005/dsub/service/parser/PlaylistsParser.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; - -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.adapter.PlaylistAdapter; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Sindre Mehus - */ -public class PlaylistsParser extends AbstractParser { - - public PlaylistsParser(Context context, int instance) { - super(context, instance); - } - - public List parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - List result = new ArrayList(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String tag = getElementName(); - if ("playlist".equals(tag)) { - String id = get("id"); - String name = get("name"); - String owner = get("owner"); - String comment = get("comment"); - String songCount = get("songCount"); - String created = get("created"); - String pub = get("public"); - result.add(new Playlist(id, name, owner, comment, songCount, created, pub)); - } else if ("error".equals(tag)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return PlaylistAdapter.PlaylistComparator.sort(result); - } - -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java b/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java deleted file mode 100644 index 8c77e2bc..00000000 --- a/src/github/daneren2005/dsub/service/parser/PodcastChannelParser.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.util.ProgressListener; -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; -import org.xmlpull.v1.XmlPullParser; - -/** - * - * @author Scott - */ -public class PodcastChannelParser extends AbstractParser { - public PodcastChannelParser(Context context, int instance) { - super(context, instance); - } - - public List parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - List channels = new ArrayList(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("channel".equals(name)) { - PodcastChannel channel = new PodcastChannel(); - channel.setId(get("id")); - channel.setUrl(get("url")); - channel.setName(get("title")); - channel.setDescription(get("description")); - channel.setStatus(get("status")); - channel.setErrorMessage(get("errorMessage")); - channels.add(channel); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - return PodcastChannel.PodcastComparator.sort(channels, context); - } -} diff --git a/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java b/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java deleted file mode 100644 index fe742819..00000000 --- a/src/github/daneren2005/dsub/service/parser/PodcastEntryParser.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Bookmark; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ProgressListener; -import java.io.Reader; -import org.xmlpull.v1.XmlPullParser; - -/** - * - * @author Scott - */ -public class PodcastEntryParser extends AbstractParser { - private static int bogusId = -1; - - public PodcastEntryParser(Context context, int instance) { - super(context, instance); - } - - public MusicDirectory parse(String channel, Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - MusicDirectory episodes = new MusicDirectory(); - int eventType; - boolean valid = false; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("channel".equals(name)) { - String id = get("id"); - if(id.equals(channel)) { - episodes.setId(id); - episodes.setName(get("title")); - valid = true; - } else { - valid = false; - } - } - else if ("episode".equals(name) && valid) { - PodcastEpisode episode = new PodcastEpisode(); - episode.setEpisodeId(get("id")); - episode.setId(get("streamId")); - episode.setTitle(get("title")); - episode.setParent(episodes.getId()); - episode.setArtist(episodes.getName()); - episode.setAlbum(get("description")); - episode.setDate(get("publishDate")); - if(episode.getDate() == null) { - episode.setDate(get("created")); - } - if(episode.getDate() != null && episode.getDate().indexOf("T") != -1) { - episode.setDate(episode.getDate().replace("T", " ")); - } - episode.setStatus(get("status")); - episode.setCoverArt(get("coverArt")); - episode.setSize(getLong("size")); - episode.setContentType(get("contentType")); - episode.setSuffix(get("suffix")); - episode.setDuration(getInteger("duration")); - episode.setBitRate(getInteger("bitRate")); - episode.setVideo(getBoolean("isVideo")); - episode.setPath(get("path")); - if(episode.getPath() == null) { - episode.setPath(FileUtil.getPodcastPath(context, episode)); - } else if(episode.getPath().indexOf("Podcasts/") == 0) { - episode.setPath(episode.getPath().substring("Podcasts/".length())); - } - - Integer bookmark = getInteger("bookmarkPosition"); - if(bookmark != null) { - episode.setBookmark(new Bookmark(bookmark)); - } - episode.setType(MusicDirectory.Entry.TYPE_PODCAST); - - if(episode.getId() == null) { - episode.setId(String.valueOf(bogusId)); - bogusId--; - } - episodes.addChild(episode); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - return episodes; - } -} diff --git a/src/github/daneren2005/dsub/service/parser/RandomSongsParser.java b/src/github/daneren2005/dsub/service/parser/RandomSongsParser.java deleted file mode 100644 index 37057723..00000000 --- a/src/github/daneren2005/dsub/service/parser/RandomSongsParser.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ProgressListener; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; - -/** - * @author Sindre Mehus - */ -public class RandomSongsParser extends MusicDirectoryEntryParser { - - public RandomSongsParser(Context context, int instance) { - super(context, instance); - } - - public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - MusicDirectory dir = new MusicDirectory(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("song".equals(name)) { - dir.addChild(parseEntry("")); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return dir; - } - -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/ScanStatusParser.java b/src/github/daneren2005/dsub/service/parser/ScanStatusParser.java deleted file mode 100644 index 395dbcb6..00000000 --- a/src/github/daneren2005/dsub/service/parser/ScanStatusParser.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.util.ProgressListener; - -public class ScanStatusParser extends AbstractParser { - - public ScanStatusParser(Context context, int instance) { - super(context, instance); - } - - public boolean parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - Boolean started = null; - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if("status".equals(name)) { - started = getBoolean("started"); - - String msg = context.getResources().getString(R.string.parser_scan_count, getInteger("count")); - progressListener.updateProgress(msg); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return started != null && started; - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/SearchResult2Parser.java b/src/github/daneren2005/dsub/service/parser/SearchResult2Parser.java deleted file mode 100644 index 8cc0c50d..00000000 --- a/src/github/daneren2005/dsub/service/parser/SearchResult2Parser.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.util.ProgressListener; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; -import java.util.List; -import java.util.ArrayList; - -/** - * @author Sindre Mehus - */ -public class SearchResult2Parser extends MusicDirectoryEntryParser { - - public SearchResult2Parser(Context context, int instance) { - super(context, instance); - } - - public SearchResult parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - List artists = new ArrayList(); - List albums = new ArrayList(); - List songs = new ArrayList(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("artist".equals(name)) { - Artist artist = new Artist(); - artist.setId(get("id")); - artist.setName(get("name")); - artists.add(artist); - } else if ("album".equals(name)) { - MusicDirectory.Entry entry = parseEntry(""); - entry.setDirectory(true); - albums.add(entry); - } else if ("song".equals(name)) { - songs.add(parseEntry("")); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return new SearchResult(artists, albums, songs); - } - -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/SearchResultParser.java b/src/github/daneren2005/dsub/service/parser/SearchResultParser.java deleted file mode 100644 index 252a7b20..00000000 --- a/src/github/daneren2005/dsub/service/parser/SearchResultParser.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.SearchResult; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.util.ProgressListener; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; -import java.util.Collections; -import java.util.List; -import java.util.ArrayList; - -/** - * @author Sindre Mehus - */ -public class SearchResultParser extends MusicDirectoryEntryParser { - - public SearchResultParser(Context context, int instance) { - super(context, instance); - } - - public SearchResult parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - List songs = new ArrayList(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("match".equals(name)) { - songs.add(parseEntry("")); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return new SearchResult(Collections.emptyList(), Collections.emptyList(), songs); - } - -} diff --git a/src/github/daneren2005/dsub/service/parser/ShareParser.java b/src/github/daneren2005/dsub/service/parser/ShareParser.java deleted file mode 100644 index 375629d9..00000000 --- a/src/github/daneren2005/dsub/service/parser/ShareParser.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import android.content.SharedPreferences; -import android.util.Log; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.domain.Share; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.Util; - -import org.xmlpull.v1.XmlPullParser; -import java.io.Reader; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; - -/** - * @author Joshua Bahnsen - */ -public class ShareParser extends MusicDirectoryEntryParser { - private static final String TAG = ShareParser.class.getSimpleName(); - - public ShareParser(Context context, int instance) { - super(context, instance); - } - - public List parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - List dir = new ArrayList(); - Share share = null; - int eventType; - - SharedPreferences prefs = Util.getPreferences(context); - int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); - String serverUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null); - if(serverUrl.charAt(serverUrl.length() - 1) != '/') { - serverUrl += '/'; - } - serverUrl += "share/"; - - boolean isDateNormalized = ServerInfo.checkServerVersion(context, "1.11"); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH); - if(isDateNormalized) { - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - } - - do { - eventType = nextParseEvent(); - - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - - if ("share".equals(name)) { - share = new Share(); - - try { - share.setCreated(dateFormat.parse(get("created"))); - } catch (Exception e) { - share.setCreated((Date) null); - } - - String url = get("url"); - if(url != null && url.indexOf(".php") == -1) { - url = url.replaceFirst(".*/([^/?]+).*", serverUrl + "$1"); - } - share.setUrl(url); - - share.setDescription(get("description")); - - try { - share.setExpires(dateFormat.parse(get("expires"))); - } catch (Exception e) { - share.setExpires((Date) null); - } - share.setId(get("id")); - - try { - share.setLastVisited(dateFormat.parse(get("lastVisited"))); - } catch (Exception e) { - share.setLastVisited((Date) null); - } - - share.setUsername(get("username")); - share.setVisitCount(getLong("visitCount")); - dir.add(share); - } else if ("entry".equals(name)) { - if(share != null) { - share.addEntry(parseEntry(null)); - } - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return dir; - } -} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/service/parser/StarredListParser.java b/src/github/daneren2005/dsub/service/parser/StarredListParser.java deleted file mode 100644 index 59652e29..00000000 --- a/src/github/daneren2005/dsub/service/parser/StarredListParser.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.service.parser; - -import android.content.Context; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ProgressListener; -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; - -/** - * @author Kurt Hardin - */ -public class StarredListParser extends MusicDirectoryEntryParser { - - public StarredListParser(Context context, int instance) { - super(context, instance); - } - - public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - MusicDirectory dir = new MusicDirectory(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("album".equals(name) || "song".equals(name)) { - MusicDirectory.Entry entry = parseEntry(""); - if("album".equals(name)) { - entry.setDirectory(true); - } - dir.addChild(entry); - } else if("artist".equals(name)) { - MusicDirectory.Entry entry = parseArtist(); - entry.setDirectory(true); - entry.setArtist(null); - entry.setParent(null); - dir.addChild(entry); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return dir; - } -} diff --git a/src/github/daneren2005/dsub/service/parser/SubsonicRESTException.java b/src/github/daneren2005/dsub/service/parser/SubsonicRESTException.java deleted file mode 100644 index 096597a1..00000000 --- a/src/github/daneren2005/dsub/service/parser/SubsonicRESTException.java +++ /dev/null @@ -1,19 +0,0 @@ -package github.daneren2005.dsub.service.parser; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public class SubsonicRESTException extends Exception { - - private final int code; - - public SubsonicRESTException(int code, String message) { - super(message); - this.code = code; - } - - public int getCode() { - return code; - } -} diff --git a/src/github/daneren2005/dsub/service/parser/UserParser.java b/src/github/daneren2005/dsub/service/parser/UserParser.java deleted file mode 100644 index c8b56080..00000000 --- a/src/github/daneren2005/dsub/service/parser/UserParser.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.service.parser; - -import android.content.Context; - -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.domain.User; -import github.daneren2005.dsub.util.ProgressListener; - -public class UserParser extends AbstractParser { - - public UserParser(Context context, int instance) { - super(context, instance); - } - - public List parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - List result = new ArrayList(); - int eventType; - - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("user".equals(name)) { - User user = new User(); - - user.setUsername(get("username")); - user.setEmail(get("email")); - parseSetting(user, User.SCROBBLING); - for(String role: User.ROLES) { - parseSetting(user, role); - } - parseSetting(user, User.LASTFM); - - result.add(user); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - - return result; - } - - private void parseSetting(User user, String name) { - String value = get(name); - if(value != null) { - user.addSetting(name, "true".equals(value)); - } - } -} diff --git a/src/github/daneren2005/dsub/service/parser/VideosParser.java b/src/github/daneren2005/dsub/service/parser/VideosParser.java deleted file mode 100644 index f22c4a4a..00000000 --- a/src/github/daneren2005/dsub/service/parser/VideosParser.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2015 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.service.parser; - -import android.content.Context; - -import org.xmlpull.v1.XmlPullParser; - -import java.io.Reader; - -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ProgressListener; - -public class VideosParser extends MusicDirectoryEntryParser { - public VideosParser(Context context, int instance) { - super(context, instance); - } - - public MusicDirectory parse(Reader reader, ProgressListener progressListener) throws Exception { - init(reader); - - MusicDirectory dir = new MusicDirectory(); - int eventType; - do { - eventType = nextParseEvent(); - if (eventType == XmlPullParser.START_TAG) { - String name = getElementName(); - if ("video".equals(name)) { - MusicDirectory.Entry entry = parseEntry(""); - dir.addChild(entry); - } else if ("error".equals(name)) { - handleError(); - } - } - } while (eventType != XmlPullParser.END_DOCUMENT); - - validate(); - return dir; - } -} diff --git a/src/github/daneren2005/dsub/service/ssl/SSLSocketFactory.java b/src/github/daneren2005/dsub/service/ssl/SSLSocketFactory.java deleted file mode 100644 index 3b1203c7..00000000 --- a/src/github/daneren2005/dsub/service/ssl/SSLSocketFactory.java +++ /dev/null @@ -1,549 +0,0 @@ -/* - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -package github.daneren2005.dsub.service.ssl; - -import android.util.Log; - -import org.apache.http.conn.ConnectTimeoutException; -import org.apache.http.conn.scheme.HostNameResolver; -import org.apache.http.conn.scheme.LayeredSocketFactory; -import org.apache.http.conn.ssl.AllowAllHostnameVerifier; -import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier; -import org.apache.http.conn.ssl.StrictHostnameVerifier; -import org.apache.http.conn.ssl.X509HostnameVerifier; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; - -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import java.io.IOException; -import java.lang.reflect.Array; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.Provider; -import java.security.SecureRandom; -import java.security.Security; -import java.security.UnrecoverableKeyException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Layered socket factory for TLS/SSL connections. - *

- * SSLSocketFactory can be used to validate the identity of the HTTPS server against a list of - * trusted certificates and to authenticate to the HTTPS server using a private key. - *

- * SSLSocketFactory will enable server authentication when supplied with - * a {@link KeyStore trust-store} file containing one or several trusted certificates. The client - * secure socket will reject the connection during the SSL session handshake if the target HTTPS - * server attempts to authenticate itself with a non-trusted certificate. - *

- * Use JDK keytool utility to import a trusted certificate and generate a trust-store file: - *

- *     keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
- *    
- *

- * In special cases the standard trust verification process can be bypassed by using a custom - * {@link TrustStrategy}. This interface is primarily intended for allowing self-signed - * certificates to be accepted as trusted without having to add them to the trust-store file. - *

- * The following parameters can be used to customize the behavior of this - * class: - *

    - *
  • {@link org.apache.http.params.CoreConnectionPNames#CONNECTION_TIMEOUT}
  • - *
  • {@link org.apache.http.params.CoreConnectionPNames#SO_TIMEOUT}
  • - *
- *

- * SSLSocketFactory will enable client authentication when supplied with - * a {@link KeyStore key-store} file containing a private key/public certificate - * pair. The client secure socket will use the private key to authenticate - * itself to the target HTTPS server during the SSL session handshake if - * requested to do so by the server. - * The target HTTPS server will in its turn verify the certificate presented - * by the client in order to establish client's authenticity - *

- * Use the following sequence of actions to generate a key-store file - *

- *
    - *
  • - *

    - * Use JDK keytool utility to generate a new key - *

    keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore
    - * For simplicity use the same password for the key as that of the key-store - *

    - *
  • - *
  • - *

    - * Issue a certificate signing request (CSR) - *

    keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore
    - *

    - *
  • - *
  • - *

    - * Send the certificate request to the trusted Certificate Authority for signature. - * One may choose to act as her own CA and sign the certificate request using a PKI - * tool, such as OpenSSL. - *

    - *
  • - *
  • - *

    - * Import the trusted CA root certificate - *

    keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore
    - *

    - *
  • - *
  • - *

    - * Import the PKCS#7 file containg the complete certificate chain - *

    keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore
    - *

    - *
  • - *
  • - *

    - * Verify the content the resultant keystore file - *

    keytool -list -v -keystore my.keystore
    - *

    - *
  • - *
- * - * @since 4.0 - */ -public class SSLSocketFactory implements LayeredSocketFactory { - private static final String TAG = SSLSocketFactory.class.getSimpleName(); - public static final String TLS = "TLS"; - - public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER - = new AllowAllHostnameVerifier(); - - public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER - = new BrowserCompatHostnameVerifier(); - - public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER - = new StrictHostnameVerifier(); - - /** - * The default factory using the default JVM settings for secure connections. - */ - private static final SSLSocketFactory DEFAULT_FACTORY = new SSLSocketFactory(); - - /** - * Gets the default factory, which uses the default JVM settings for secure - * connections. - * - * @return the default factory - */ - public static SSLSocketFactory getSocketFactory() { - return DEFAULT_FACTORY; - } - - private final javax.net.ssl.SSLSocketFactory socketfactory; - private final HostNameResolver nameResolver; - // TODO: make final - private volatile X509HostnameVerifier hostnameVerifier; - - private static SSLContext createSSLContext( - String algorithm, - final KeyStore keystore, - final String keystorePassword, - final KeyStore truststore, - final SecureRandom random, - final TrustStrategy trustStrategy) - throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, KeyManagementException { - if (algorithm == null) { - algorithm = TLS; - } - KeyManagerFactory kmfactory = KeyManagerFactory.getInstance( - KeyManagerFactory.getDefaultAlgorithm()); - kmfactory.init(keystore, keystorePassword != null ? keystorePassword.toCharArray(): null); - KeyManager[] keymanagers = kmfactory.getKeyManagers(); - TrustManagerFactory tmfactory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - tmfactory.init(keystore); - TrustManager[] trustmanagers = tmfactory.getTrustManagers(); - if (trustmanagers != null && trustStrategy != null) { - for (int i = 0; i < trustmanagers.length; i++) { - TrustManager tm = trustmanagers[i]; - if (tm instanceof X509TrustManager) { - trustmanagers[i] = new TrustManagerDecorator( - (X509TrustManager) tm, trustStrategy); - } - } - } - - SSLContext sslcontext = SSLContext.getInstance(algorithm); - sslcontext.init(keymanagers, trustmanagers, random); - return sslcontext; - } - - /** - * @deprecated Use {@link #SSLSocketFactory(String, KeyStore, String, KeyStore, SecureRandom, X509HostnameVerifier)} - */ - @Deprecated - public SSLSocketFactory( - final String algorithm, - final KeyStore keystore, - final String keystorePassword, - final KeyStore truststore, - final SecureRandom random, - final HostNameResolver nameResolver) - throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { - this(createSSLContext( - algorithm, keystore, keystorePassword, truststore, random, null), - nameResolver); - } - - /** - * @since 4.1 - */ - public SSLSocketFactory( - String algorithm, - final KeyStore keystore, - final String keystorePassword, - final KeyStore truststore, - final SecureRandom random, - final X509HostnameVerifier hostnameVerifier) - throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { - this(createSSLContext( - algorithm, keystore, keystorePassword, truststore, random, null), - hostnameVerifier); - } - - /** - * @since 4.1 - */ - public SSLSocketFactory( - String algorithm, - final KeyStore keystore, - final String keystorePassword, - final KeyStore truststore, - final SecureRandom random, - final TrustStrategy trustStrategy, - final X509HostnameVerifier hostnameVerifier) - throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { - this(createSSLContext( - algorithm, keystore, keystorePassword, truststore, random, trustStrategy), - hostnameVerifier); - } - - public SSLSocketFactory( - final KeyStore keystore, - final String keystorePassword, - final KeyStore truststore) - throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { - this(TLS, keystore, keystorePassword, truststore, null, null, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); - } - - public SSLSocketFactory( - final KeyStore keystore, - final String keystorePassword) - throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException{ - this(TLS, keystore, keystorePassword, null, null, null, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); - } - - public SSLSocketFactory( - final KeyStore truststore) - throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { - this(TLS, null, null, truststore, null, null, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); - } - - /** - * @since 4.1 - */ - public SSLSocketFactory( - final TrustStrategy trustStrategy, - final X509HostnameVerifier hostnameVerifier) - throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { - this(TLS, null, null, null, null, trustStrategy, hostnameVerifier); - } - - /** - * @since 4.1 - */ - public SSLSocketFactory( - final TrustStrategy trustStrategy) - throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { - this(TLS, null, null, null, null, trustStrategy, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); - } - - public SSLSocketFactory(final SSLContext sslContext) { - this(sslContext, BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); - } - - /** - * @deprecated Use {@link #SSLSocketFactory(SSLContext)} - */ - @Deprecated - public SSLSocketFactory( - final SSLContext sslContext, final HostNameResolver nameResolver) { - super(); - this.socketfactory = sslContext.getSocketFactory(); - this.hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER; - this.nameResolver = nameResolver; - } - - /** - * @since 4.1 - */ - public SSLSocketFactory( - final SSLContext sslContext, final X509HostnameVerifier hostnameVerifier) { - super(); - this.socketfactory = sslContext.getSocketFactory(); - this.hostnameVerifier = hostnameVerifier; - this.nameResolver = null; - } - - private SSLSocketFactory() { - super(); - this.socketfactory = HttpsURLConnection.getDefaultSSLSocketFactory(); - this.hostnameVerifier = null; - this.nameResolver = null; - } - - /** - * @param params Optional parameters. Parameters passed to this method will have no effect. - * This method will create a unconnected instance of {@link Socket} class - * using {@link javax.net.ssl.SSLSocketFactory#createSocket()} method. - * @since 4.1 - */ - @SuppressWarnings("cast") - public Socket createSocket(final HttpParams params) throws IOException { - // the cast makes sure that the factory is working as expected - SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(); - sslSocket.setEnabledProtocols(getProtocols(sslSocket)); - sslSocket.setEnabledCipherSuites(getCiphers(sslSocket)); - return sslSocket; - } - - @SuppressWarnings("cast") - public Socket createSocket() throws IOException { - // the cast makes sure that the factory is working as expected - SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(); - sslSocket.setEnabledProtocols(getProtocols(sslSocket)); - sslSocket.setEnabledCipherSuites(getCiphers(sslSocket)); - return sslSocket; - } - - /** - * @since 4.1 - */ - public Socket connectSocket( - final Socket sock, - final InetSocketAddress remoteAddress, - final InetSocketAddress localAddress, - final HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException { - if (remoteAddress == null) { - throw new IllegalArgumentException("Remote address may not be null"); - } - if (params == null) { - throw new IllegalArgumentException("HTTP parameters may not be null"); - } - SSLSocket sslsock = (SSLSocket) (sock != null ? sock : createSocket()); - if (localAddress != null) { -// sslsock.setReuseAddress(HttpConnectionParams.getSoReuseaddr(params)); - sslsock.bind(localAddress); - } - - setHostName(sslsock, remoteAddress.getHostName()); - int connTimeout = HttpConnectionParams.getConnectionTimeout(params); - int soTimeout = HttpConnectionParams.getSoTimeout(params); - - try { - sslsock.connect(remoteAddress, connTimeout); - } catch (SocketTimeoutException ex) { - throw new ConnectTimeoutException("Connect to " + remoteAddress.getHostName() + "/" - + remoteAddress.getAddress() + " timed out"); - } - sslsock.setSoTimeout(soTimeout); - if (this.hostnameVerifier != null) { - try { - this.hostnameVerifier.verify(remoteAddress.getHostName(), sslsock); - // verifyHostName() didn't blowup - good! - } catch (IOException iox) { - // close the socket before re-throwing the exception - try { sslsock.close(); } catch (Exception x) { /*ignore*/ } - throw iox; - } - } - return sslsock; - } - - - /** - * Checks whether a socket connection is secure. - * This factory creates TLS/SSL socket connections - * which, by default, are considered secure. - *
- * Derived classes may override this method to perform - * runtime checks, for example based on the cypher suite. - * - * @param sock the connected socket - * - * @return true - * - * @throws IllegalArgumentException if the argument is invalid - */ - public boolean isSecure(final Socket sock) throws IllegalArgumentException { - if (sock == null) { - throw new IllegalArgumentException("Socket may not be null"); - } - // This instanceof check is in line with createSocket() above. - if (!(sock instanceof SSLSocket)) { - throw new IllegalArgumentException("Socket not created by this factory"); - } - // This check is performed last since it calls the argument object. - if (sock.isClosed()) { - throw new IllegalArgumentException("Socket is closed"); - } - return true; - } - - /** - * @since 4.1 - */ - public Socket createLayeredSocket( - final Socket socket, - final String host, - final int port, - final boolean autoClose) throws IOException, UnknownHostException { - SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket( - socket, - host, - port, - autoClose - ); - sslSocket.setEnabledProtocols(getProtocols(sslSocket)); - sslSocket.setEnabledCipherSuites(getCiphers(sslSocket)); - if (this.hostnameVerifier != null) { - this.hostnameVerifier.verify(host, sslSocket); - } - // verifyHostName() didn't blowup - good! - return sslSocket; - } - - @Deprecated - public void setHostnameVerifier(X509HostnameVerifier hostnameVerifier) { - if ( hostnameVerifier == null ) { - throw new IllegalArgumentException("Hostname verifier may not be null"); - } - this.hostnameVerifier = hostnameVerifier; - } - - public X509HostnameVerifier getHostnameVerifier() { - return this.hostnameVerifier; - } - - /** - * @deprecated Use {@link #connectSocket(Socket, InetSocketAddress, InetSocketAddress, HttpParams)} - */ - @Deprecated - public Socket connectSocket( - final Socket socket, - final String host, int port, - final InetAddress localAddress, int localPort, - final HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException { - InetSocketAddress local = null; - if (localAddress != null || localPort > 0) { - // we need to bind explicitly - if (localPort < 0) { - localPort = 0; // indicates "any" - } - local = new InetSocketAddress(localAddress, localPort); - } - InetAddress remoteAddress; - if (this.nameResolver != null) { - remoteAddress = this.nameResolver.resolve(host); - } else { - remoteAddress = InetAddress.getByName(host); - } - InetSocketAddress remote = new InetSocketAddress(remoteAddress, port); - return connectSocket(socket, remote, local, params); - } - - /** - * @deprecated Use {@link #createLayeredSocket(Socket, String, int, boolean)} - */ - @Deprecated - public Socket createSocket( - final Socket socket, - final String host, int port, - boolean autoClose) throws IOException, UnknownHostException { - SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket(socket, host, port, autoClose); - sslSocket.setEnabledProtocols(getProtocols(sslSocket)); - sslSocket.setEnabledCipherSuites(getCiphers(sslSocket)); - setHostName(sslSocket, host); - return sslSocket; - } - - private void setHostName(SSLSocket sslsock, String hostname){ - try { - java.lang.reflect.Method setHostnameMethod = sslsock.getClass().getMethod("setHostname", String.class); - setHostnameMethod.invoke(sslsock, hostname); - } catch (Exception e) { - Log.w(TAG, "SNI not useable", e); - } - } - - private String[] getProtocols(SSLSocket sslSocket) { - String[] protocols = sslSocket.getEnabledProtocols(); - - // Remove SSLv3 if it is not the only option - if(protocols.length > 1) { - List protocolList = new ArrayList(Arrays.asList(protocols)); - protocolList.remove("SSLv3"); - protocols = protocolList.toArray(new String[protocolList.size()]); - } - - return protocols; - } - - private String[] getCiphers(SSLSocket sslSocket) { - String[] ciphers = sslSocket.getEnabledCipherSuites(); - - List enabledCiphers = new ArrayList(Arrays.asList(ciphers)); - // On Android 5.0 release, Jetty doesn't seem to play nice with these ciphers - enabledCiphers.remove("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"); - enabledCiphers.remove("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"); - - ciphers = enabledCiphers.toArray(new String[enabledCiphers.size()]); - return ciphers; - } -} diff --git a/src/github/daneren2005/dsub/service/ssl/TrustManagerDecorator.java b/src/github/daneren2005/dsub/service/ssl/TrustManagerDecorator.java deleted file mode 100644 index f2364368..00000000 --- a/src/github/daneren2005/dsub/service/ssl/TrustManagerDecorator.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ -package github.daneren2005.dsub.service.ssl; - -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.X509TrustManager; - - -/** - * @since 4.1 - */ -class TrustManagerDecorator implements X509TrustManager { - - private final X509TrustManager trustManager; - private final TrustStrategy trustStrategy; - - TrustManagerDecorator(final X509TrustManager trustManager, final TrustStrategy trustStrategy) { - super(); - this.trustManager = trustManager; - this.trustStrategy = trustStrategy; - } - - public void checkClientTrusted( - final X509Certificate[] chain, final String authType) throws CertificateException { - this.trustManager.checkClientTrusted(chain, authType); - } - - public void checkServerTrusted( - final X509Certificate[] chain, final String authType) throws CertificateException { - if (!this.trustStrategy.isTrusted(chain, authType)) { - this.trustManager.checkServerTrusted(chain, authType); - } - } - - public X509Certificate[] getAcceptedIssuers() { - return this.trustManager.getAcceptedIssuers(); - } - -} diff --git a/src/github/daneren2005/dsub/service/ssl/TrustSelfSignedStrategy.java b/src/github/daneren2005/dsub/service/ssl/TrustSelfSignedStrategy.java deleted file mode 100644 index 637a8931..00000000 --- a/src/github/daneren2005/dsub/service/ssl/TrustSelfSignedStrategy.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ -package github.daneren2005.dsub.service.ssl; - -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -/** - * A trust strategy that accepts self-signed certificates as trusted. Verification of all other - * certificates is done by the trust manager configured in the SSL context. - * - * @since 4.1 - */ -public class TrustSelfSignedStrategy implements TrustStrategy { - - public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException { - return true; - } - -} diff --git a/src/github/daneren2005/dsub/service/ssl/TrustStrategy.java b/src/github/daneren2005/dsub/service/ssl/TrustStrategy.java deleted file mode 100644 index 334a97c5..00000000 --- a/src/github/daneren2005/dsub/service/ssl/TrustStrategy.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ -package github.daneren2005.dsub.service.ssl; - -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -/** - * A strategy to establish trustworthiness of certificates without consulting the trust manager - * configured in the actual SSL context. This interface can be used to override the standard - * JSSE certificate verification process. - * - * @since 4.1 - */ -public interface TrustStrategy { - - /** - * Determines whether the certificate chain can be trusted without consulting the trust manager - * configured in the actual SSL context. This method can be used to override the standard JSSE - * certificate verification process. - *

- * Please note that, if this method returns false, the trust manager configured - * in the actual SSL context can still clear the certificate as trusted. - * - * @param chain the peer certificate chain - * @param authType the authentication type based on the client certificate - * @return true if the certificate can be trusted without verification by - * the trust manager, false otherwise. - * @throws CertificateException thrown if the certificate is not trusted or invalid. - */ - boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException; - -} diff --git a/src/github/daneren2005/dsub/service/sync/AuthenticatorService.java b/src/github/daneren2005/dsub/service/sync/AuthenticatorService.java deleted file mode 100644 index ae12c88e..00000000 --- a/src/github/daneren2005/dsub/service/sync/AuthenticatorService.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.service.sync; - -import android.accounts.AbstractAccountAuthenticator; -import android.accounts.Account; -import android.accounts.AccountAuthenticatorResponse; -import android.accounts.NetworkErrorException; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; - -/** - * Created by Scott on 8/28/13. - */ - -public class AuthenticatorService extends Service { - private SubsonicAuthenticator authenticator; - - @Override - public void onCreate() { - authenticator = new SubsonicAuthenticator(this); - } - - @Override - public IBinder onBind(Intent intent) { - return authenticator.getIBinder(); - - } - - private class SubsonicAuthenticator extends AbstractAccountAuthenticator { - public SubsonicAuthenticator(Context context) { - super(context); - } - - @Override - public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { - return null; - } - - @Override - public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { - return null; - } - - @Override - public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { - return null; - } - - @Override - public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { - return null; - } - - @Override - public String getAuthTokenLabel(String authTokenType) { - return null; - } - - @Override - public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { - return null; - } - - @Override - public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { - return null; - } - } -} diff --git a/src/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java b/src/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java deleted file mode 100644 index a0727201..00000000 --- a/src/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.service.sync; - -import android.annotation.TargetApi; -import android.content.Context; -import android.util.Log; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Notifications; -import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.util.SyncUtil.SyncSet; -import github.daneren2005.dsub.util.Util; - -/** - * Created by Scott on 8/28/13. - */ - -public class MostRecentSyncAdapter extends SubsonicSyncAdapter { - private static String TAG = MostRecentSyncAdapter.class.getSimpleName(); - - public MostRecentSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - } - @TargetApi(14) - public MostRecentSyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) { - super(context, autoInitialize, allowParallelSyncs); - } - - @Override - public void onExecuteSync(Context context, int instance) { - try { - ArrayList syncedList = SyncUtil.getSyncedMostRecent(context, instance); - MusicDirectory albumList = musicService.getAlbumList("newest", 20, 0, context, null); - List updated = new ArrayList(); - boolean firstRun = false; - if(syncedList.size() == 0) { - // Get the initial set of albums on first run, don't sync any of these! - for(MusicDirectory.Entry album: albumList.getChildren()) { - syncedList.add(album.getId()); - } - firstRun = true; - } else { - for(MusicDirectory.Entry album: albumList.getChildren()) { - if(!syncedList.contains(album.getId())) { - if(!"Podcast".equals(album.getGenre())) { - try { - if(downloadRecursively(null, getMusicDirectory(album), context, false)) { - updated.add(album.getTitle()); - } - } catch(Exception e) { - Log.w(TAG, "Failed to get songs for " + album.getId() + " on " + Util.getServerName(context, instance)); - } - } - syncedList.add(album.getId()); - } - } - } - - if(updated.size() > 0) { - while(syncedList.size() > 40) { - syncedList.remove(0); - } - - FileUtil.serialize(context, syncedList, SyncUtil.getMostRecentSyncFile(context, instance)); - - // If there is a new album on the active server, chances are artists need to be refreshed - if(Util.getActiveServer(context) == instance) { - musicService.getIndexes(Util.getSelectedMusicFolderId(context), true, context, null); - } - - Notifications.showSyncNotification(context, R.string.sync_new_albums, SyncUtil.joinNames(updated)); - } else if(firstRun) { - FileUtil.serialize(context, syncedList, SyncUtil.getMostRecentSyncFile(context, instance)); - } - } catch(Exception e) { - Log.e(TAG, "Failed to get most recent list for " + Util.getServerName(context, instance)); - } - } -} diff --git a/src/github/daneren2005/dsub/service/sync/MostRecentSyncService.java b/src/github/daneren2005/dsub/service/sync/MostRecentSyncService.java deleted file mode 100644 index 378fe432..00000000 --- a/src/github/daneren2005/dsub/service/sync/MostRecentSyncService.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.service.sync; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -/** - * Created by Scott on 8/28/13. - */ - -public class MostRecentSyncService extends Service { - private static MostRecentSyncAdapter mostRecentSyncAdapter; - private static final Object syncLock = new Object(); - - @Override - public void onCreate() { - synchronized (syncLock) { - if(mostRecentSyncAdapter == null) { - mostRecentSyncAdapter = new MostRecentSyncAdapter(getApplicationContext(), true); - } - } - } - - @Override - public IBinder onBind(Intent intent) { - return mostRecentSyncAdapter.getSyncAdapterBinder(); - - } -} diff --git a/src/github/daneren2005/dsub/service/sync/PlaylistSyncAdapter.java b/src/github/daneren2005/dsub/service/sync/PlaylistSyncAdapter.java deleted file mode 100644 index e96ccb3e..00000000 --- a/src/github/daneren2005/dsub/service/sync/PlaylistSyncAdapter.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus -*/ - -package github.daneren2005.dsub.service.sync; - -import android.annotation.TargetApi; -import android.content.Context; -import android.util.Log; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.parser.SubsonicRESTException; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Notifications; -import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.util.SyncUtil.SyncSet; -import github.daneren2005.dsub.util.Util; - -/** - * Created by Scott on 8/28/13. -*/ - -public class PlaylistSyncAdapter extends SubsonicSyncAdapter { - private static String TAG = PlaylistSyncAdapter.class.getSimpleName(); - // Update playlists every day to make sure they are still valid - private static int MAX_PLAYLIST_AGE = 24; - - public PlaylistSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - } - @TargetApi(14) - public PlaylistSyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) { - super(context, autoInitialize, allowParallelSyncs); - } - - @Override - public void onExecuteSync(Context context, int instance) { - String serverName = Util.getServerName(context, instance); - - List remainder = null; - try { - // Just update playlist listings so user doesn't have to - remainder = musicService.getPlaylists(true, context, null); - } catch(Exception e) { - Log.e(TAG, "Failed to refresh playlist list for " + serverName); - } - - ArrayList playlistList = SyncUtil.getSyncedPlaylists(context, instance); - List updated = new ArrayList(); - boolean removed = false; - for(int i = 0; i < playlistList.size(); i++) { - SyncSet cachedPlaylist = playlistList.get(i); - String id = cachedPlaylist.id; - - // Remove playlist from remainder list - if(remainder != null) { - remainder.remove(new Playlist(id, "")); - } - - try { - MusicDirectory playlist = musicService.getPlaylist(true, id, serverName, context, null); - - // Get list of original paths - List origPathList = new ArrayList(); - if(cachedPlaylist.synced != null) { - origPathList.addAll(cachedPlaylist.synced); - } else { - cachedPlaylist.synced = new ArrayList(); - } - - for(MusicDirectory.Entry entry: playlist.getChildren()) { - DownloadFile file = new DownloadFile(context, entry, true); - String path = file.getCompleteFile().getPath(); - while(!file.isSaved() && !file.isFailedMax()) { - file.downloadNow(musicService); - if(file.isSaved() && !updated.contains(playlist.getName())) { - updated.add(playlist.getName()); - } - } - - // Add to cached path set if saved - if(file.isSaved() && !cachedPlaylist.synced.contains(path)) { - cachedPlaylist.synced.add(path); - } - - origPathList.remove(path); - } - - // Check to unpin all paths which are no longer in playlist - if(origPathList.size() > 0) { - for(String path: origPathList) { - File saveFile = new File(path); - FileUtil.unpinSong(context, saveFile); - cachedPlaylist.synced.remove(path); - } - - removed = true; - } - } catch(SubsonicRESTException e) { - if(e.getCode() == 70) { - SyncUtil.removeSyncedPlaylist(context, id, instance); - Log.i(TAG, "Unsync deleted playlist " + id + " for " + serverName); - } - } catch(Exception e) { - Log.e(TAG, "Failed to get playlist " + id + " for " + serverName, e); - } - - if(updated.size() > 0 || removed) { - SyncUtil.setSyncedPlaylists(context, instance, playlistList); - } - } - - // For remaining playlists, check to make sure they have been updated recently - if(remainder != null) { - for (Playlist playlist : remainder) { - MusicDirectory dir = FileUtil.deserialize(context, Util.getCacheName(context, instance, "playlist", playlist.getId()), MusicDirectory.class, MAX_PLAYLIST_AGE); - if (dir == null) { - try { - musicService.getPlaylist(true, playlist.getId(), serverName, context, null); - } catch(Exception e) { - Log.w(TAG, "Failed to update playlist for " + playlist.getName()); - } - } - } - } - - if(updated.size() > 0) { - Notifications.showSyncNotification(context, R.string.sync_new_playlists, SyncUtil.joinNames(updated)); - } - } -} diff --git a/src/github/daneren2005/dsub/service/sync/PlaylistSyncService.java b/src/github/daneren2005/dsub/service/sync/PlaylistSyncService.java deleted file mode 100644 index 80ec5564..00000000 --- a/src/github/daneren2005/dsub/service/sync/PlaylistSyncService.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.service.sync; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -/** - * Created by Scott on 8/28/13. - */ - -public class PlaylistSyncService extends Service { - private static PlaylistSyncAdapter playlistSyncAdapter; - private static final Object syncLock = new Object(); - - @Override - public void onCreate() { - synchronized (syncLock) { - if(playlistSyncAdapter == null) { - playlistSyncAdapter = new PlaylistSyncAdapter(getApplicationContext(), true); - } - } - } - - @Override - public IBinder onBind(Intent intent) { - return playlistSyncAdapter.getSyncAdapterBinder(); - - } -} diff --git a/src/github/daneren2005/dsub/service/sync/PodcastSyncAdapter.java b/src/github/daneren2005/dsub/service/sync/PodcastSyncAdapter.java deleted file mode 100644 index c34ce678..00000000 --- a/src/github/daneren2005/dsub/service/sync/PodcastSyncAdapter.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.service.sync; - -import android.annotation.TargetApi; -import android.content.Context; -import android.util.Log; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.parser.SubsonicRESTException; -import github.daneren2005.dsub.util.Notifications; -import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.util.SyncUtil.SyncSet; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Util; - -/** - * Created by Scott on 8/28/13. - */ - -public class PodcastSyncAdapter extends SubsonicSyncAdapter { - private static String TAG = PodcastSyncAdapter.class.getSimpleName(); - - public PodcastSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - } - @TargetApi(14) - public PodcastSyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) { - super(context, autoInitialize, allowParallelSyncs); - } - - @Override - public void onExecuteSync(Context context, int instance) { - ArrayList podcastList = SyncUtil.getSyncedPodcasts(context, instance); - - try { - // Only refresh if syncs exist (implies a server where supported) - if(podcastList.size() > 0) { - // Just update podcast listings so user doesn't have to - musicService.getPodcastChannels(true, context, null); - - // Refresh podcast listings before syncing - musicService.refreshPodcasts(context, null); - } - - List updated = new ArrayList(); - for(int i = 0; i < podcastList.size(); i++) { - SyncSet set = podcastList.get(i); - String id = set.id; - List existingEpisodes = set.synced; - try { - MusicDirectory podcasts = musicService.getPodcastEpisodes(true, id, context, null); - - for(MusicDirectory.Entry entry: podcasts.getChildren()) { - // Make sure podcast is valid and not already synced - if(entry.getId() != null && "completed".equals(((PodcastEpisode)entry).getStatus()) && !existingEpisodes.contains(entry.getId())) { - DownloadFile file = new DownloadFile(context, entry, false); - while(!file.isCompleteFileAvailable() && !file.isFailedMax()) { - file.downloadNow(musicService); - } - // Only add if actualy downloaded correctly - if(file.isCompleteFileAvailable()) { - existingEpisodes.add(entry.getId()); - if(!updated.contains(podcasts.getName())) { - updated.add(podcasts.getName()); - } - } - } - } - } catch(SubsonicRESTException e) { - if(e.getCode() == 70) { - SyncUtil.removeSyncedPodcast(context, id, instance); - Log.i(TAG, "Unsync deleted podcasts for " + id + " on " + Util.getServerName(context, instance)); - } - } catch (Exception e) { - Log.w(TAG, "Failed to get podcasts for " + id + " on " + Util.getServerName(context, instance)); - } - } - - // Make sure there are is at least one change before re-syncing - if(updated.size() > 0) { - FileUtil.serialize(context, podcastList, SyncUtil.getPodcastSyncFile(context, instance)); - Notifications.showSyncNotification(context, R.string.sync_new_podcasts, SyncUtil.joinNames(updated)); - } - } catch(Exception e) { - Log.w(TAG, "Failed to get podcasts for " + Util.getServerName(context, instance)); - } - } -} diff --git a/src/github/daneren2005/dsub/service/sync/PodcastSyncService.java b/src/github/daneren2005/dsub/service/sync/PodcastSyncService.java deleted file mode 100644 index ff9ef5f1..00000000 --- a/src/github/daneren2005/dsub/service/sync/PodcastSyncService.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.service.sync; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -/** - * Created by Scott on 8/28/13. - */ - -public class PodcastSyncService extends Service { - private static PodcastSyncAdapter podcastSyncAdapter; - private static final Object syncLock = new Object(); - - @Override - public void onCreate() { - synchronized (syncLock) { - if(podcastSyncAdapter == null) { - podcastSyncAdapter = new PodcastSyncAdapter(getApplicationContext(), true); - } - } - } - - @Override - public IBinder onBind(Intent intent) { - return podcastSyncAdapter.getSyncAdapterBinder(); - - } -} diff --git a/src/github/daneren2005/dsub/service/sync/StarredSyncAdapter.java b/src/github/daneren2005/dsub/service/sync/StarredSyncAdapter.java deleted file mode 100644 index 7cff68aa..00000000 --- a/src/github/daneren2005/dsub/service/sync/StarredSyncAdapter.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.service.sync; - -import android.annotation.TargetApi; -import android.app.Notification; -import android.content.Context; -import android.util.Log; - -import java.io.File; -import java.util.ArrayList; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Notifications; -import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.util.Util; - -/** - * Created by Scott on 8/28/13. - */ - -public class StarredSyncAdapter extends SubsonicSyncAdapter { - private static String TAG = StarredSyncAdapter.class.getSimpleName(); - - public StarredSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - } - @TargetApi(14) - public StarredSyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) { - super(context, autoInitialize, allowParallelSyncs); - } - - @Override - public void onExecuteSync(Context context, int instance) { - try { - ArrayList syncedList = new ArrayList(); - MusicDirectory starredList = musicService.getStarredList(context, null); - - // Pin all the starred stuff - boolean updated = downloadRecursively(syncedList, starredList, context, true); - - // Get old starred list - ArrayList oldSyncedList = SyncUtil.getSyncedStarred(context, instance); - - // Check to make sure there aren't any old starred songs that now need to be removed - oldSyncedList.removeAll(syncedList); - - for(String path: oldSyncedList) { - File saveFile = new File(path); - FileUtil.unpinSong(context, saveFile); - } - - SyncUtil.setSyncedStarred(syncedList, context, instance); - if(updated) { - Notifications.showSyncNotification(context, R.string.sync_new_starred, null); - } - } catch(Exception e) { - Log.e(TAG, "Failed to get starred list for " + Util.getServerName(context, instance)); - } - } -} diff --git a/src/github/daneren2005/dsub/service/sync/StarredSyncService.java b/src/github/daneren2005/dsub/service/sync/StarredSyncService.java deleted file mode 100644 index 378ab996..00000000 --- a/src/github/daneren2005/dsub/service/sync/StarredSyncService.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.service.sync; - -import android.app.Service; -import android.content.Intent; -import android.os.IBinder; - -/** - * Created by Scott on 8/28/13. - */ - -public class StarredSyncService extends Service { - private static StarredSyncAdapter starredSyncAdapter; - private static final Object syncLock = new Object(); - - @Override - public void onCreate() { - synchronized (syncLock) { - if(starredSyncAdapter == null) { - starredSyncAdapter = new StarredSyncAdapter(getApplicationContext(), true); - } - } - } - - @Override - public IBinder onBind(Intent intent) { - return starredSyncAdapter.getSyncAdapterBinder(); - - } -} diff --git a/src/github/daneren2005/dsub/service/sync/SubsonicSyncAdapter.java b/src/github/daneren2005/dsub/service/sync/SubsonicSyncAdapter.java deleted file mode 100644 index 661f126d..00000000 --- a/src/github/daneren2005/dsub/service/sync/SubsonicSyncAdapter.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ - -package github.daneren2005.dsub.service.sync; - -import android.accounts.Account; -import android.annotation.TargetApi; -import android.content.AbstractThreadedSyncAdapter; -import android.content.ContentProviderClient; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.content.SyncResult; -import android.os.BatteryManager; -import android.os.Bundle; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.util.Log; - -import java.util.List; - -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.CachedMusicService; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.RESTMusicService; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.Util; - -/** - * Created by Scott on 9/6/13. - */ - -public class SubsonicSyncAdapter extends AbstractThreadedSyncAdapter { - private static final String TAG = SubsonicSyncAdapter.class.getSimpleName(); - protected CachedMusicService musicService = new CachedMusicService(new RESTMusicService()); - protected boolean tagBrowsing; - private Context context; - - public SubsonicSyncAdapter(Context context, boolean autoInitialize) { - super(context, autoInitialize); - this.context = context; - } - @TargetApi(14) - public SubsonicSyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) { - super(context, autoInitialize, allowParallelSyncs); - this.context = context; - } - - @Override - public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { - ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = manager.getActiveNetworkInfo(); - - // Don't try to sync if no network! - if(networkInfo == null || !networkInfo.isConnected() || Util.isOffline(context)) { - Log.w(TAG, "Not running sync, not connected to network"); - return; - } - - // Make sure battery > x% or is charging - IntentFilter intentFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); - Intent batteryStatus = context.registerReceiver(null, intentFilter); - int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); - if(status != BatteryManager.BATTERY_STATUS_CHARGING && status != BatteryManager.BATTERY_STATUS_FULL) { - int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); - int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1); - - if((level / (float)scale) < 0.15) { - Log.w(TAG, "Not running sync, battery too low"); - return; - } - } - - // Check if user wants to only sync on wifi - SharedPreferences prefs = Util.getPreferences(context); - if(prefs.getBoolean(Constants.PREFERENCES_KEY_SYNC_WIFI, true)) { - if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { - executeSync(context); - } else { - Log.w(TAG, "Not running sync, not connected to wifi"); - } - } else { - executeSync(context); - } - } - - private void executeSync(Context context) { - String className = this.getClass().getSimpleName(); - Log.i(TAG, "Running sync for " + className); - long start = System.currentTimeMillis(); - int servers = Util.getServerCount(context); - for(int i = 1; i <= servers; i++) { - try { - if(isValidServer(context, i) && Util.isSyncEnabled(context, i)) { - tagBrowsing = Util.isTagBrowsing(context, i); - musicService.setInstance(i); - onExecuteSync(context, i); - } else { - Log.i(TAG, "Skipped sync for " + i); - } - } catch(Exception e) { - Log.e(TAG, "Failed sync for " + className + "(" + i + ")", e); - } - } - - Log.i(TAG, className + " executed in " + (System.currentTimeMillis() - start) + " ms"); - } - public void onExecuteSync(Context context, int instance) { - - } - - protected boolean downloadRecursively(List paths, MusicDirectory parent, Context context, boolean save) throws Exception { - boolean downloaded = false; - for (MusicDirectory.Entry song: parent.getChildren(false, true)) { - if (!song.isVideo()) { - DownloadFile file = new DownloadFile(context, song, save); - while(!(save && file.isSaved() || !save && file.isCompleteFileAvailable()) && !file.isFailedMax()) { - file.downloadNow(musicService); - if(!file.isFailed()) { - downloaded = true; - } - } - - if(paths != null && file.isCompleteFileAvailable()) { - paths.add(file.getCompleteFile().getPath()); - } - } - } - - for (MusicDirectory.Entry dir: parent.getChildren(true, false)) { - if(downloadRecursively(paths, getMusicDirectory(dir), context, save)) { - downloaded = true; - } - } - - return downloaded; - } - protected MusicDirectory getMusicDirectory(MusicDirectory.Entry dir) throws Exception{ - String id = dir.getId(); - String name = dir.getTitle(); - - if(tagBrowsing) { - if(dir.getArtist() == null) { - return musicService.getArtist(id, name, true, context, null); - } else { - return musicService.getAlbum(id, name, true, context, null); - } - } else { - return musicService.getMusicDirectory(id, name, true, context, null); - } - } - - private boolean isValidServer(Context context, int instance) { - String url = Util.getRestUrl(context, "null", instance, false); - return !(url.contains("demo.subsonic.org") || url.contains("yourhost")); - } -} diff --git a/src/github/daneren2005/dsub/updates/Updater.java b/src/github/daneren2005/dsub/updates/Updater.java deleted file mode 100644 index c3157a3c..00000000 --- a/src/github/daneren2005/dsub/updates/Updater.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.updates; - -import android.content.Context; -import android.content.SharedPreferences; -import android.util.Log; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.SilentBackgroundTask; -import github.daneren2005.dsub.util.Util; -import java.util.ArrayList; -import java.util.List; - -/** - * - * @author Scott - */ -public class Updater { - protected String TAG = Updater.class.getSimpleName(); - protected int version; - protected Context context; - - public Updater(int version) { - this.version = version; - } - - public void checkUpdates(Context context) { - this.context = context; - List updaters = new ArrayList(); - updaters.add(new Updater403()); - - SharedPreferences prefs = Util.getPreferences(context); - int lastVersion = prefs.getInt(Constants.LAST_VERSION, 0); - if(lastVersion == 0) { - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(Constants.LAST_VERSION, version); - editor.commit(); - } - else if(version > lastVersion) { - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(Constants.LAST_VERSION, version); - editor.commit(); - - Log.i(TAG, "Updating from version " + lastVersion + " to " + version); - for(Updater updater: updaters) { - if(updater.shouldUpdate(lastVersion)) { - new BackgroundUpdate(context, updater).execute(); - } - } - } - } - - public String getName() { - return this.TAG; - } - - private class BackgroundUpdate extends SilentBackgroundTask { - private final Updater updater; - - public BackgroundUpdate(Context context, Updater updater) { - super(context); - this.updater = updater; - } - - @Override - protected Void doInBackground() { - try { - updater.update(context); - } catch(Exception e) { - Log.w(TAG, "Failed to run update for " + updater.getName()); - } - return null; - } - } - - public boolean shouldUpdate(int version) { - return this.version > version; - } - public void update(Context context) { - - } -} diff --git a/src/github/daneren2005/dsub/updates/Updater403.java b/src/github/daneren2005/dsub/updates/Updater403.java deleted file mode 100644 index 17947ce5..00000000 --- a/src/github/daneren2005/dsub/updates/Updater403.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.updates; - -import android.content.Context; -import android.util.Log; -import github.daneren2005.dsub.updates.Updater; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.FileUtil; -import java.io.File; - -/** - * - * @author Scott - */ -public class Updater403 extends Updater { - public Updater403() { - super(403); - TAG = Updater403.class.getSimpleName(); - } - - @Override - public void update(Context context) { - // Rename cover.jpeg to cover.jpg - Log.i(TAG, "Running Updater403: updating cover.jpg to albumart.jpg"); - File dir = FileUtil.getMusicDirectory(context); - if(dir != null) { - moveArt(dir); - } - } - - private void moveArt(File dir) { - for(File file: dir.listFiles()) { - if(file.isDirectory()) { - moveArt(file); - } else if("cover.jpg".equals(file.getName()) || "cover.jpeg".equals(file.getName())) { - File renamed = new File(dir, Constants.ALBUM_ART_FILE); - file.renameTo(renamed); - } - } - } -} diff --git a/src/github/daneren2005/dsub/util/ArtistRadioBuffer.java b/src/github/daneren2005/dsub/util/ArtistRadioBuffer.java deleted file mode 100644 index 6e9b8309..00000000 --- a/src/github/daneren2005/dsub/util/ArtistRadioBuffer.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.util; - -import android.util.Log; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; - -public class ArtistRadioBuffer { - private static final String TAG = ArtistRadioBuffer.class.getSimpleName(); - - private ScheduledExecutorService executorService; - private Runnable runnable; - private final ArrayList buffer = new ArrayList(); - private int lastCount = -1; - private DownloadService context; - private boolean awaitingResults = false; - private int capacity; - private int refillThreshold; - - private String artistId; - - public ArtistRadioBuffer(DownloadService context) { - this.context = context; - runnable = new Runnable() { - @Override - public void run() { - refill(); - } - }; - - // Calculate out the capacity and refill threshold based on the user's random size preference - int shuffleListSize = Integer.parseInt(Util.getPreferences(context).getString(Constants.PREFERENCES_KEY_RANDOM_SIZE, "20")); - // ex: default 20 -> 50 - capacity = shuffleListSize * 5 / 2; - capacity = Math.min(500, capacity); - - // ex: default 20 -> 40 - refillThreshold = capacity * 4 / 5; - } - - public void setArtist(String artistId) { - if(!Util.equals(this.artistId, artistId)) { - buffer.clear(); - } - - context.clear(); - this.artistId = artistId; - awaitingResults = true; - refill(); - } - public void restoreArtist(String artistId) { - this.artistId = artistId; - awaitingResults = false; - restart(); - } - - public List get(int size) { - // Make sure fetcher is running if needed - restart(); - - List result = new ArrayList(size); - synchronized (buffer) { - while (!buffer.isEmpty() && result.size() < size) { - result.add(buffer.remove(buffer.size() - 1)); - } - } - Log.i(TAG, "Taking " + result.size() + " songs from artist radio buffer. " + buffer.size() + " remaining."); - if(result.isEmpty()) { - awaitingResults = true; - } - return result; - } - - public void shutdown() { - executorService.shutdown(); - } - - private void restart() { - synchronized(buffer) { - if(buffer.size() <= refillThreshold && lastCount != 0 && (executorService == null || executorService.isShutdown())) { - executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleWithFixedDelay(runnable, 0, 10, TimeUnit.SECONDS); - } - } - } - - private void refill() { - if (buffer != null && (buffer.size() > refillThreshold || (!Util.isNetworkConnected(context) && !Util.isOffline(context)) || lastCount == 0)) { - executorService.shutdown(); - return; - } - - try { - MusicService service = MusicServiceFactory.getMusicService(context); - - // Get capacity based - int n = capacity - buffer.size(); - MusicDirectory songs = service.getRandomSongs(n, artistId, context, null); - - synchronized (buffer) { - lastCount = 0; - for(MusicDirectory.Entry entry: songs.getChildren()) { - if(!buffer.contains(entry) && entry.getRating() != 1) { - buffer.add(entry); - lastCount++; - } - } - Log.i(TAG, "Refilled artist radio buffer with " + lastCount + " songs."); - } - } catch (Exception x) { - // Give it one more try before quitting - if(lastCount != -2) { - lastCount = -2; - } else if(lastCount == -2) { - lastCount = 0; - } - Log.w(TAG, "Failed to refill artist radio buffer.", x); - } - - if(awaitingResults) { - awaitingResults = false; - context.checkDownloads(); - } - } -} diff --git a/src/github/daneren2005/dsub/util/BackgroundTask.java b/src/github/daneren2005/dsub/util/BackgroundTask.java deleted file mode 100644 index 9b39ac82..00000000 --- a/src/github/daneren2005/dsub/util/BackgroundTask.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.util; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.xmlpull.v1.XmlPullParserException; - -import android.app.Activity; -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.view.ErrorDialog; - -/** - * @author Sindre Mehus - */ -public abstract class BackgroundTask implements ProgressListener { - private static final String TAG = BackgroundTask.class.getSimpleName(); - - private final Context context; - protected AtomicBoolean cancelled = new AtomicBoolean(false); - protected OnCancelListener cancelListener; - protected Runnable onCompletionListener = null; - protected Task task; - - private static final int DEFAULT_CONCURRENCY = 8; - private static final Collection threads = Collections.synchronizedCollection(new ArrayList()); - protected static final BlockingQueue queue = new LinkedBlockingQueue(10); - private static Handler handler = null; - static { - try { - handler = new Handler(Looper.getMainLooper()); - } catch(Exception e) { - // Not called from main thread - } - } - - public BackgroundTask(Context context) { - this.context = context; - - if(threads.size() < DEFAULT_CONCURRENCY) { - for(int i = threads.size(); i < DEFAULT_CONCURRENCY; i++) { - Thread thread = new Thread(new TaskRunnable(), String.format("BackgroundTask_%d", i)); - threads.add(thread); - thread.start(); - } - } - if(handler == null) { - try { - handler = new Handler(Looper.getMainLooper()); - } catch(Exception e) { - // Not called from main thread - } - } - } - - public static void stopThreads() { - for(Thread thread: threads) { - thread.interrupt(); - } - threads.clear(); - queue.clear(); - } - - protected Activity getActivity() { - return (context instanceof Activity) ? ((Activity) context) : null; - } - - protected Handler getHandler() { - return handler; - } - - public abstract void execute(); - - protected abstract T doInBackground() throws Throwable; - - protected abstract void done(T result); - - protected void error(Throwable error) { - Log.w(TAG, "Got exception: " + error, error); - Activity activity = getActivity(); - if(activity != null) { - new ErrorDialog(activity, getErrorMessage(error), true); - } - } - - protected String getErrorMessage(Throwable error) { - - if (error instanceof IOException && !Util.isNetworkConnected(context)) { - return context.getResources().getString(R.string.background_task_no_network); - } - - if (error instanceof FileNotFoundException) { - return context.getResources().getString(R.string.background_task_not_found); - } - - if (error instanceof IOException) { - return context.getResources().getString(R.string.background_task_network_error); - } - - if (error instanceof XmlPullParserException) { - return context.getResources().getString(R.string.background_task_parse_error); - } - - String message = error.getMessage(); - if (message != null) { - return message; - } - return error.getClass().getSimpleName(); - } - - public void cancel() { - if(cancelled.compareAndSet(false, true)) { - if(isRunning()) { - if(cancelListener != null) { - cancelListener.onCancel(); - } else { - task.cancel(); - } - } - - task = null; - } - } - public boolean isCancelled() { - return cancelled.get(); - } - public void setOnCancelListener(OnCancelListener listener) { - cancelListener = listener; - } - - public boolean isRunning() { - if(task == null) { - return false; - } else { - return task.isRunning(); - } - } - - @Override - public abstract void updateProgress(final String message); - - @Override - public void updateProgress(int messageId) { - updateProgress(context.getResources().getString(messageId)); - } - - public void setOnCompletionListener(Runnable onCompletionListener) { - this.onCompletionListener = onCompletionListener; - } - - protected class Task { - private Thread thread; - private AtomicBoolean taskStart = new AtomicBoolean(false); - - private void execute() throws Exception { - // Don't run if cancelled already - if(isCancelled()) { - return; - } - - try { - thread = Thread.currentThread(); - taskStart.set(true); - - final T result = doInBackground(); - if(isCancelled()) { - taskStart.set(false); - return; - } - - if(handler != null) { - handler.post(new Runnable() { - @Override - public void run() { - if(!isCancelled()) { - onDone(result); - } - - taskStart.set(false); - } - }); - } else { - taskStart.set(false); - } - } catch(InterruptedException interrupt) { - if(taskStart.get()) { - // Don't exit root thread if task cancelled - throw interrupt; - } - } catch(final Throwable t) { - if(isCancelled()) { - taskStart.set(false); - return; - } - - if(handler != null) { - handler.post(new Runnable() { - @Override - public void run() { - if(!isCancelled()) { - try { - onError(t); - } catch(Exception e) { - // Don't care - } - } - - taskStart.set(false); - } - }); - } else { - taskStart.set(false); - } - } finally { - thread = null; - } - } - - public void cancel() { - if(taskStart.compareAndSet(true, false)) { - if (thread != null) { - thread.interrupt(); - } - } - } - public boolean isCancelled() { - if(Thread.interrupted()) { - return true; - } else if(BackgroundTask.this.isCancelled()) { - return true; - } else { - return false; - } - } - public void onDone(T result) { - done(result); - - if(onCompletionListener != null) { - onCompletionListener.run(); - } - } - public void onError(Throwable t) { - error(t); - } - - public boolean isRunning() { - return taskStart.get(); - } - } - - private class TaskRunnable implements Runnable { - private boolean running = true; - - public TaskRunnable() { - - } - - @Override - public void run() { - Looper.prepare(); - while(running) { - try { - Task task = queue.take(); - task.execute(); - } catch(InterruptedException stop) { - Log.e(TAG, "Thread died"); - running = false; - threads.remove(Thread.currentThread()); - } catch(Throwable t) { - Log.e(TAG, "Unexpected crash in BackgroundTask thread", t); - } - } - } - } - - public static interface OnCancelListener { - void onCancel(); - } -} diff --git a/src/github/daneren2005/dsub/util/CacheCleaner.java b/src/github/daneren2005/dsub/util/CacheCleaner.java deleted file mode 100644 index ac8fa72a..00000000 --- a/src/github/daneren2005/dsub/util/CacheCleaner.java +++ /dev/null @@ -1,292 +0,0 @@ -package github.daneren2005.dsub.util; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import android.content.Context; -import android.util.Log; -import android.os.StatFs; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MediaStoreService; - -import java.util.*; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public class CacheCleaner { - - private static final String TAG = CacheCleaner.class.getSimpleName(); - private static final long MIN_FREE_SPACE = 500 * 1024L * 1024L; - private static final long MAX_COVER_ART_SPACE = 100 * 1024L * 1024L; - - private final Context context; - private final DownloadService downloadService; - private final MediaStoreService mediaStore; - - public CacheCleaner(Context context, DownloadService downloadService) { - this.context = context; - this.downloadService = downloadService; - this.mediaStore = new MediaStoreService(context); - } - - public void clean() { - new BackgroundCleanup(context).execute(); - } - public void cleanSpace() { - new BackgroundSpaceCleanup(context).execute(); - } - public void cleanPlaylists(List playlists) { - new BackgroundPlaylistsCleanup(context, playlists).execute(); - } - - private void deleteEmptyDirs(List dirs, Set undeletable) { - for (File dir : dirs) { - if (undeletable.contains(dir)) { - continue; - } - - FileUtil.deleteEmptyDir(dir); - } - } - - private long getMinimumDelete(List files, List pinned) { - if(files.size() == 0) { - return 0L; - } - - long cacheSizeBytes = Util.getCacheSizeMB(context) * 1024L * 1024L; - - long bytesUsedBySubsonic = 0L; - for (File file : files) { - bytesUsedBySubsonic += file.length(); - } - for (File file : pinned) { - bytesUsedBySubsonic += file.length(); - } - - // Ensure that file system is not more than 95% full. - StatFs stat = new StatFs(files.get(0).getPath()); - long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize(); - long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize(); - long bytesUsedFs = bytesTotalFs - bytesAvailableFs; - long minFsAvailability = bytesTotalFs - MIN_FREE_SPACE; - - long bytesToDeleteCacheLimit = Math.max(bytesUsedBySubsonic - cacheSizeBytes, 0L); - long bytesToDeleteFsLimit = Math.max(bytesUsedFs - minFsAvailability, 0L); - long bytesToDelete = Math.max(bytesToDeleteCacheLimit, bytesToDeleteFsLimit); - - Log.i(TAG, "File system : " + Util.formatBytes(bytesAvailableFs) + " of " + Util.formatBytes(bytesTotalFs) + " available"); - Log.i(TAG, "Cache limit : " + Util.formatBytes(cacheSizeBytes)); - Log.i(TAG, "Cache size before : " + Util.formatBytes(bytesUsedBySubsonic)); - Log.i(TAG, "Minimum to delete : " + Util.formatBytes(bytesToDelete)); - - return bytesToDelete; - } - - private void deleteFiles(List files, Set undeletable, long bytesToDelete, boolean deletePartials) { - if (files.isEmpty()) { - return; - } - - long bytesDeleted = 0L; - for (File file : files) { - if(!deletePartials && bytesDeleted > bytesToDelete) break; - - if (bytesToDelete > bytesDeleted || (deletePartials && (file.getName().endsWith(".partial") || file.getName().contains(".partial.")))) { - if (!undeletable.contains(file) && !file.getName().equals(Constants.ALBUM_ART_FILE)) { - long size = file.length(); - if (Util.delete(file)) { - bytesDeleted += size; - mediaStore.deleteFromMediaStore(file); - } - } - } - } - - Log.i(TAG, "Deleted : " + Util.formatBytes(bytesDeleted)); - } - - private void findCandidatesForDeletion(File file, List files, List pinned, List dirs) { - if (file.isFile()) { - String name = file.getName(); - boolean isCacheFile = name.endsWith(".partial") || name.contains(".partial.") || name.endsWith(".complete") || name.contains(".complete."); - if (isCacheFile) { - files.add(file); - } else { - pinned.add(file); - } - } else { - // Depth-first - for (File child : FileUtil.listFiles(file)) { - findCandidatesForDeletion(child, files, pinned, dirs); - } - dirs.add(file); - } - } - - private void sortByAscendingModificationTime(List files) { - Collections.sort(files, new Comparator() { - @Override - public int compare(File a, File b) { - if (a.lastModified() < b.lastModified()) { - return -1; - } - if (a.lastModified() > b.lastModified()) { - return 1; - } - return 0; - } - }); - } - - private Set findUndeletableFiles() { - Set undeletable = new HashSet(5); - - for (DownloadFile downloadFile : downloadService.getDownloads()) { - undeletable.add(downloadFile.getPartialFile()); - undeletable.add(downloadFile.getCompleteFile()); - } - - undeletable.add(FileUtil.getMusicDirectory(context)); - return undeletable; - } - - private void cleanupCoverArt(Context context) { - File dir = FileUtil.getAlbumArtDirectory(context); - - List files = new ArrayList(); - long bytesUsed = 0L; - for(File file: dir.listFiles()) { - if(file.isFile()) { - files.add(file); - bytesUsed += file.length(); - } - } - - // Don't waste time sorting if under limit already - if(bytesUsed < MAX_COVER_ART_SPACE) { - return; - } - - sortByAscendingModificationTime(files); - long bytesDeleted = 0L; - for(File file: files) { - // End as soon as the space used is below the threshold - if(bytesUsed < MAX_COVER_ART_SPACE) { - break; - } - - long bytes = file.length(); - if(file.delete()) { - bytesUsed -= bytes; - bytesDeleted += bytes; - } - } - - Log.i(TAG, "Deleted " + Util.formatBytes(bytesDeleted) + " worth of cover art"); - } - - private class BackgroundCleanup extends SilentBackgroundTask { - public BackgroundCleanup(Context context) { - super(context); - } - - @Override - protected Void doInBackground() { - if (downloadService == null) { - Log.e(TAG, "DownloadService not set. Aborting cache cleaning."); - return null; - } - - try { - List files = new ArrayList(); - List pinned = new ArrayList(); - List dirs = new ArrayList(); - - findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, pinned, dirs); - sortByAscendingModificationTime(files); - - Set undeletable = findUndeletableFiles(); - - deleteFiles(files, undeletable, getMinimumDelete(files, pinned), true); - deleteEmptyDirs(dirs, undeletable); - - // Make sure cover art directory does not grow too large - cleanupCoverArt(context); - } catch (RuntimeException x) { - Log.e(TAG, "Error in cache cleaning.", x); - } - - return null; - } - } - - private class BackgroundSpaceCleanup extends SilentBackgroundTask { - public BackgroundSpaceCleanup(Context context) { - super(context); - } - - @Override - protected Void doInBackground() { - if (downloadService == null) { - Log.e(TAG, "DownloadService not set. Aborting cache cleaning."); - return null; - } - - try { - List files = new ArrayList(); - List pinned = new ArrayList(); - List dirs = new ArrayList(); - findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, pinned, dirs); - - long bytesToDelete = getMinimumDelete(files, pinned); - if(bytesToDelete > 0L) { - sortByAscendingModificationTime(files); - Set undeletable = findUndeletableFiles(); - deleteFiles(files, undeletable, bytesToDelete, false); - } - } catch (RuntimeException x) { - Log.e(TAG, "Error in cache cleaning.", x); - } - - return null; - } - } - - private class BackgroundPlaylistsCleanup extends SilentBackgroundTask { - private final List playlists; - - public BackgroundPlaylistsCleanup(Context context, List playlists) { - super(context); - this.playlists = playlists; - } - - @Override - protected Void doInBackground() { - try { - String server = Util.getServerName(context); - SortedSet playlistFiles = FileUtil.listFiles(FileUtil.getPlaylistDirectory(context, server)); - for (Playlist playlist : playlists) { - playlistFiles.remove(FileUtil.getPlaylistFile(context, server, playlist.getName())); - } - - for(File playlist : playlistFiles) { - playlist.delete(); - } - } catch (RuntimeException x) { - Log.e(TAG, "Error in playlist cache cleaning.", x); - } - - return null; - } - } -} diff --git a/src/github/daneren2005/dsub/util/Constants.java b/src/github/daneren2005/dsub/util/Constants.java deleted file mode 100644 index 31c5bef2..00000000 --- a/src/github/daneren2005/dsub/util/Constants.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.util; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public final class Constants { - - // Character encoding used throughout. - public static final String UTF_8 = "UTF-8"; - - // REST protocol version and client ID. - // Note: Keep it as low as possible to maintain compatibility with older servers. - public static final String REST_PROTOCOL_VERSION = "1.2.0"; - public static final String REST_CLIENT_ID = "DSub"; - public static final String CHROMECAST_CLIENT_ID = "DSubCC"; - public static final String LAST_VERSION = "subsonic.version"; - - // Names for intent extras. - public static final String INTENT_EXTRA_NAME_ID = "subsonic.id"; - public static final String INTENT_EXTRA_NAME_NAME = "subsonic.name"; - public static final String INTENT_EXTRA_NAME_DIRECTORY = "subsonic.directory"; - public static final String INTENT_EXTRA_NAME_CHILD_ID = "subsonic.child.id"; - public static final String INTENT_EXTRA_NAME_ARTIST = "subsonic.artist"; - public static final String INTENT_EXTRA_NAME_TITLE = "subsonic.title"; - public static final String INTENT_EXTRA_NAME_AUTOPLAY = "subsonic.playall"; - public static final String INTENT_EXTRA_NAME_QUERY = "subsonic.query"; - public static final String INTENT_EXTRA_NAME_PLAYLIST_ID = "subsonic.playlist.id"; - public static final String INTENT_EXTRA_NAME_PLAYLIST_NAME = "subsonic.playlist.name"; - public static final String INTENT_EXTRA_NAME_PLAYLIST_OWNER = "subsonic.playlist.isOwner"; - public static final String INTENT_EXTRA_NAME_ALBUM_LIST_TYPE = "subsonic.albumlisttype"; - public static final String INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA = "subsonic.albumlistextra"; - public static final String INTENT_EXTRA_NAME_ALBUM_LIST_SIZE = "subsonic.albumlistsize"; - public static final String INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET = "subsonic.albumlistoffset"; - public static final String INTENT_EXTRA_NAME_SHUFFLE = "subsonic.shuffle"; - public static final String INTENT_EXTRA_REQUEST_SEARCH = "subsonic.requestsearch"; - public static final String INTENT_EXTRA_NAME_EXIT = "subsonic.exit" ; - public static final String INTENT_EXTRA_NAME_DOWNLOAD = "subsonic.download"; - public static final String INTENT_EXTRA_NAME_DOWNLOAD_VIEW = "subsonic.download_view"; - public static final String INTENT_EXTRA_VIEW_ALBUM = "subsonic.view_album"; - public static final String INTENT_EXTRA_NAME_PODCAST_ID = "subsonic.podcast.id"; - public static final String INTENT_EXTRA_NAME_PODCAST_NAME = "subsonic.podcast.name"; - public static final String INTENT_EXTRA_NAME_PODCAST_DESCRIPTION = "subsonic.podcast.description"; - public static final String INTENT_EXTRA_NAME_SHARE = "subsonic.share"; - public static final String INTENT_EXTRA_FRAGMENT_TYPE = "fragmentType"; - public static final String INTENT_EXTRA_REFRESH_LISTINGS = "refreshListings"; - public static final String INTENT_EXTRA_SEARCH_SONG = "searchSong"; - public static final String INTENT_EXTRA_TOP_TRACKS = "topTracks"; - public static final String INTENT_EXTRA_SHOW_ALL = "showAll"; - - // Preferences keys. - public static final String PREFERENCES_KEY_SERVER_KEY = "server"; - public static final String PREFERENCES_KEY_SERVER_COUNT = "serverCount"; - public static final String PREFERENCES_KEY_SERVER_ADD = "serverAdd"; - public static final String PREFERENCES_KEY_SERVER_REMOVE = "serverRemove"; - public static final String PREFERENCES_KEY_SERVER_INSTANCE = "serverInstanceId"; - public static final String PREFERENCES_KEY_SERVER_NAME = "serverName"; - public static final String PREFERENCES_KEY_SERVER_URL = "serverUrl"; - public static final String PREFERENCES_KEY_SERVER_INTERNAL_URL = "serverInternalUrl"; - public static final String PREFERENCES_KEY_SERVER_LOCAL_NETWORK_SSID = "serverLocalNetworkSSID"; - public static final String PREFERENCES_KEY_TEST_CONNECTION = "serverTestConnection"; - public static final String PREFERENCES_KEY_OPEN_BROWSER = "openBrowser"; - public static final String PREFERENCES_KEY_MUSIC_FOLDER_ID = "musicFolderId"; - public static final String PREFERENCES_KEY_USERNAME = "username"; - public static final String PREFERENCES_KEY_PASSWORD = "password"; - public static final String PREFERENCES_KEY_INSTALL_TIME = "installTime"; - public static final String PREFERENCES_KEY_THEME = "theme"; - public static final String PREFERENCES_KEY_FULL_SCREEN = "fullScreen"; - public static final String PREFERENCES_KEY_DISPLAY_TRACK = "displayTrack"; - public static final String PREFERENCES_KEY_MAX_BITRATE_WIFI = "maxBitrateWifi"; - public static final String PREFERENCES_KEY_MAX_BITRATE_MOBILE = "maxBitrateMobile"; - public static final String PREFERENCES_KEY_MAX_VIDEO_BITRATE_WIFI = "maxVideoBitrateWifi"; - public static final String PREFERENCES_KEY_MAX_VIDEO_BITRATE_MOBILE = "maxVideoBitrateMobile"; - public static final String PREFERENCES_KEY_NETWORK_TIMEOUT = "networkTimeout"; - public static final String PREFERENCES_KEY_CACHE_SIZE = "cacheSize"; - public static final String PREFERENCES_KEY_CACHE_LOCATION = "cacheLocation"; - public static final String PREFERENCES_KEY_PRELOAD_COUNT_WIFI = "preloadCountWifi"; - public static final String PREFERENCES_KEY_PRELOAD_COUNT_MOBILE = "preloadCountMobile"; - public static final String PREFERENCES_KEY_HIDE_MEDIA = "hideMedia"; - public static final String PREFERENCES_KEY_MEDIA_BUTTONS = "mediaButtons"; - public static final String PREFERENCES_KEY_SCREEN_LIT_ON_DOWNLOAD = "screenLitOnDownload"; - public static final String PREFERENCES_KEY_SCROBBLE = "scrobble"; - public static final String PREFERENCES_KEY_REPEAT_MODE = "repeatMode"; - public static final String PREFERENCES_KEY_WIFI_REQUIRED_FOR_DOWNLOAD = "wifiRequiredForDownload"; - public static final String PREFERENCES_KEY_RANDOM_SIZE = "randomSize"; - public static final String PREFERENCES_KEY_SLEEP_TIMER_DURATION = "sleepTimerDuration"; - public static final String PREFERENCES_KEY_OFFLINE = "offline"; - public static final String PREFERENCES_KEY_TEMP_LOSS = "tempLoss"; - public static final String PREFERENCES_KEY_SHUFFLE_START_YEAR = "startYear"; - public static final String PREFERENCES_KEY_SHUFFLE_END_YEAR = "endYear"; - public static final String PREFERENCES_KEY_SHUFFLE_GENRE = "genre"; - public static final String PREFERENCES_KEY_KEEP_SCREEN_ON = "keepScreenOn"; - public static final String PREFERENCES_EQUALIZER_ON = "equalizerOn"; - public static final String PREFERENCES_EQUALIZER_SETTINGS = "equalizerSettings"; - public static final String PREFERENCES_KEY_PERSISTENT_NOTIFICATION = "persistentNotification"; - public static final String PREFERENCES_KEY_GAPLESS_PLAYBACK = "gaplessPlayback"; - public static final String PREFERENCES_KEY_REMOVE_PLAYED = "removePlayed"; - public static final String PREFERENCES_KEY_SHUFFLE_MODE = "shuffleMode2"; - public static final String PREFERENCES_KEY_SHUFFLE_MODE_EXTRA = "shuffleModeExtra"; - public static final String PREFERENCES_KEY_CHAT_REFRESH = "chatRefreshRate"; - public static final String PREFERENCES_KEY_CHAT_ENABLED = "chatEnabled"; - public static final String PREFERENCES_KEY_VIDEO_PLAYER = "videoPlayer"; - public static final String PREFERENCES_KEY_CONTROL_MODE = "remoteControlMode"; - public static final String PREFERENCES_KEY_CONTROL_ID = "remoteControlId"; - public static final String PREFERENCES_KEY_SYNC_ENABLED = "syncEnabled"; - public static final String PREFERENCES_KEY_SYNC_INTERVAL = "syncInterval"; - public static final String PREFERENCES_KEY_SYNC_WIFI = "syncWifi"; - public static final String PREFERENCES_KEY_SYNC_NOTIFICATION = "syncNotification"; - public static final String PREFERENCES_KEY_SYNC_STARRED = "syncStarred"; - public static final String PREFERENCES_KEY_SYNC_MOST_RECENT = "syncMostRecent"; - public static final String PREFERENCES_KEY_PAUSE_DISCONNECT = "pauseOnDisconnect"; - public static final String PREFERENCES_KEY_HIDE_WIDGET = "hideWidget"; - public static final String PREFERENCES_KEY_PODCASTS_ENABLED = "podcastsEnabled"; - public static final String PREFERENCES_KEY_BOOKMARKS_ENABLED = "bookmarksEnabled"; - public static final String PREFERENCES_KEY_CUSTOM_SORT_ENABLED = "customSortEnabled"; - public static final String PREFERENCES_KEY_MENU_PLAY_NEXT = "showPlayNext"; - public static final String PREFERENCES_KEY_MENU_PLAY_LAST = "showPlayLast"; - public static final String PREFERENCES_KEY_MENU_STAR = "showStar"; - public static final String PREFERENCES_KEY_MENU_SHARED = "showShared"; - public static final String PREFERENCES_KEY_SHARED_ENABLED = "sharedEnabled"; - public static final String PREFERENCES_KEY_BROWSE_TAGS = "browseTags"; - public static final String PREFERENCES_KEY_OPEN_TO_TAB = "openToTab"; - public static final String PREFERENCES_KEY_OVERRIDE_SYSTEM_LANGUAGE = "overrideSystemLanguage"; - public static final String PREFERENCES_KEY_PLAY_NOW_AFTER = "playNowAfter"; - public static final String PREFERENCES_KEY_LARGE_ALBUM_ART = "largeAlbumArt"; - public static final String PREFERENCES_KEY_ADMIN_ENABLED = "adminEnabled"; - public static final String PREFERENCES_KEY_PLAYLIST_NAME = "suggestedPlaylistName"; - public static final String PREFERENCES_KEY_PLAYLIST_ID = "suggestedPlaylistId"; - public static final String PREFERENCES_KEY_SERVER_SYNC = "serverSync"; - public static final String PREFERENCES_KEY_RECENT_COUNT = "mostRecentCount"; - public static final String PREFERENCES_KEY_MENU_RATING = "showRating"; - public static final String PREFERENCES_KEY_REPLAY_GAIN = "replayGain"; - public static final String PREFERENCES_KEY_REPLAY_GAIN_BUMP = "replayGainBump2"; - public static final String PREFERENCES_KEY_REPLAY_GAIN_UNTAGGED = "replayGainUntagged2"; - public static final String PREFERENCES_KEY_REPLAY_GAIN_TYPE= "replayGainType"; - public static final String PREFERENCES_KEY_ALBUMS_PER_FOLDER = "albumsPerFolder"; - public static final String PREFERENCES_KEY_CAST_PROXY = "castProxy"; - public static final String PREFERENCES_KEY_DISABLE_EXIT_PROMPT = "disableExitPrompt"; - public static final String PREFERENCES_KEY_RENAME_DUPLICATES = "renameDuplicates"; - public static final String PREFERENCES_KEY_FIRST_LEVEL_ARTIST = "firstLevelArtist"; - public static final String PREFERENCES_KEY_START_ON_HEADPHONES = "startOnHeadphones"; - - public static final String OFFLINE_SCROBBLE_COUNT = "scrobbleCount"; - public static final String OFFLINE_SCROBBLE_ID = "scrobbleID"; - public static final String OFFLINE_SCROBBLE_SEARCH = "scrobbleTitle"; - public static final String OFFLINE_SCROBBLE_TIME = "scrobbleTime"; - public static final String OFFLINE_STAR_COUNT = "starCount"; - public static final String OFFLINE_STAR_ID = "starID"; - public static final String OFFLINE_STAR_SEARCH = "starTitle"; - public static final String OFFLINE_STAR_SETTING = "starSetting"; - - public static final String CACHE_KEY_IGNORE = "ignoreArticles"; - - public static final String MAIN_BACK_STACK = "backStackIds"; - public static final String MAIN_BACK_STACK_SIZE = "backStackIdsSize"; - public static final String FRAGMENT_LIST = "fragmentList"; - public static final String FRAGMENT_LIST2 = "fragmentList2"; - public static final String FRAGMENT_EXTRA = "fragmentExtra"; - public static final String FRAGMENT_DOWNLOAD_FLIPPER = "fragmentDownloadFlipper"; - public static final String FRAGMENT_NAME = "fragmentName"; - public static final String FRAGMENT_POSITION = "fragmentPosition"; - - // Name of the preferences file. - public static final String PREFERENCES_FILE_NAME = "github.daneren2005.dsub_preferences"; - public static final String OFFLINE_SYNC_NAME = "github.daneren2005.dsub.offline"; - public static final String OFFLINE_SYNC_DEFAULT = "syncDefaults"; - - // Account prefs - public static final String SYNC_ACCOUNT_NAME = "Subsonic Account"; - public static final String SYNC_ACCOUNT_TYPE = "subsonic.org"; - public static final String SYNC_ACCOUNT_PLAYLIST_AUTHORITY = "github.daneren2005.dsub.playlists.provider"; - public static final String SYNC_ACCOUNT_PODCAST_AUTHORITY = "github.daneren2005.dsub.podcasts.provider"; - public static final String SYNC_ACCOUNT_STARRED_AUTHORITY = "github.daneren2005.dsub.starred.provider"; - public static final String SYNC_ACCOUNT_MOST_RECENT_AUTHORITY = "github.daneren2005.dsub.mostrecent.provider"; - - public static final String TASKER_EXTRA_BUNDLE = "com.twofortyfouram.locale.intent.extra.BUNDLE"; - - // Number of free trial days for non-licensed servers. - public static final int FREE_TRIAL_DAYS = 30; - - // URL for project donations. - public static final String DONATION_URL = "http://subsonic.org/pages/android-donation.jsp"; - - public static final String ALBUM_ART_FILE = "albumart.jpg"; - - private Constants() { - } -} diff --git a/src/github/daneren2005/dsub/util/FileUtil.java b/src/github/daneren2005/dsub/util/FileUtil.java deleted file mode 100644 index 990eae06..00000000 --- a/src/github/daneren2005/dsub/util/FileUtil.java +++ /dev/null @@ -1,860 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.util; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.io.Serializable; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.Iterator; -import java.util.List; -import java.util.zip.DeflaterOutputStream; -import java.util.zip.InflaterInputStream; - -import android.annotation.TargetApi; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.Build; -import android.os.Environment; -import android.support.v4.content.ContextCompat; -import android.util.Log; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.domain.Genre; -import github.daneren2005.dsub.domain.Indexes; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.MusicFolder; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.service.MediaStoreService; - -import com.esotericsoftware.kryo.Kryo; -import com.esotericsoftware.kryo.io.Input; -import com.esotericsoftware.kryo.io.Output; - -/** - * @author Sindre Mehus - */ -public class FileUtil { - - private static final String TAG = FileUtil.class.getSimpleName(); - private static final String[] FILE_SYSTEM_UNSAFE = {"/", "\\", "..", ":", "\"", "?", "*", "<", ">", "|"}; - private static final String[] FILE_SYSTEM_UNSAFE_DIR = {"\\", "..", ":", "\"", "?", "*", "<", ">", "|"}; - private static final List MUSIC_FILE_EXTENSIONS = Arrays.asList("mp3", "ogg", "aac", "flac", "m4a", "wav", "wma"); - private static final List VIDEO_FILE_EXTENSIONS = Arrays.asList("flv", "mp4", "m4v", "wmv", "avi", "mov", "mpg", "mkv"); - private static final List PLAYLIST_FILE_EXTENSIONS = Arrays.asList("m3u"); - private static File DEFAULT_MUSIC_DIR; - private static final Kryo kryo = new Kryo(); - private static HashMap entryLookup; - - static { - kryo.register(MusicDirectory.Entry.class); - kryo.register(Indexes.class); - kryo.register(Artist.class); - kryo.register(MusicFolder.class); - kryo.register(PodcastChannel.class); - kryo.register(Playlist.class); - kryo.register(Genre.class); - } - - public static File getAnySong(Context context) { - File dir = getMusicDirectory(context); - return getAnySong(context, dir); - } - private static File getAnySong(Context context, File dir) { - for(File file: dir.listFiles()) { - if(file.isDirectory()) { - return getAnySong(context, file); - } - - String extension = getExtension(file.getName()); - if(MUSIC_FILE_EXTENSIONS.contains(extension)) { - return file; - } - } - - return null; - } - - public static File getEntryFile(Context context, MusicDirectory.Entry entry) { - if(entry.isDirectory()) { - return getAlbumDirectory(context, entry); - } else { - return getSongFile(context, entry); - } - } - - public static File getSongFile(Context context, MusicDirectory.Entry song) { - File dir = getAlbumDirectory(context, song); - - StringBuilder fileName = new StringBuilder(); - Integer track = song.getTrack(); - if (track != null) { - if (track < 10) { - fileName.append("0"); - } - fileName.append(track).append("-"); - } - - fileName.append(fileSystemSafe(song.getTitle())).append("."); - - if(song.isVideo()) { - String videoPlayerType = Util.getVideoPlayerType(context); - if("hls".equals(videoPlayerType)) { - // HLS should be able to transcode to mp4 automatically - fileName.append("mp4"); - } else if("raw".equals(videoPlayerType)) { - // Download the original video without any transcoding - fileName.append(song.getSuffix()); - } - } else { - if (song.getTranscodedSuffix() != null) { - fileName.append(song.getTranscodedSuffix()); - } else { - fileName.append(song.getSuffix()); - } - } - - return new File(dir, fileName.toString()); - } - - public static File getPlaylistFile(Context context, String server, String name) { - File playlistDir = getPlaylistDirectory(context, server); - return new File(playlistDir, fileSystemSafe(name) + ".m3u"); - } - public static void writePlaylistFile(Context context, File file, MusicDirectory playlist) throws IOException { - FileWriter fw = new FileWriter(file); - BufferedWriter bw = new BufferedWriter(fw); - try { - fw.write("#EXTM3U\n"); - for (MusicDirectory.Entry e : playlist.getChildren()) { - String filePath = FileUtil.getSongFile(context, e).getAbsolutePath(); - if(! new File(filePath).exists()){ - String ext = FileUtil.getExtension(filePath); - String base = FileUtil.getBaseName(filePath); - filePath = base + ".complete." + ext; - } - fw.write(filePath + "\n"); - } - } catch(Exception e) { - Log.w(TAG, "Failed to save playlist: " + playlist.getName()); - } finally { - bw.close(); - fw.close(); - } - } - public static File getPlaylistDirectory(Context context) { - File playlistDir = new File(getSubsonicDirectory(context), "playlists"); - ensureDirectoryExistsAndIsReadWritable(playlistDir); - return playlistDir; - } - public static File getPlaylistDirectory(Context context, String server) { - File playlistDir = new File(getPlaylistDirectory(context), server); - ensureDirectoryExistsAndIsReadWritable(playlistDir); - return playlistDir; - } - - public static File getAlbumArtFile(Context context, MusicDirectory.Entry entry) { - File albumDir = getAlbumDirectory(context, entry); - File artFile; - File albumFile = getAlbumArtFile(albumDir); - File hexFile = getHexAlbumArtFile(context, albumDir); - if(albumDir.exists()) { - if(hexFile.exists()) { - hexFile.renameTo(albumFile); - } - artFile = albumFile; - } else { - artFile = hexFile; - } - return artFile; - } - - public static File getAlbumArtFile(File albumDir) { - return new File(albumDir, Constants.ALBUM_ART_FILE); - } - public static File getHexAlbumArtFile(Context context, File albumDir) { - return new File(getAlbumArtDirectory(context), Util.md5Hex(albumDir.getPath()) + ".jpeg"); - } - - public static Bitmap getAlbumArtBitmap(Context context, MusicDirectory.Entry entry, int size) { - File albumArtFile = getAlbumArtFile(context, entry); - if (albumArtFile.exists()) { - final BitmapFactory.Options opt = new BitmapFactory.Options(); - opt.inJustDecodeBounds = true; - BitmapFactory.decodeFile(albumArtFile.getPath(), opt); - opt.inPurgeable = true; - opt.inSampleSize = Util.calculateInSampleSize(opt, size, Util.getScaledHeight(opt.outHeight, opt.outWidth, size)); - opt.inJustDecodeBounds = false; - - Bitmap bitmap = BitmapFactory.decodeFile(albumArtFile.getPath(), opt); - return bitmap == null ? null : getScaledBitmap(bitmap, size); - } - return null; - } - - public static File getAvatarDirectory(Context context) { - File avatarDir = new File(getSubsonicDirectory(context), "avatars"); - ensureDirectoryExistsAndIsReadWritable(avatarDir); - ensureDirectoryExistsAndIsReadWritable(new File(avatarDir, ".nomedia")); - return avatarDir; - } - - public static File getAvatarFile(Context context, String username) { - return new File(getAvatarDirectory(context), Util.md5Hex(username) + ".jpeg"); - } - - public static Bitmap getAvatarBitmap(Context context, String username, int size) { - File avatarFile = getAvatarFile(context, username); - if (avatarFile.exists()) { - final BitmapFactory.Options opt = new BitmapFactory.Options(); - opt.inJustDecodeBounds = true; - BitmapFactory.decodeFile(avatarFile.getPath(), opt); - opt.inPurgeable = true; - opt.inSampleSize = Util.calculateInSampleSize(opt, size, Util.getScaledHeight(opt.outHeight, opt.outWidth, size)); - opt.inJustDecodeBounds = false; - - Bitmap bitmap = BitmapFactory.decodeFile(avatarFile.getPath(), opt); - return bitmap == null ? null : getScaledBitmap(bitmap, size, false); - } - return null; - } - - public static File getMiscDirectory(Context context) { - File dir = new File(getSubsonicDirectory(context), "misc"); - ensureDirectoryExistsAndIsReadWritable(dir); - ensureDirectoryExistsAndIsReadWritable(new File(dir, ".nomedia")); - return dir; - } - - public static File getMiscFile(Context context, String url) { - return new File(getMiscDirectory(context), Util.md5Hex(url) + ".jpeg"); - } - - public static Bitmap getMiscBitmap(Context context, String url, int size) { - File avatarFile = getMiscFile(context, url); - if (avatarFile.exists()) { - final BitmapFactory.Options opt = new BitmapFactory.Options(); - opt.inJustDecodeBounds = true; - BitmapFactory.decodeFile(avatarFile.getPath(), opt); - opt.inPurgeable = true; - opt.inSampleSize = Util.calculateInSampleSize(opt, size, Util.getScaledHeight(opt.outHeight, opt.outWidth, size)); - opt.inJustDecodeBounds = false; - - Bitmap bitmap = BitmapFactory.decodeFile(avatarFile.getPath(), opt); - return bitmap == null ? null : getScaledBitmap(bitmap, size, false); - } - return null; - } - - public static Bitmap getSampledBitmap(byte[] bytes, int size) { - return getSampledBitmap(bytes, size, true); - } - public static Bitmap getSampledBitmap(byte[] bytes, int size, boolean allowUnscaled) { - final BitmapFactory.Options opt = new BitmapFactory.Options(); - opt.inJustDecodeBounds = true; - BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt); - opt.inPurgeable = true; - opt.inSampleSize = Util.calculateInSampleSize(opt, size, Util.getScaledHeight(opt.outHeight, opt.outWidth, size)); - opt.inJustDecodeBounds = false; - Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt); - if(bitmap == null) { - return null; - } else { - return getScaledBitmap(bitmap, size, allowUnscaled); - } - } - public static Bitmap getScaledBitmap(Bitmap bitmap, int size) { - return getScaledBitmap(bitmap, size, true); - } - public static Bitmap getScaledBitmap(Bitmap bitmap, int size, boolean allowUnscaled) { - // Don't waste time scaling if the difference is minor - // Large album arts still need to be scaled since displayed as is on now playing! - if(allowUnscaled && size < 400 && bitmap.getWidth() < (size * 1.1)) { - return bitmap; - } else { - return Bitmap.createScaledBitmap(bitmap, size, Util.getScaledHeight(bitmap, size), true); - } - } - - public static File getAlbumArtDirectory(Context context) { - File albumArtDir = new File(getSubsonicDirectory(context), "artwork"); - ensureDirectoryExistsAndIsReadWritable(albumArtDir); - ensureDirectoryExistsAndIsReadWritable(new File(albumArtDir, ".nomedia")); - return albumArtDir; - } - - public static File getArtistDirectory(Context context, Artist artist) { - File dir = new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(artist.getName())); - return dir; - } - public static File getArtistDirectory(Context context, MusicDirectory.Entry artist) { - File dir = new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(artist.getTitle())); - return dir; - } - - public static File getAlbumDirectory(Context context, MusicDirectory.Entry entry) { - File dir = null; - if (entry.getPath() != null) { - File f = new File(fileSystemSafeDir(entry.getPath())); - dir = new File(getMusicDirectory(context).getPath() + "/" + (entry.isDirectory() ? f.getPath() : f.getParent())); - } else { - MusicDirectory.Entry firstSong; - if(!Util.isOffline(context)) { - firstSong = lookupChild(context, entry, false); - if(firstSong != null) { - File songFile = FileUtil.getSongFile(context, firstSong); - dir = songFile.getParentFile(); - } - } - - if(dir == null) { - String artist = fileSystemSafe(entry.getArtist()); - String album = fileSystemSafe(entry.getAlbum()); - if("unnamed".equals(album)) { - album = fileSystemSafe(entry.getTitle()); - } - dir = new File(getMusicDirectory(context).getPath() + "/" + artist + "/" + album); - } - } - return dir; - } - - public static MusicDirectory.Entry lookupChild(Context context, MusicDirectory.Entry entry, boolean allowDir) { - // Initialize lookupMap if first time called - String lookupName = Util.getCacheName(context, "entryLookup"); - if(entryLookup == null) { - entryLookup = deserialize(context, lookupName, HashMap.class); - - // Create it if - if(entryLookup == null) { - entryLookup = new HashMap(); - } - } - - // Check if this lookup has already been done before - MusicDirectory.Entry child = entryLookup.get(entry.getId()); - if(child != null) { - return child; - } - - // Do a special lookup since 4.7+ doesn't match artist/album to entry.getPath - String s = Util.getRestUrl(context, null, false) + entry.getId(); - String cacheName = (Util.isTagBrowsing(context) ? "album-" : "directory-") + s.hashCode() + ".ser"; - MusicDirectory entryDir = FileUtil.deserialize(context, cacheName, MusicDirectory.class); - - if(entryDir != null) { - List songs = entryDir.getChildren(allowDir, true); - if(songs.size() > 0) { - child = songs.get(0); - entryLookup.put(entry.getId(), child); - serialize(context, entryLookup, lookupName); - return child; - } - } - - return null; - } - - public static String getPodcastPath(Context context, PodcastEpisode episode) { - return fileSystemSafe(episode.getArtist()) + "/" + fileSystemSafe(episode.getTitle()); - } - public static File getPodcastFile(Context context, String server) { - File dir = getPodcastDirectory(context); - return new File(dir.getPath() + "/" + fileSystemSafe(server)); - } - public static File getPodcastDirectory(Context context) { - File dir = new File(context.getCacheDir(), "podcasts"); - ensureDirectoryExistsAndIsReadWritable(dir); - return dir; - } - public static File getPodcastDirectory(Context context, PodcastChannel channel) { - File dir = new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(channel.getName())); - return dir; - } - public static File getPodcastDirectory(Context context, String channel) { - File dir = new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(channel)); - return dir; - } - - public static void createDirectoryForParent(File file) { - File dir = file.getParentFile(); - if (!dir.exists()) { - if (!dir.mkdirs()) { - Log.e(TAG, "Failed to create directory " + dir); - } - } - } - - private static File createDirectory(Context context, String name) { - File dir = new File(getSubsonicDirectory(context), name); - if (!dir.exists() && !dir.mkdirs()) { - Log.e(TAG, "Failed to create " + name); - } - return dir; - } - - public static File getSubsonicDirectory(Context context) { - return context.getExternalFilesDir(null); - } - - public static File getDefaultMusicDirectory(Context context) { - if(DEFAULT_MUSIC_DIR == null) { - File[] dirs; - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - dirs = context.getExternalMediaDirs(); - } else { - dirs = ContextCompat.getExternalFilesDirs(context, null); - } - - DEFAULT_MUSIC_DIR = new File(getBestDir(dirs), "music"); - Log.d(TAG, "Default: " + DEFAULT_MUSIC_DIR.getAbsolutePath()); - - if (!DEFAULT_MUSIC_DIR.exists() && !DEFAULT_MUSIC_DIR.mkdirs()) { - Log.e(TAG, "Failed to create default dir " + DEFAULT_MUSIC_DIR); - - // Some devices seem to have screwed up the new media directory API. Go figure. Try again with standard locations - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - dirs = ContextCompat.getExternalFilesDirs(context, null); - - DEFAULT_MUSIC_DIR = new File(getBestDir(dirs), "music"); - if (!DEFAULT_MUSIC_DIR.exists() && !DEFAULT_MUSIC_DIR.mkdirs()) { - Log.e(TAG, "Failed to create default dir " + DEFAULT_MUSIC_DIR); - } else { - Log.w(TAG, "Stupid OEM's messed up media dir API added in 5.0"); - } - } - } - } - - return DEFAULT_MUSIC_DIR; - } - private static File getBestDir(File[] dirs) { - // Past 5.0 we can query directly for SD Card - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - for(int i = 0; i < dirs.length; i++) { - if(dirs[i] != null && Environment.isExternalStorageRemovable(dirs[i])) { - return dirs[i]; - } - } - } - - // Before 5.0, we have to guess. Most of the time the SD card is last - for(int i = dirs.length - 1; i >= 0; i--) { - if(dirs[i] != null) { - return dirs[i]; - } - } - - // Should be impossible to be reached - return dirs[0]; - } - - public static File getMusicDirectory(Context context) { - String path = Util.getPreferences(context).getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, getDefaultMusicDirectory(context).getPath()); - File dir = new File(path); - return ensureDirectoryExistsAndIsReadWritable(dir) ? dir : getDefaultMusicDirectory(context); - } - public static boolean deleteMusicDirectory(Context context) { - File musicDirectory = FileUtil.getMusicDirectory(context); - MediaStoreService mediaStore = new MediaStoreService(context); - return recursiveDelete(musicDirectory, mediaStore); - } - public static void deleteSerializedCache(Context context) { - for(File file: context.getCacheDir().listFiles()) { - if(file.getName().indexOf(".ser") != -1) { - file.delete(); - } - } - } - public static boolean deleteArtworkCache(Context context) { - File artDirectory = FileUtil.getAlbumArtDirectory(context); - return recursiveDelete(artDirectory); - } - public static boolean deleteAvatarCache(Context context) { - File artDirectory = FileUtil.getAvatarDirectory(context); - return recursiveDelete(artDirectory); - } - - public static boolean recursiveDelete(File dir) { - return recursiveDelete(dir, null); - } - public static boolean recursiveDelete(File dir, MediaStoreService mediaStore) { - if (dir != null && dir.exists()) { - File[] list = dir.listFiles(); - if(list != null) { - for(File file: list) { - if(file.isDirectory()) { - if(!recursiveDelete(file, mediaStore)) { - return false; - } - } else if(file.exists()) { - if(!file.delete()) { - return false; - } else if(mediaStore != null) { - mediaStore.deleteFromMediaStore(file); - } - } - } - } - return dir.delete(); - } - return false; - } - - public static void deleteEmptyDir(File dir) { - try { - File[] children = dir.listFiles(); - if(children == null) { - return; - } - - // No songs left in the folder - if (children.length == 1 && children[0].getPath().equals(FileUtil.getAlbumArtFile(dir).getPath())) { - Util.delete(children[0]); - children = dir.listFiles(); - } - - // Delete empty directory - if (children.length == 0) { - Util.delete(dir); - } - } catch(Exception e) { - Log.w(TAG, "Error while trying to delete empty dir", e); - } - } - - public static void unpinSong(Context context, File saveFile) { - // Don't try to unpin a song which isn't actually pinned - if(saveFile.getName().contains(".complete")) { - return; - } - - // Unpin file, rename to .complete - File completeFile = new File(saveFile.getParent(), FileUtil.getBaseName(saveFile.getName()) + - ".complete." + FileUtil.getExtension(saveFile.getName())); - - if(!saveFile.renameTo(completeFile)) { - Log.w(TAG, "Failed to upin " + saveFile + " to " + completeFile); - } else { - try { - new MediaStoreService(context).renameInMediaStore(completeFile, saveFile); - } catch(Exception e) { - Log.w(TAG, "Failed to write to media store"); - } - } - } - - public static boolean ensureDirectoryExistsAndIsReadWritable(File dir) { - if (dir == null) { - return false; - } - - if (dir.exists()) { - if (!dir.isDirectory()) { - Log.w(TAG, dir + " exists but is not a directory."); - return false; - } - } else { - if (dir.mkdirs()) { - Log.i(TAG, "Created directory " + dir); - } else { - Log.w(TAG, "Failed to create directory " + dir); - return false; - } - } - - if (!dir.canRead()) { - Log.w(TAG, "No read permission for directory " + dir); - return false; - } - - if (!dir.canWrite()) { - Log.w(TAG, "No write permission for directory " + dir); - return false; - } - return true; - } - public static boolean verifyCanWrite(File dir) { - if(ensureDirectoryExistsAndIsReadWritable(dir)) { - try { - File tmp = new File(dir, "checkWrite"); - tmp.createNewFile(); - if(tmp.exists()) { - if(tmp.delete()) { - return true; - } else { - Log.w(TAG, "Failed to delete temp file, retrying"); - - // This should never be reached since this is a file DSub created! - Thread.sleep(100L); - tmp = new File(dir, "checkWrite"); - if(tmp.delete()) { - return true; - } else { - Log.w(TAG, "Failed retry to delete temp file"); - return false; - } - } - } else { - Log.w(TAG, "Temp file does not actually exist"); - return false; - } - } catch(Exception e) { - Log.w(TAG, "Failed to create tmp file", e); - return false; - } - } else { - return false; - } - } - - /** - * Makes a given filename safe by replacing special characters like slashes ("/" and "\") - * with dashes ("-"). - * - * @param filename The filename in question. - * @return The filename with special characters replaced by hyphens. - */ - private static String fileSystemSafe(String filename) { - if (filename == null || filename.trim().length() == 0) { - return "unnamed"; - } - - for (String s : FILE_SYSTEM_UNSAFE) { - filename = filename.replace(s, "-"); - } - return filename; - } - - /** - * Makes a given filename safe by replacing special characters like colons (":") - * with dashes ("-"). - * - * @param path The path of the directory in question. - * @return The the directory name with special characters replaced by hyphens. - */ - private static String fileSystemSafeDir(String path) { - if (path == null || path.trim().length() == 0) { - return ""; - } - - for (String s : FILE_SYSTEM_UNSAFE_DIR) { - path = path.replace(s, "-"); - } - return path; - } - - /** - * Similar to {@link File#listFiles()}, but returns a sorted set. - * Never returns {@code null}, instead a warning is logged, and an empty set is returned. - */ - public static SortedSet listFiles(File dir) { - File[] files = dir.listFiles(); - if (files == null) { - Log.w(TAG, "Failed to list children for " + dir.getPath()); - return new TreeSet(); - } - - return new TreeSet(Arrays.asList(files)); - } - - public static SortedSet listMediaFiles(File dir) { - SortedSet files = listFiles(dir); - Iterator iterator = files.iterator(); - while (iterator.hasNext()) { - File file = iterator.next(); - if (!file.isDirectory() && !isMediaFile(file)) { - iterator.remove(); - } - } - return files; - } - - private static boolean isMediaFile(File file) { - String extension = getExtension(file.getName()); - return MUSIC_FILE_EXTENSIONS.contains(extension) || VIDEO_FILE_EXTENSIONS.contains(extension); - } - - public static boolean isMusicFile(File file) { - String extension = getExtension(file.getName()); - return MUSIC_FILE_EXTENSIONS.contains(extension); - } - public static boolean isVideoFile(File file) { - String extension = getExtension(file.getName()); - return VIDEO_FILE_EXTENSIONS.contains(extension); - } - - public static boolean isPlaylistFile(File file) { - String extension = getExtension(file.getName()); - return PLAYLIST_FILE_EXTENSIONS.contains(extension); - } - - /** - * Returns the extension (the substring after the last dot) of the given file. The dot - * is not included in the returned extension. - * - * @param name The filename in question. - * @return The extension, or an empty string if no extension is found. - */ - public static String getExtension(String name) { - int index = name.lastIndexOf('.'); - return index == -1 ? "" : name.substring(index + 1).toLowerCase(); - } - - /** - * Returns the base name (the substring before the last dot) of the given file. The dot - * is not included in the returned basename. - * - * @param name The filename in question. - * @return The base name, or an empty string if no basename is found. - */ - public static String getBaseName(String name) { - int index = name.lastIndexOf('.'); - return index == -1 ? name : name.substring(0, index); - } - - public static Pair getUsedSize(Context context, File file) { - long number = 0L; - long size = 0L; - - if(file.isFile()) { - if(isMediaFile(file)) { - return new Pair(1L, file.length()); - } else { - return new Pair(0L, 0L); - } - } else { - for (File child : FileUtil.listFiles(file)) { - Pair pair = getUsedSize(context, child); - number += pair.getFirst(); - size += pair.getSecond(); - } - return new Pair(number, size); - } - } - - public static boolean serialize(Context context, T obj, String fileName) { - Output out = null; - try { - RandomAccessFile file = new RandomAccessFile(context.getCacheDir() + "/" + fileName, "rw"); - out = new Output(new FileOutputStream(file.getFD())); - synchronized (kryo) { - kryo.writeObject(out, obj); - } - return true; - } catch (Throwable x) { - Log.w(TAG, "Failed to serialize object to " + fileName); - return false; - } finally { - Util.close(out); - } - } - - public static T deserialize(Context context, String fileName, Class tClass) { - return deserialize(context, fileName, tClass, 0); - } - - public static T deserialize(Context context, String fileName, Class tClass, int hoursOld) { - Input in = null; - try { - File file = new File(context.getCacheDir(), fileName); - if(!file.exists()) { - return null; - } - - if(hoursOld != 0) { - Date fileDate = new Date(file.lastModified()); - // Convert into hours - long age = (new Date().getTime() - fileDate.getTime()) / 1000 / 3600; - if(age > hoursOld) { - return null; - } - } - - RandomAccessFile randomFile = new RandomAccessFile(file, "r"); - - in = new Input(new FileInputStream(randomFile.getFD())); - synchronized (kryo) { - T result = kryo.readObject(in, tClass); - return result; - } - } catch(FileNotFoundException e) { - // Different error message - Log.w(TAG, "No serialization for object from " + fileName); - return null; - } catch (Throwable x) { - Log.w(TAG, "Failed to deserialize object from " + fileName); - return null; - } finally { - Util.close(in); - } - } - - public static boolean serializeCompressed(Context context, T obj, String fileName) { - Output out = null; - try { - RandomAccessFile file = new RandomAccessFile(context.getCacheDir() + "/" + fileName, "rw"); - out = new Output(new DeflaterOutputStream(new FileOutputStream(file.getFD()))); - synchronized (kryo) { - kryo.writeObject(out, obj); - } - return true; - } catch (Throwable x) { - Log.w(TAG, "Failed to serialize compressed object to " + fileName); - return false; - } finally { - Util.close(out); - } - } - - @TargetApi(Build.VERSION_CODES.GINGERBREAD) - public static T deserializeCompressed(Context context, String fileName, Class tClass) { - Input in = null; - try { - RandomAccessFile file = new RandomAccessFile(context.getCacheDir() + "/" + fileName, "r"); - - in = new Input(new InflaterInputStream(new FileInputStream(file.getFD()))); - synchronized (kryo) { - T result = kryo.readObject(in, tClass); - return result; - } - } catch(FileNotFoundException e) { - // Different error message - Log.w(TAG, "No serialization compressed for object from " + fileName); - return null; - } catch (Throwable x) { - Log.w(TAG, "Failed to deserialize compressed object from " + fileName); - return null; - } finally { - Util.close(in); - } - } -} diff --git a/src/github/daneren2005/dsub/util/ImageLoader.java b/src/github/daneren2005/dsub/util/ImageLoader.java deleted file mode 100644 index 1a0e8242..00000000 --- a/src/github/daneren2005/dsub/util/ImageLoader.java +++ /dev/null @@ -1,600 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.util; - -import android.annotation.TargetApi; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.Shader; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.TransitionDrawable; -import android.media.RemoteControlClient; -import android.os.Build; -import android.os.Handler; -import android.os.Looper; -import android.util.DisplayMetrics; -import android.util.Log; -import android.support.v4.util.LruCache; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.ArtistInfo; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; - -/** - * Asynchronous loading of images, with caching. - *

- * There should normally be only one instance of this class. - * - * @author Sindre Mehus - */ -public class ImageLoader { - private static final String TAG = ImageLoader.class.getSimpleName(); - - private Context context; - private LruCache cache; - private Handler handler; - private Bitmap nowPlaying; - private final int imageSizeDefault; - private final int imageSizeLarge; - private final int avatarSizeDefault; - private boolean clearingCache = false; - - private final static int[] COLORS = {0xFF33B5E5, 0xFFAA66CC, 0xFF99CC00, 0xFFFFBB33, 0xFFFF4444}; - - public ImageLoader(Context context) { - this.context = context; - handler = new Handler(Looper.getMainLooper()); - final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); - final int cacheSize = maxMemory / 4; - - // Determine the density-dependent image sizes. - imageSizeDefault = context.getResources().getDrawable(R.drawable.unknown_album).getIntrinsicHeight(); - DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - imageSizeLarge = Math.round(Math.min(metrics.widthPixels, metrics.heightPixels)); - avatarSizeDefault = context.getResources().getDrawable(R.drawable.ic_social_person).getIntrinsicHeight(); - - cache = new LruCache(cacheSize) { - @Override - protected int sizeOf(String key, Bitmap bitmap) { - return bitmap.getRowBytes() * bitmap.getHeight() / 1024; - } - - @Override - protected void entryRemoved(boolean evicted, String key, Bitmap oldBitmap, Bitmap newBitmap) { - if(evicted) { - if(oldBitmap != nowPlaying && key.indexOf("unknown") != 0 || clearingCache) { - if(sizeOf("", oldBitmap) > 500) { - oldBitmap.recycle(); - } - } else { - cache.put(key, oldBitmap); - } - } - } - }; - } - - public void clearCache() { - nowPlaying = null; - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - clearingCache = true; - cache.evictAll(); - clearingCache = false; - return null; - } - }.execute(); - } - - private Bitmap getUnknownImage(MusicDirectory.Entry entry, int size) { - String key; - int color; - if(entry == null) { - key = getKey("unknown", size); - color = COLORS[0]; - - return getUnknownImage(key, size, color, null, null); - } else { - key = getKey(entry.getId() + "unknown", size); - String hash; - if(entry.getAlbum() != null) { - hash = entry.getAlbum(); - } else if(entry.getArtist() != null) { - hash = entry.getArtist(); - } else { - hash = entry.getId(); - } - color = COLORS[Math.abs(hash.hashCode()) % COLORS.length]; - - return getUnknownImage(key, size, color, entry.getAlbum(), entry.getArtist()); - } - } - private Bitmap getUnknownImage(String key, int size, int color, String topText, String bottomText) { - Bitmap bitmap = cache.get(key); - if(bitmap == null) { - bitmap = createUnknownImage(size, color, topText, bottomText); - cache.put(key, bitmap); - } - - return bitmap; - } - private Bitmap createUnknownImage(int size, int primaryColor, String topText, String bottomText) { - Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - - Paint color = new Paint(); - color.setColor(primaryColor); - canvas.drawRect(0, 0, size, size * 2.0f / 3.0f, color); - - color.setShader(new LinearGradient(0, 0, 0, size / 3.0f, Color.rgb(82, 82, 82), Color.BLACK, Shader.TileMode.MIRROR)); - canvas.drawRect(0, size * 2.0f / 3.0f, size, size, color); - - if(topText != null || bottomText != null) { - Paint font = new Paint(); - font.setFlags(Paint.ANTI_ALIAS_FLAG); - font.setColor(Color.WHITE); - font.setTextSize(3.0f + size * 0.07f); - - if(topText != null) { - canvas.drawText(topText, size * 0.05f, size * 0.6f, font); - } - - if(bottomText != null) { - canvas.drawText(bottomText, size * 0.05f, size * 0.8f, font); - } - } - - return bitmap; - } - - public Bitmap getCachedImage(Context context, MusicDirectory.Entry entry, boolean large) { - int size = large ? imageSizeLarge : imageSizeDefault; - if(entry == null || entry.getCoverArt() == null) { - return getUnknownImage(entry, size); - } - - Bitmap bitmap = cache.get(getKey(entry.getCoverArt(), size)); - if(bitmap == null || bitmap.isRecycled()) { - bitmap = FileUtil.getAlbumArtBitmap(context, entry, size); - String key = getKey(entry.getCoverArt(), size); - cache.put(key, bitmap); - cache.get(key); - } - - return bitmap; - } - - public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) { - // TODO: If we know this a artist, try to load artist info instead - int size = large ? imageSizeLarge : imageSizeDefault; - if(entry != null && !entry.isAlbum() && ServerInfo.checkServerVersion(context, "1.11") && !Util.isOffline(context)) { - SilentBackgroundTask task = new ArtistImageTask(view.getContext(), entry, size, imageSizeLarge, large, view, crossfade); - task.execute(); - return task; - } else if(entry != null && entry.getCoverArt() == null && entry.isDirectory() && !Util.isOffline(context)) { - // Try to lookup child cover art - MusicDirectory.Entry firstChild = FileUtil.lookupChild(context, entry, true); - if(firstChild != null) { - entry.setCoverArt(firstChild.getCoverArt()); - } - } - - Bitmap bitmap; - if (entry == null || entry.getCoverArt() == null) { - bitmap = getUnknownImage(entry, size); - setImage(view, Util.createDrawableFromBitmap(context, bitmap), crossfade); - return null; - } - - bitmap = cache.get(getKey(entry.getCoverArt(), size)); - if (bitmap != null && !bitmap.isRecycled()) { - final Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); - setImage(view, drawable, crossfade); - if(large) { - nowPlaying = bitmap; - } - return null; - } - - if (!large) { - setImage(view, Util.createDrawableFromBitmap(context, null), false); - } - ImageTask task = new ViewImageTask(view.getContext(), entry, size, imageSizeLarge, large, view, crossfade); - task.execute(); - return task; - } - - public SilentBackgroundTask loadImage(View view, String url, boolean large) { - Bitmap bitmap; - int size = large ? imageSizeLarge : imageSizeDefault; - if (url == null) { - String key = getKey(url + "unknown", size); - int color = COLORS[Math.abs(key.hashCode()) % COLORS.length]; - bitmap = getUnknownImage(key, size, color, null, null); - setImage(view, Util.createDrawableFromBitmap(context, bitmap), true); - return null; - } - - bitmap = cache.get(getKey(url, size)); - if (bitmap != null && !bitmap.isRecycled()) { - final Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); - setImage(view, drawable, true); - return null; - } - - SilentBackgroundTask task = new ViewUrlTask(view.getContext(), view, url, size); - task.execute(); - return task; - } - - public SilentBackgroundTask loadImage(Context context, RemoteControlClient remoteControl, MusicDirectory.Entry entry) { - Bitmap bitmap; - if (entry == null || entry.getCoverArt() == null) { - bitmap = getUnknownImage(entry, imageSizeLarge); - setImage(remoteControl, Util.createDrawableFromBitmap(context, bitmap)); - return null; - } - - bitmap = cache.get(getKey(entry.getCoverArt(), imageSizeLarge)); - if (bitmap != null && !bitmap.isRecycled()) { - Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); - setImage(remoteControl, drawable); - return null; - } - - setImage(remoteControl, Util.createDrawableFromBitmap(context, null)); - ImageTask task = new RemoteControlClientImageTask(context, entry, imageSizeLarge, imageSizeLarge, false, remoteControl); - task.execute(); - return task; - } - - public SilentBackgroundTask loadAvatar(Context context, ImageView view, String username) { - Bitmap bitmap = cache.get(username); - if (bitmap != null && !bitmap.isRecycled()) { - Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); - view.setImageDrawable(drawable); - return null; - } - - SilentBackgroundTask task = new AvatarTask(context, view, username); - task.execute(); - return task; - } - - private String getKey(String coverArtId, int size) { - return coverArtId + size; - } - - private void setImage(View view, final Drawable drawable, boolean crossfade) { - if (view instanceof TextView) { - // Cross-fading is not implemented for TextView since it's not in use. It would be easy to add it, though. - TextView textView = (TextView) view; - textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null); - } else if (view instanceof ImageView) { - final ImageView imageView = (ImageView) view; - if (crossfade && drawable != null) { - Drawable existingDrawable = imageView.getDrawable(); - if (existingDrawable == null) { - Bitmap emptyImage; - if(drawable.getIntrinsicWidth() > 0 && drawable.getIntrinsicHeight() > 0) { - emptyImage = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - } else { - emptyImage = Bitmap.createBitmap(imageSizeDefault, imageSizeDefault, Bitmap.Config.ARGB_8888); - } - existingDrawable = new BitmapDrawable(context.getResources(), emptyImage); - } else if(existingDrawable instanceof TransitionDrawable) { - // This should only ever be used if user is skipping through many songs quickly - TransitionDrawable tmp = (TransitionDrawable) existingDrawable; - existingDrawable = tmp.getDrawable(tmp.getNumberOfLayers() - 1); - } - if(existingDrawable != null && drawable != null) { - Drawable[] layers = new Drawable[]{existingDrawable, drawable}; - final TransitionDrawable transitionDrawable = new TransitionDrawable(layers); - imageView.setImageDrawable(transitionDrawable); - transitionDrawable.startTransition(250); - - // Get rid of transition drawable after transition occurs - handler.postDelayed(new Runnable() { - @Override - public void run() { - // Only execute if still on same transition drawable - if (imageView.getDrawable() == transitionDrawable) { - imageView.setImageDrawable(drawable); - } - } - }, 500L); - } else { - imageView.setImageDrawable(drawable); - } - } else { - imageView.setImageDrawable(drawable); - } - } - } - - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) - private void setImage(RemoteControlClient remoteControl, Drawable drawable) { - if(remoteControl != null && drawable != null) { - Bitmap origBitmap = ((BitmapDrawable)drawable).getBitmap(); - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && origBitmap != null) { - origBitmap = origBitmap.copy(origBitmap.getConfig(), false); - } - if ( origBitmap != null && !origBitmap.isRecycled()) { - remoteControl.editMetadata(false).putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, origBitmap).apply(); - } else { - if(origBitmap != null) { - Log.e(TAG, "Tried to load a recycled bitmap."); - } - remoteControl.editMetadata(false) - .putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, null) - .apply(); - } - } - } - - public abstract class ImageTask extends SilentBackgroundTask { - private final Context mContext; - private final MusicDirectory.Entry mEntry; - private final int mSize; - private final int mSaveSize; - private final boolean mIsNowPlaying; - protected Drawable mDrawable; - - public ImageTask(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying) { - super(context); - mContext = context; - mEntry = entry; - mSize = size; - mSaveSize = saveSize; - mIsNowPlaying = isNowPlaying; - } - - @Override - protected Void doInBackground() throws Throwable { - try { - MusicService musicService = MusicServiceFactory.getMusicService(mContext); - Bitmap bitmap = musicService.getCoverArt(mContext, mEntry, mSize, null, this); - String key = getKey(mEntry.getCoverArt(), mSize); - cache.put(key, bitmap); - // Make sure key is the most recently "used" - cache.get(key); - if(mIsNowPlaying) { - nowPlaying = bitmap; - } - - mDrawable = Util.createDrawableFromBitmap(mContext, bitmap); - } catch (Throwable x) { - Log.e(TAG, "Failed to download album art.", x); - cancelled.set(true); - } - - return null; - } - } - - private class ViewImageTask extends ImageTask { - protected boolean mCrossfade; - private View mView; - - public ViewImageTask(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying, View view, boolean crossfade) { - super(context, entry, size, saveSize, isNowPlaying); - - mView = view; - mCrossfade = crossfade; - } - - @Override - protected void done(Void result) { - setImage(mView, mDrawable, mCrossfade); - } - } - - private class RemoteControlClientImageTask extends ImageTask { - private RemoteControlClient mRemoteControl; - - public RemoteControlClientImageTask(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying, RemoteControlClient remoteControl) { - super(context, entry, size, saveSize, isNowPlaying); - - mRemoteControl = remoteControl; - } - - @Override - protected void done(Void result) { - setImage(mRemoteControl, mDrawable); - } - } - - private class ArtistImageTask extends SilentBackgroundTask { - private final Context mContext; - private final MusicDirectory.Entry mEntry; - private final int mSize; - private final int mSaveSize; - private final boolean mIsNowPlaying; - private Drawable mDrawable; - private boolean mCrossfade; - private View mView; - - private SilentBackgroundTask subTask; - - public ArtistImageTask(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying, View view, boolean crossfade) { - super(context); - mContext = context; - mEntry = entry; - mSize = size; - mSaveSize = saveSize; - mIsNowPlaying = isNowPlaying; - mView = view; - mCrossfade = crossfade; - } - - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(mContext); - ArtistInfo artistInfo = musicService.getArtistInfo(mEntry.getId(), false, true, mContext, null); - String url = artistInfo.getImageUrl(); - - // Figure out whether we are going to get a artist image or the standard image - if(url != null && !"".equals(url.trim())) { - // If getting the artist image fails for any reason, retry for the standard version - subTask = new ViewUrlTask(mContext, mView, url, mSize) { - @Override - protected void failedToDownload() { - // Call loadImage so we can take advantage of all of it's logic checks - loadImage(mView, mEntry, mSize == imageSizeLarge, mCrossfade); - - // Delete subTask so it doesn't get called in done - subTask = null; - } - }; - } else { - if (mEntry != null && mEntry.getCoverArt() == null && mEntry.isDirectory() && !Util.isOffline(context)) { - // Try to lookup child cover art - MusicDirectory.Entry firstChild = FileUtil.lookupChild(context, mEntry, true); - if (firstChild != null) { - mEntry.setCoverArt(firstChild.getCoverArt()); - } - } - - if (mEntry != null && mEntry.getCoverArt() != null) { - subTask = new ViewImageTask(mContext, mEntry, mSize, mSaveSize, mIsNowPlaying, mView, mCrossfade); - } else { - // If entry is null as well, we need to just set as a blank image - Bitmap bitmap = getUnknownImage(mEntry, mSize); - mDrawable = Util.createDrawableFromBitmap(mContext, bitmap); - return null; - } - } - - // Execute whichever way we decided to go - subTask.doInBackground(); - return null; - } - - @Override - public void done(Void result) { - if(subTask != null) { - subTask.done(result); - } else if(mDrawable != null) { - setImage(mView, mDrawable, mCrossfade); - } - } - } - - private class ViewUrlTask extends SilentBackgroundTask { - private final Context mContext; - private final String mUrl; - private final ImageView mView; - private Drawable mDrawable; - private int mSize; - - public ViewUrlTask(Context context, View view, String url, int size) { - super(context); - mContext = context; - mView = (ImageView) view; - mUrl = url; - mSize = size; - } - - @Override - protected Void doInBackground() throws Throwable { - try { - MusicService musicService = MusicServiceFactory.getMusicService(mContext); - Bitmap bitmap = musicService.getBitmap(mUrl, mSize, mContext, null, this); - if(bitmap != null) { - String key = getKey(mUrl, mSize); - cache.put(key, bitmap); - // Make sure key is the most recently "used" - cache.get(key); - - mDrawable = Util.createDrawableFromBitmap(mContext, bitmap); - } - } catch (Throwable x) { - Log.e(TAG, "Failed to download from url " + mUrl, x); - cancelled.set(true); - } - - return null; - } - - @Override - protected void done(Void result) { - if(mDrawable != null) { - mView.setImageDrawable(mDrawable); - } else { - failedToDownload(); - } - } - - protected void failedToDownload() { - - } - } - - private class AvatarTask extends SilentBackgroundTask { - private final Context mContext; - private final String mUsername; - private final ImageView mView; - private Drawable mDrawable; - - public AvatarTask(Context context, ImageView view, String username) { - super(context); - mContext = context; - mView = view; - mUsername = username; - } - - @Override - protected Void doInBackground() throws Throwable { - try { - MusicService musicService = MusicServiceFactory.getMusicService(mContext); - Bitmap bitmap = musicService.getAvatar(mUsername, avatarSizeDefault, mContext, null, this); - if(bitmap != null) { - cache.put(mUsername, bitmap); - // Make sure key is the most recently "used" - cache.get(mUsername); - - mDrawable = Util.createDrawableFromBitmap(mContext, bitmap); - } - } catch (Throwable x) { - Log.e(TAG, "Failed to download album art.", x); - cancelled.set(true); - } - - return null; - } - - @Override - protected void done(Void result) { - if(mDrawable != null) { - mView.setImageDrawable(mDrawable); - } - } - } -} diff --git a/src/github/daneren2005/dsub/util/LoadingTask.java b/src/github/daneren2005/dsub/util/LoadingTask.java deleted file mode 100644 index 77622e1e..00000000 --- a/src/github/daneren2005/dsub/util/LoadingTask.java +++ /dev/null @@ -1,73 +0,0 @@ -package github.daneren2005.dsub.util; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.content.DialogInterface; - -import github.daneren2005.dsub.activity.SubsonicActivity; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public abstract class LoadingTask extends BackgroundTask { - - private final Activity tabActivity; - private ProgressDialog loading; - private final boolean cancellable; - - public LoadingTask(Activity activity) { - super(activity); - tabActivity = activity; - this.cancellable = true; - } - public LoadingTask(Activity activity, final boolean cancellable) { - super(activity); - tabActivity = activity; - this.cancellable = cancellable; - } - - @Override - public void execute() { - loading = ProgressDialog.show(tabActivity, "", "Loading. Please Wait...", true, cancellable, new DialogInterface.OnCancelListener() { - public void onCancel(DialogInterface dialog) { - cancel(); - } - }); - - queue.offer(task = new Task() { - @Override - public void onDone(T result) { - if(loading.isShowing()) { - loading.dismiss(); - } - done(result); - } - - @Override - public void onError(Throwable t) { - if(loading.isShowing()) { - loading.dismiss(); - } - error(t); - } - }); - } - - @Override - public boolean isCancelled() { - return (tabActivity instanceof SubsonicActivity && ((SubsonicActivity) tabActivity).isDestroyedCompat()) || cancelled.get(); - } - - @Override - public void updateProgress(final String message) { - if(!cancelled.get()) { - getHandler().post(new Runnable() { - @Override - public void run() { - loading.setMessage(message); - } - }); - } - } -} diff --git a/src/github/daneren2005/dsub/util/MediaRouteManager.java b/src/github/daneren2005/dsub/util/MediaRouteManager.java deleted file mode 100644 index 9aa54c4b..00000000 --- a/src/github/daneren2005/dsub/util/MediaRouteManager.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.util; - -import android.os.Build; -import android.support.v7.media.MediaRouteProvider; -import android.support.v7.media.MediaRouteSelector; -import android.support.v7.media.MediaRouter; -import android.util.Log; - -import com.google.android.gms.common.ConnectionResult; -import com.google.android.gms.common.GooglePlayServicesUtil; - -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.domain.RemoteControlState; -import github.daneren2005.dsub.provider.DLNARouteProvider; -import github.daneren2005.dsub.provider.JukeboxRouteProvider; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.RemoteController; -import github.daneren2005.dsub.util.compat.CastCompat; - -import static android.support.v7.media.MediaRouter.RouteInfo; - -/** - * Created by owner on 2/8/14. - */ -public class MediaRouteManager extends MediaRouter.Callback { - private static final String TAG = MediaRouteManager.class.getSimpleName(); - private static boolean castAvailable = false; - - private DownloadService downloadService; - private MediaRouter router; - private MediaRouteSelector selector; - private List providers = new ArrayList(); - private List onlineProviders = new ArrayList(); - - static { - try { - CastCompat.checkAvailable(); - castAvailable = true; - } catch(Throwable t) { - castAvailable = false; - } - } - - public MediaRouteManager(DownloadService downloadService) { - this.downloadService = downloadService; - router = MediaRouter.getInstance(downloadService); - - // Check if play services is available - int result = GooglePlayServicesUtil.isGooglePlayServicesAvailable(downloadService); - if(result != ConnectionResult.SUCCESS){ - Log.w(TAG, "No play services, failed with result: " + result); - castAvailable = false; - } - - addProviders(); - buildSelector(); - } - - public void destroy() { - for(MediaRouteProvider provider: providers) { - router.removeProvider(provider); - } - } - - @Override - public void onRouteSelected(MediaRouter router, RouteInfo info) { - if(castAvailable) { - RemoteController controller = CastCompat.getController(downloadService, info); - if(controller != null) { - downloadService.setRemoteEnabled(RemoteControlState.CHROMECAST, controller); - } - } - - if(downloadService.isRemoteEnabled()) { - downloadService.registerRoute(router); - } - } - @Override - public void onRouteUnselected(MediaRouter router, RouteInfo info) { - if(downloadService.isRemoteEnabled()) { - downloadService.unregisterRoute(router); - } - - downloadService.setRemoteEnabled(RemoteControlState.LOCAL); - } - - public void setDefaultRoute() { - router.selectRoute(router.getDefaultRoute()); - } - - public void startScan() { - router.addCallback(selector, this, MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN); - } - public void stopScan() { - router.removeCallback(this); - } - - public MediaRouteSelector getSelector() { - return selector; - } - - public RouteInfo getSelectedRoute() { - return router.getSelectedRoute(); - } - public RouteInfo getRouteForId(String id) { - if(id == null) { - return null; - } - - // Try to find matching id - for(RouteInfo info: router.getRoutes()) { - if(id.equals(info.getId())) { - router.selectRoute(info); - return info; - } - } - - return null; - } - public RemoteController getRemoteController(RouteInfo info) { - if(castAvailable) { - return CastCompat.getController(downloadService, info); - } else { - return null; - } - } - - public void addOnlineProviders() { - JukeboxRouteProvider jukeboxProvider = new JukeboxRouteProvider(downloadService); - router.addProvider(jukeboxProvider); - providers.add(jukeboxProvider); - onlineProviders.add(jukeboxProvider); - } - public void removeOnlineProviders() { - for(MediaRouteProvider provider: onlineProviders) { - router.removeProvider(provider); - } - } - - private void addProviders() { - if(!Util.isOffline(downloadService)) { - addOnlineProviders(); - } - - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - DLNARouteProvider dlnaProvider = new DLNARouteProvider(downloadService); - router.addProvider(dlnaProvider); - providers.add(dlnaProvider); - } - } - public void buildSelector() { - MediaRouteSelector.Builder builder = new MediaRouteSelector.Builder(); - if(UserUtil.canJukebox()) { - builder.addControlCategory(JukeboxRouteProvider.CATEGORY_JUKEBOX_ROUTE); - } - if(castAvailable) { - builder.addControlCategory(CastCompat.getCastControlCategory()); - } - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - builder.addControlCategory(DLNARouteProvider.CATEGORY_DLNA); - } - selector = builder.build(); - } -} diff --git a/src/github/daneren2005/dsub/util/Notifications.java b/src/github/daneren2005/dsub/util/Notifications.java deleted file mode 100644 index 0ff149b0..00000000 --- a/src/github/daneren2005/dsub/util/Notifications.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.util; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.os.Build; -import android.os.Handler; -import android.support.v4.app.NotificationCompat; -import android.util.Log; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.RemoteViews; -import android.widget.TextView; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.SubsonicActivity; -import github.daneren2005.dsub.activity.SubsonicFragmentActivity; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.provider.DSubWidgetProvider; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.service.DownloadService; - -public final class Notifications { - private static final String TAG = Notifications.class.getSimpleName(); - - // Notification IDs. - public static final int NOTIFICATION_ID_PLAYING = 100; - public static final int NOTIFICATION_ID_DOWNLOADING = 102; - public static final String NOTIFICATION_SYNC_GROUP = "github.daneren2005.dsub.sync"; - - private static boolean playShowing = false; - private static boolean downloadShowing = false; - private static boolean downloadForeground = false; - - private final static Pair NOTIFICATION_TEXT_COLORS = new Pair(); - - public static void showPlayingNotification(final Context context, final DownloadService downloadService, final Handler handler, MusicDirectory.Entry song) { - // Set the icon, scrolling text and timestamp - final Notification notification = new Notification(R.drawable.stat_notify_playing, song.getTitle(), System.currentTimeMillis()); - - final boolean playing = downloadService.getPlayerState() == PlayerState.STARTED; - if(playing) { - notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; - } - boolean remote = downloadService.isRemoteEnabled(); - if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN){ - RemoteViews expandedContentView = new RemoteViews(context.getPackageName(), R.layout.notification_expanded); - setupViews(expandedContentView ,context, song, true, playing, remote); - notification.bigContentView = expandedContentView; - notification.priority = Notification.PRIORITY_HIGH; - } - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - notification.visibility = Notification.VISIBILITY_PUBLIC; - } - - RemoteViews smallContentView = new RemoteViews(context.getPackageName(), R.layout.notification); - setupViews(smallContentView, context, song, false, playing, remote); - notification.contentView = smallContentView; - - Intent notificationIntent = new Intent(context, SubsonicFragmentActivity.class); - notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true); - notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - notification.contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0); - - playShowing = true; - if(downloadForeground && downloadShowing) { - downloadForeground = false; - handler.post(new Runnable() { - @Override - public void run() { - downloadService.stopForeground(true); - showDownloadingNotification(context, downloadService, handler, downloadService.getCurrentDownloading(), downloadService.getBackgroundDownloads().size()); - downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification); - } - }); - } else { - handler.post(new Runnable() { - @Override - public void run() { - if(playing) { - downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification); - } else { - playShowing = false; - NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - downloadService.stopForeground(true); - notificationManager.notify(NOTIFICATION_ID_PLAYING, notification); - } - } - }); - } - - // Update widget - DSubWidgetProvider.notifyInstances(context, downloadService, playing); - } - - private static void setupViews(RemoteViews rv, Context context, MusicDirectory.Entry song, boolean expanded, boolean playing, boolean remote){ - - // Use the same text for the ticker and the expanded notification - String title = song.getTitle(); - String arist = song.getArtist(); - String album = song.getAlbum(); - - // Set the album art. - try { - ImageLoader imageLoader = SubsonicActivity.getStaticImageLoader(context); - Bitmap bitmap = null; - if(imageLoader != null) { - bitmap = imageLoader.getCachedImage(context, song, false); - } - if (bitmap == null) { - // set default album art - rv.setImageViewResource(R.id.notification_image, R.drawable.unknown_album); - } else { - rv.setImageViewBitmap(R.id.notification_image, bitmap); - } - } catch (Exception x) { - Log.w(TAG, "Failed to get notification cover art", x); - rv.setImageViewResource(R.id.notification_image, R.drawable.unknown_album); - } - - // set the text for the notifications - rv.setTextViewText(R.id.notification_title, title); - rv.setTextViewText(R.id.notification_artist, arist); - rv.setTextViewText(R.id.notification_album, album); - - boolean persistent = Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false); - if(persistent) { - if(expanded) { - rv.setImageViewResource(R.id.control_pause, playing ? R.drawable.notification_pause : R.drawable.notification_play); - } else { - rv.setImageViewResource(R.id.control_previous, playing ? R.drawable.notification_pause : R.drawable.notification_play); - rv.setImageViewResource(R.id.control_pause, R.drawable.notification_next); - rv.setImageViewResource(R.id.control_next, R.drawable.notification_close); - } - } - - // Create actions for media buttons - PendingIntent pendingIntent; - int previous = 0, pause = 0, next = 0, close = 0; - if(persistent && !expanded) { - pause = R.id.control_previous; - next = R.id.control_pause; - close = R.id.control_next; - } else { - previous = R.id.control_previous; - pause = R.id.control_pause; - next = R.id.control_next; - } - - if((remote || persistent) && close == 0 && expanded) { - close = R.id.notification_close; - rv.setViewVisibility(close, View.VISIBLE); - } - - if(previous > 0) { - Intent prevIntent = new Intent("KEYCODE_MEDIA_PREVIOUS"); - prevIntent.setComponent(new ComponentName(context, DownloadService.class)); - prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PREVIOUS)); - pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0); - rv.setOnClickPendingIntent(previous, pendingIntent); - } - if(pause > 0) { - if(playing) { - Intent pauseIntent = new Intent("KEYCODE_MEDIA_PLAY_PAUSE"); - pauseIntent.setComponent(new ComponentName(context, DownloadService.class)); - pauseIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE)); - pendingIntent = PendingIntent.getService(context, 0, pauseIntent, 0); - rv.setOnClickPendingIntent(pause, pendingIntent); - } else { - Intent prevIntent = new Intent("KEYCODE_MEDIA_START"); - prevIntent.setComponent(new ComponentName(context, DownloadService.class)); - prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY)); - pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0); - rv.setOnClickPendingIntent(pause, pendingIntent); - } - } - if(next > 0) { - Intent nextIntent = new Intent("KEYCODE_MEDIA_NEXT"); - nextIntent.setComponent(new ComponentName(context, DownloadService.class)); - nextIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_NEXT)); - pendingIntent = PendingIntent.getService(context, 0, nextIntent, 0); - rv.setOnClickPendingIntent(next, pendingIntent); - } - if(close > 0) { - Intent prevIntent = new Intent("KEYCODE_MEDIA_STOP"); - prevIntent.setComponent(new ComponentName(context, DownloadService.class)); - prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_STOP)); - pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0); - rv.setOnClickPendingIntent(close, pendingIntent); - } - } - - public static void hidePlayingNotification(final Context context, final DownloadService downloadService, Handler handler) { - playShowing = false; - - // Remove notification and remove the service from the foreground - handler.post(new Runnable() { - @Override - public void run() { - downloadService.stopForeground(true); - } - }); - - // Get downloadNotification in foreground if playing - if(downloadShowing) { - showDownloadingNotification(context, downloadService, handler, downloadService.getCurrentDownloading(), downloadService.getBackgroundDownloads().size()); - } - - // Update widget - DSubWidgetProvider.notifyInstances(context, downloadService, false); - } - - public static void showDownloadingNotification(final Context context, final DownloadService downloadService, Handler handler, DownloadFile file, int size) { - Intent cancelIntent = new Intent(context, DownloadService.class); - cancelIntent.setAction(DownloadService.CANCEL_DOWNLOADS); - PendingIntent cancelPI = PendingIntent.getService(context, 0, cancelIntent, 0); - - String currentDownloading, currentSize; - if(file != null) { - currentDownloading = file.getSong().getTitle(); - currentSize = Util.formatLocalizedBytes(file.getEstimatedSize(), context); - } else { - currentDownloading = "none"; - currentSize = "0"; - } - - NotificationCompat.Builder builder; - builder = new NotificationCompat.Builder(context) - .setSmallIcon(android.R.drawable.stat_sys_download) - .setContentTitle(context.getResources().getString(R.string.download_downloading_title, size)) - .setContentText(context.getResources().getString(R.string.download_downloading_summary, currentDownloading)) - .setStyle(new NotificationCompat.BigTextStyle() - .bigText(context.getResources().getString(R.string.download_downloading_summary_expanded, currentDownloading, currentSize))) - .setProgress(10, 5, true) - .setOngoing(true) - .addAction(R.drawable.notification_close, - context.getResources().getString(R.string.common_cancel), - cancelPI); - - Intent notificationIntent = new Intent(context, SubsonicFragmentActivity.class); - notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true); - notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW, true); - notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - builder.setContentIntent(PendingIntent.getActivity(context, 1, notificationIntent, 0)); - - final Notification notification = builder.build(); - downloadShowing = true; - if(playShowing) { - NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.notify(NOTIFICATION_ID_DOWNLOADING, notification); - } else { - downloadForeground = true; - handler.post(new Runnable() { - @Override - public void run() { - downloadService.startForeground(NOTIFICATION_ID_DOWNLOADING, notification); - } - }); - } - - } - public static void hideDownloadingNotification(final Context context, final DownloadService downloadService, Handler handler) { - downloadShowing = false; - if(playShowing) { - NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.cancel(NOTIFICATION_ID_DOWNLOADING); - } else { - downloadForeground = false; - handler.post(new Runnable() { - @Override - public void run() { - downloadService.stopForeground(true); - } - }); - } - } - - public static void showSyncNotification(final Context context, int stringId, String extra) { - if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_SYNC_NOTIFICATION, true)) { - if(extra == null) { - extra = ""; - } - - NotificationCompat.Builder builder; - builder = new NotificationCompat.Builder(context) - .setSmallIcon(R.drawable.stat_notify_sync) - .setContentTitle(context.getResources().getString(stringId)) - .setContentText(extra) - .setStyle(new NotificationCompat.BigTextStyle().bigText(extra.replace(", ", "\n"))) - .setOngoing(false) - .setGroup(NOTIFICATION_SYNC_GROUP) - .setPriority(NotificationCompat.PRIORITY_LOW) - .setAutoCancel(true); - - Intent notificationIntent = new Intent(context, SubsonicFragmentActivity.class); - notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - - String tab = null, type = null; - switch(stringId) { - case R.string.sync_new_albums: - type = "newest"; - break; - case R.string.sync_new_playlists: - tab = "Playlist"; - break; - case R.string.sync_new_podcasts: - tab = "Podcast"; - break; - case R.string.sync_new_starred: - type = "starred"; - break; - } - if(tab != null) { - notificationIntent.putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, tab); - } - if(type != null) { - notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type); - } - - builder.setContentIntent(PendingIntent.getActivity(context, stringId, notificationIntent, 0)); - - NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.notify(stringId, builder.build()); - } - } -} diff --git a/src/github/daneren2005/dsub/util/Pair.java b/src/github/daneren2005/dsub/util/Pair.java deleted file mode 100644 index 54386a62..00000000 --- a/src/github/daneren2005/dsub/util/Pair.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.util; - -import java.io.Serializable; - -/** - * @author Sindre Mehus - */ -public class Pair implements Serializable { - - private S first; - private T second; - - public Pair() { - } - - public Pair(S first, T second) { - this.first = first; - this.second = second; - } - - public S getFirst() { - return first; - } - - public void setFirst(S first) { - this.first = first; - } - - public T getSecond() { - return second; - } - - public void setSecond(T second) { - this.second = second; - } -} diff --git a/src/github/daneren2005/dsub/util/ProgressListener.java b/src/github/daneren2005/dsub/util/ProgressListener.java deleted file mode 100644 index c6d58f42..00000000 --- a/src/github/daneren2005/dsub/util/ProgressListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.util; - -/** - * @author Sindre Mehus - */ -public interface ProgressListener { - void updateProgress(String message); - void updateProgress(int messageId); -} diff --git a/src/github/daneren2005/dsub/util/SettingsBackupAgent.java b/src/github/daneren2005/dsub/util/SettingsBackupAgent.java deleted file mode 100644 index 7eb6d137..00000000 --- a/src/github/daneren2005/dsub/util/SettingsBackupAgent.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus -*/ -package github.daneren2005.dsub.util; - -import android.app.backup.BackupAgentHelper; -import android.app.backup.SharedPreferencesBackupHelper; -import github.daneren2005.dsub.util.Constants; - -public class SettingsBackupAgent extends BackupAgentHelper { - public void onCreate() { - super.onCreate(); - SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, Constants.PREFERENCES_FILE_NAME); - addHelper("mypreferences", helper); - } - } diff --git a/src/github/daneren2005/dsub/util/ShufflePlayBuffer.java b/src/github/daneren2005/dsub/util/ShufflePlayBuffer.java deleted file mode 100644 index 7da35f77..00000000 --- a/src/github/daneren2005/dsub/util/ShufflePlayBuffer.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.util; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import android.content.Context; -import android.content.SharedPreferences; -import android.util.Log; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.FileUtil; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public class ShufflePlayBuffer { - - private static final String TAG = ShufflePlayBuffer.class.getSimpleName(); - private static final String CACHE_FILENAME = "shuffleBuffer.ser"; - - private ScheduledExecutorService executorService; - private Runnable runnable; - private boolean firstRun = true; - private final ArrayList buffer = new ArrayList(); - private int lastCount = -1; - private DownloadService context; - private boolean awaitingResults = false; - private int capacity; - private int refillThreshold; - - private SharedPreferences.OnSharedPreferenceChangeListener listener; - private int currentServer; - private String currentFolder = ""; - private String genre = ""; - private String startYear = ""; - private String endYear = ""; - - public ShufflePlayBuffer(DownloadService context) { - this.context = context; - - executorService = Executors.newSingleThreadScheduledExecutor(); - runnable = new Runnable() { - @Override - public void run() { - refill(); - } - }; - executorService.scheduleWithFixedDelay(runnable, 1, 10, TimeUnit.SECONDS); - - // Calculate out the capacity and refill threshold based on the user's random size preference - int shuffleListSize = Integer.parseInt(Util.getPreferences(context).getString(Constants.PREFERENCES_KEY_RANDOM_SIZE, "20")); - // ex: default 20 -> 50 - capacity = shuffleListSize * 5 / 2; - capacity = Math.min(500, capacity); - - // ex: default 20 -> 40 - refillThreshold = capacity * 4 / 5; - } - - public List get(int size) { - clearBufferIfnecessary(); - // Make sure fetcher is running if needed - restart(); - - List result = new ArrayList(size); - synchronized (buffer) { - boolean removed = false; - while (!buffer.isEmpty() && result.size() < size) { - result.add(buffer.remove(buffer.size() - 1)); - removed = true; - } - - // Re-cache if anything is taken out - if(removed) { - FileUtil.serialize(context, buffer, CACHE_FILENAME); - } - } - Log.i(TAG, "Taking " + result.size() + " songs from shuffle play buffer. " + buffer.size() + " remaining."); - if(result.isEmpty()) { - awaitingResults = true; - } - return result; - } - - public void shutdown() { - executorService.shutdown(); - Util.getPreferences(context).unregisterOnSharedPreferenceChangeListener(listener); - } - - private void restart() { - synchronized(buffer) { - if(buffer.size() <= refillThreshold && lastCount != 0 && executorService.isShutdown()) { - executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleWithFixedDelay(runnable, 0, 10, TimeUnit.SECONDS); - } - } - } - - private void refill() { - // Check if active server has changed. - clearBufferIfnecessary(); - - if (buffer != null && (buffer.size() > refillThreshold || (!Util.isNetworkConnected(context) && !Util.isOffline(context)) || lastCount == 0)) { - executorService.shutdown(); - return; - } - - try { - MusicService service = MusicServiceFactory.getMusicService(context); - - // Get capacity based - int n = capacity - buffer.size(); - String folder = null; - if(!Util.isTagBrowsing(context)) { - folder = Util.getSelectedMusicFolderId(context); - } - MusicDirectory songs = service.getRandomSongs(n, folder, genre, startYear, endYear, context, null); - - synchronized (buffer) { - lastCount = 0; - for(MusicDirectory.Entry entry: songs.getChildren()) { - if(!buffer.contains(entry) && entry.getRating() != 1) { - buffer.add(entry); - lastCount++; - } - } - Log.i(TAG, "Refilled shuffle play buffer with " + lastCount + " songs."); - - // Cache buffer - FileUtil.serialize(context, buffer, CACHE_FILENAME); - } - } catch (Exception x) { - // Give it one more try before quitting - if(lastCount != -2) { - lastCount = -2; - } else if(lastCount == -2) { - lastCount = 0; - } - Log.w(TAG, "Failed to refill shuffle play buffer.", x); - } - - if(awaitingResults) { - awaitingResults = false; - context.checkDownloads(); - } - } - - private void clearBufferIfnecessary() { - synchronized (buffer) { - final SharedPreferences prefs = Util.getPreferences(context); - if (currentServer != Util.getActiveServer(context) - || !Util.equals(currentFolder, Util.getSelectedMusicFolderId(context)) - || (genre != null && !genre.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, ""))) - || (startYear != null && !startYear.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, ""))) - || (endYear != null && !endYear.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, "")))) { - lastCount = -1; - currentServer = Util.getActiveServer(context); - currentFolder = Util.getSelectedMusicFolderId(context); - genre = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, ""); - startYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, ""); - endYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, ""); - buffer.clear(); - - if(firstRun) { - ArrayList cacheList = FileUtil.deserialize(context, CACHE_FILENAME, ArrayList.class); - if(cacheList != null) { - buffer.addAll(cacheList); - } - - listener = new SharedPreferences.OnSharedPreferenceChangeListener() { - @Override - public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { - clearBufferIfnecessary(); - restart(); - } - }; - prefs.registerOnSharedPreferenceChangeListener(listener); - firstRun = false; - } else { - // Clear cache - File file = new File(context.getCacheDir(), CACHE_FILENAME); - file.delete(); - } - } - } - } -} diff --git a/src/github/daneren2005/dsub/util/SilentBackgroundTask.java b/src/github/daneren2005/dsub/util/SilentBackgroundTask.java deleted file mode 100644 index b99b7e0e..00000000 --- a/src/github/daneren2005/dsub/util/SilentBackgroundTask.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.util; - -import android.content.Context; - -/** - * @author Sindre Mehus - */ -public abstract class SilentBackgroundTask extends BackgroundTask { - public SilentBackgroundTask(Context context) { - super(context); - } - - @Override - public void execute() { - queue.offer(task = new Task()); - } - - @Override - protected void done(T result) { - // Don't do anything unless overriden - } - - @Override - public void updateProgress(int messageId) { - } - - @Override - public void updateProgress(String message) { - } -} diff --git a/src/github/daneren2005/dsub/util/SimpleServiceBinder.java b/src/github/daneren2005/dsub/util/SimpleServiceBinder.java deleted file mode 100644 index 9c0b36a9..00000000 --- a/src/github/daneren2005/dsub/util/SimpleServiceBinder.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.util; - -import android.os.Binder; - -/** - * @author Sindre Mehus - */ -public class SimpleServiceBinder extends Binder { - - private final S service; - - public SimpleServiceBinder(S service) { - this.service = service; - } - - public S getService() { - return service; - } -} diff --git a/src/github/daneren2005/dsub/util/SyncUtil.java b/src/github/daneren2005/dsub/util/SyncUtil.java deleted file mode 100644 index 15fa2d47..00000000 --- a/src/github/daneren2005/dsub/util/SyncUtil.java +++ /dev/null @@ -1,222 +0,0 @@ -package github.daneren2005.dsub.util; - -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.Context; -import android.content.Intent; -import android.support.v4.app.NotificationCompat; - -import java.io.File; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.SubsonicFragmentActivity; - -/** - * Created by Scott on 11/24/13. - */ -public final class SyncUtil { - private static String TAG = SyncUtil.class.getSimpleName(); - private static ArrayList syncedPlaylists; - private static ArrayList syncedPodcasts; - private static String url; - - private static void checkRestURL(Context context) { - int instance = Util.getActiveServer(context); - String newURL = Util.getRestUrl(context, null, instance, false); - if(url == null || !url.equals(newURL)) { - syncedPlaylists = null; - syncedPodcasts = null; - url = newURL; - } - } - - // Playlist sync - public static boolean isSyncedPlaylist(Context context, String playlistId) { - checkRestURL(context); - if(syncedPlaylists == null) { - syncedPlaylists = getSyncedPlaylists(context); - } - return syncedPlaylists.contains(new SyncSet(playlistId)); - } - public static ArrayList getSyncedPlaylists(Context context) { - return getSyncedPlaylists(context, Util.getActiveServer(context)); - } - public static ArrayList getSyncedPlaylists(Context context, int instance) { - String syncFile = getPlaylistSyncFile(context, instance); - ArrayList playlists = FileUtil.deserializeCompressed(context, syncFile, ArrayList.class); - if(playlists == null) { - playlists = new ArrayList(); - - // Try to convert old style into new style - ArrayList oldPlaylists = FileUtil.deserialize(context, syncFile, ArrayList.class); - // If exists, time to convert! - if(oldPlaylists != null) { - for(String id: oldPlaylists) { - playlists.add(new SyncSet(id)); - } - - FileUtil.serializeCompressed(context, playlists, syncFile); - } - } - return playlists; - } - public static void setSyncedPlaylists(Context context, int instance, ArrayList playlists) { - FileUtil.serializeCompressed(context, playlists, getPlaylistSyncFile(context, instance)); - } - public static void addSyncedPlaylist(Context context, String playlistId) { - String playlistFile = getPlaylistSyncFile(context); - ArrayList playlists = getSyncedPlaylists(context); - SyncSet set = new SyncSet(playlistId); - if(!playlists.contains(set)) { - playlists.add(set); - } - FileUtil.serializeCompressed(context, playlists, playlistFile); - syncedPlaylists = playlists; - } - public static void removeSyncedPlaylist(Context context, String playlistId) { - int instance = Util.getActiveServer(context); - removeSyncedPlaylist(context, playlistId, instance); - } - public static void removeSyncedPlaylist(Context context, String playlistId, int instance) { - String playlistFile = getPlaylistSyncFile(context, instance); - ArrayList playlists = getSyncedPlaylists(context, instance); - SyncSet set = new SyncSet(playlistId); - if(playlists.contains(set)) { - playlists.remove(set); - FileUtil.serializeCompressed(context, playlists, playlistFile); - syncedPlaylists = playlists; - } - } - public static String getPlaylistSyncFile(Context context) { - int instance = Util.getActiveServer(context); - return getPlaylistSyncFile(context, instance); - } - public static String getPlaylistSyncFile(Context context, int instance) { - return "sync-playlist-" + (Util.getRestUrl(context, null, instance, false)).hashCode() + ".ser"; - } - - // Podcast sync - public static boolean isSyncedPodcast(Context context, String podcastId) { - checkRestURL(context); - if(syncedPodcasts == null) { - syncedPodcasts = getSyncedPodcasts(context); - } - return syncedPodcasts.contains(new SyncSet(podcastId)); - } - public static ArrayList getSyncedPodcasts(Context context) { - return getSyncedPodcasts(context, Util.getActiveServer(context)); - } - public static ArrayList getSyncedPodcasts(Context context, int instance) { - ArrayList podcasts = FileUtil.deserialize(context, getPodcastSyncFile(context, instance), ArrayList.class); - if(podcasts == null) { - podcasts = new ArrayList(); - } - return podcasts; - } - public static void addSyncedPodcast(Context context, String podcastId, List synced) { - String podcastFile = getPodcastSyncFile(context); - ArrayList podcasts = getSyncedPodcasts(context); - SyncSet set = new SyncSet(podcastId, synced); - if(!podcasts.contains(set)) { - podcasts.add(set); - } - FileUtil.serialize(context, podcasts, podcastFile); - syncedPodcasts = podcasts; - } - public static void removeSyncedPodcast(Context context, String podcastId) { - removeSyncedPodcast(context, podcastId, Util.getActiveServer(context)); - } - public static void removeSyncedPodcast(Context context, String podcastId, int instance) { - String podcastFile = getPodcastSyncFile(context, instance); - ArrayList podcasts = getSyncedPodcasts(context, instance); - SyncSet set = new SyncSet(podcastId); - if(podcasts.contains(set)) { - podcasts.remove(set); - FileUtil.serialize(context, podcasts, podcastFile); - syncedPodcasts = podcasts; - } - } - public static String getPodcastSyncFile(Context context) { - int instance = Util.getActiveServer(context); - return getPodcastSyncFile(context, instance); - } - public static String getPodcastSyncFile(Context context, int instance) { - return "sync-podcast-" + (Util.getRestUrl(context, null, instance, false)).hashCode() + ".ser"; - } - - // Starred - public static ArrayList getSyncedStarred(Context context, int instance) { - ArrayList list = FileUtil.deserializeCompressed(context, getStarredSyncFile(context, instance), ArrayList.class); - if(list == null) { - list = new ArrayList(); - } - return list; - } - public static void setSyncedStarred(ArrayList syncedList, Context context, int instance) { - FileUtil.serializeCompressed(context, syncedList, SyncUtil.getStarredSyncFile(context, instance)); - } - public static String getStarredSyncFile(Context context, int instance) { - return "sync-starred-" + (Util.getRestUrl(context, null, instance, false)).hashCode() + ".ser"; - } - - // Most Recently Added - public static ArrayList getSyncedMostRecent(Context context, int instance) { - ArrayList list = FileUtil.deserialize(context, getMostRecentSyncFile(context, instance), ArrayList.class); - if(list == null) { - list = new ArrayList(); - } - return list; - } - public static void removeMostRecentSyncFiles(Context context) { - int total = Util.getServerCount(context); - for(int i = 0; i < total; i++) { - File file = new File(context.getCacheDir(), getMostRecentSyncFile(context, i)); - file.delete(); - } - } - public static String getMostRecentSyncFile(Context context, int instance) { - return "sync-most_recent-" + (Util.getRestUrl(context, null, instance, false)).hashCode() + ".ser"; - } - - public static String joinNames(List names) { - StringBuilder builder = new StringBuilder(); - for (String val : names) { - builder.append(val).append(", "); - } - builder.setLength(builder.length() - 2); - return builder.toString(); - } - - public static class SyncSet implements Serializable { - public String id; - public List synced; - - protected SyncSet() { - - } - public SyncSet(String id) { - this.id = id; - } - public SyncSet(String id, List synced) { - this.id = id; - this.synced = synced; - } - - @Override - public boolean equals(Object obj) { - if(obj instanceof SyncSet) { - return this.id.equals(((SyncSet)obj).id); - } else { - return false; - } - } - - @Override - public int hashCode() { - return id.hashCode(); - } - } -} diff --git a/src/github/daneren2005/dsub/util/TabBackgroundTask.java b/src/github/daneren2005/dsub/util/TabBackgroundTask.java deleted file mode 100644 index b0a24b28..00000000 --- a/src/github/daneren2005/dsub/util/TabBackgroundTask.java +++ /dev/null @@ -1,51 +0,0 @@ -package github.daneren2005.dsub.util; - -import github.daneren2005.dsub.fragments.SubsonicFragment; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public abstract class TabBackgroundTask extends BackgroundTask { - - private final SubsonicFragment tabFragment; - - public TabBackgroundTask(SubsonicFragment fragment) { - super(fragment.getActivity()); - tabFragment = fragment; - } - - @Override - public void execute() { - tabFragment.setProgressVisible(true); - - queue.offer(task = new Task() { - @Override - public void onDone(T result) { - tabFragment.setProgressVisible(false); - done(result); - } - - @Override - public void onError(Throwable t) { - tabFragment.setProgressVisible(false); - error(t); - } - }); - } - - @Override - public boolean isCancelled() { - return !tabFragment.isAdded() || cancelled.get(); - } - - @Override - public void updateProgress(final String message) { - getHandler().post(new Runnable() { - @Override - public void run() { - tabFragment.updateProgress(message); - } - }); - } -} diff --git a/src/github/daneren2005/dsub/util/TimeLimitedCache.java b/src/github/daneren2005/dsub/util/TimeLimitedCache.java deleted file mode 100644 index 8b7df783..00000000 --- a/src/github/daneren2005/dsub/util/TimeLimitedCache.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.util; - -import java.lang.ref.SoftReference; -import java.util.concurrent.TimeUnit; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public class TimeLimitedCache { - - private SoftReference value; - private final long ttlMillis; - private long expires; - - public TimeLimitedCache(long ttl, TimeUnit timeUnit) { - this.ttlMillis = TimeUnit.MILLISECONDS.convert(ttl, timeUnit); - } - - public T get() { - return System.currentTimeMillis() < expires ? value.get() : null; - } - - public void set(T value) { - set(value, ttlMillis, TimeUnit.MILLISECONDS); - } - - public void set(T value, long ttl, TimeUnit timeUnit) { - this.value = new SoftReference(value); - expires = System.currentTimeMillis() + timeUnit.toMillis(ttl); - } - - public void clear() { - expires = 0L; - value = null; - } -} diff --git a/src/github/daneren2005/dsub/util/UserUtil.java b/src/github/daneren2005/dsub/util/UserUtil.java deleted file mode 100644 index c5da93d3..00000000 --- a/src/github/daneren2005/dsub/util/UserUtil.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.util; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.SharedPreferences; -import android.support.v7.app.ActionBarActivity; -import android.util.Log; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.widget.TextView; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.User; -import github.daneren2005.dsub.fragments.SubsonicFragment; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.service.OfflineException; -import github.daneren2005.dsub.service.ServerTooOldException; -import github.daneren2005.dsub.adapter.SettingsAdapter; - -public final class UserUtil { - private static final String TAG = UserUtil.class.getSimpleName(); - private static final long MIN_VERIFY_DURATION = 1000L * 60L * 60L; - - private static int instance = -1; - private static User currentUser; - private static long lastVerifiedTime = 0; - - - public static void refreshCurrentUser(Context context, boolean forceRefresh) { - refreshCurrentUser(context, forceRefresh, false); - } - public static void refreshCurrentUser(Context context, boolean forceRefresh, boolean unAuth) { - currentUser = null; - if(unAuth) { - lastVerifiedTime = 0; - } - seedCurrentUser(context, forceRefresh); - } - - public static void seedCurrentUser(Context context) { - seedCurrentUser(context, false); - } - public static void seedCurrentUser(final Context context, final boolean refresh) { - // Only try to seed if online - if(Util.isOffline(context)) { - currentUser = null; - return; - } - - final int instance = Util.getActiveServer(context); - if(UserUtil.instance == instance && currentUser != null) { - return; - } else { - UserUtil.instance = instance; - } - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - currentUser = MusicServiceFactory.getMusicService(context).getUser(refresh, getCurrentUsername(context, instance), context, null); - - // If running, redo cast selector - DownloadService downloadService = DownloadService.getInstance(); - if(downloadService != null) { - downloadService.userSettingsChanged(); - } - - return null; - } - - @Override - protected void done(Void result) { - if(context instanceof ActionBarActivity) { - ((ActionBarActivity) context).supportInvalidateOptionsMenu(); - } - } - - @Override - protected void error(Throwable error) { - // Don't do anything, supposed to be background pull - Log.e(TAG, "Failed to seed user information"); - } - }.execute(); - } - - public static User getCurrentUser() { - return currentUser; - } - - public static String getCurrentUsername(Context context, int instance) { - SharedPreferences prefs = Util.getPreferences(context); - return prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null); - } - - public static String getCurrentUsername(Context context) { - return getCurrentUsername(context, Util.getActiveServer(context)); - } - - public static boolean isCurrentAdmin() { - return isCurrentRole(User.ADMIN); - } - - public static boolean canPodcast() { - return isCurrentRole(User.PODCAST); - } - public static boolean canShare() { - return isCurrentRole(User.SHARE); - } - public static boolean canJukebox() { - return isCurrentRole(User.JUKEBOX); - } - public static boolean canScrobble() { - return isCurrentRole(User.SCROBBLING, true); - } - - public static boolean isCurrentRole(String role) { - return isCurrentRole(role, false); - } - public static boolean isCurrentRole(String role, boolean defaultValue) { - if(currentUser == null) { - return defaultValue; - } - - for(User.Setting setting: currentUser.getSettings()) { - if(setting.getName().equals(role)) { - return setting.getValue() == true; - } - } - - return defaultValue; - } - - public static void confirmCredentials(final Activity context, final Runnable onSuccess) { - final long currentTime = System.currentTimeMillis(); - // If already ran this check within last x time, just go ahead and auth - if((currentTime - lastVerifiedTime) < MIN_VERIFY_DURATION) { - onSuccess.run(); - } else { - View layout = context.getLayoutInflater().inflate(R.layout.confirm_password, null); - final TextView passwordView = (TextView) layout.findViewById(R.id.password); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.admin_confirm_password) - .setView(layout) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - String password = passwordView.getText().toString(); - - SharedPreferences prefs = Util.getPreferences(context); - String correctPassword = prefs.getString(Constants.PREFERENCES_KEY_PASSWORD + Util.getActiveServer(context), null); - - if(password != null && password.equals(correctPassword)) { - lastVerifiedTime = currentTime; - onSuccess.run(); - } else { - Util.toast(context, R.string.admin_confirm_password_bad); - } - } - }) - .setNegativeButton(R.string.common_cancel, null) - .setCancelable(true); - - AlertDialog dialog = builder.create(); - dialog.show(); - } - } - - public static void changePassword(final Activity context, final User user) { - View layout = context.getLayoutInflater().inflate(R.layout.change_password, null); - final TextView passwordView = (TextView) layout.findViewById(R.id.new_password); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.admin_change_password) - .setView(layout) - .setPositiveButton(R.string.common_save, null) - .setNegativeButton(R.string.common_cancel, null) - .setCancelable(true); - - final AlertDialog dialog = builder.create(); - dialog.show(); - - dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - final String password = passwordView.getText().toString(); - // Don't allow blank passwords - if ("".equals(password)) { - Util.toast(context, R.string.admin_change_password_invalid); - return; - } - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.changePassword(user.getUsername(), password, context, null); - return null; - } - - @Override - protected void done(Void v) { - Util.toast(context, context.getResources().getString(R.string.admin_change_password_success, user.getUsername())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.admin_change_password_error, user.getUsername()); - } - - Util.toast(context, msg); - } - }.execute(); - - dialog.dismiss(); - } - }); - } - - public static void updateSettings(final Context context, final User user) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.updateUser(user, context, null); - user.setSettings(user.getSettings()); - return null; - } - - @Override - protected void done(Void v) { - Util.toast(context, context.getResources().getString(R.string.admin_update_permissions_success, user.getUsername())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.admin_update_permissions_error, user.getUsername()); - } - - Util.toast(context, msg); - } - }.execute(); - } - - public static void changeEmail(final Activity context, final User user) { - View layout = context.getLayoutInflater().inflate(R.layout.change_email, null); - final TextView emailView = (TextView) layout.findViewById(R.id.new_email); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.admin_change_email) - .setView(layout) - .setPositiveButton(R.string.common_save, null) - .setNegativeButton(R.string.common_cancel, null) - .setCancelable(true); - - final AlertDialog dialog = builder.create(); - dialog.show(); - - dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - final String email = emailView.getText().toString(); - // Don't allow blank emails - if ("".equals(email)) { - Util.toast(context, R.string.admin_change_email_invalid); - return; - } - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.changeEmail(user.getUsername(), email, context, null); - user.setEmail(email); - return null; - } - - @Override - protected void done(Void v) { - Util.toast(context, context.getResources().getString(R.string.admin_change_email_success, user.getUsername())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.admin_change_email_error, user.getUsername()); - } - - Util.toast(context, msg); - } - }.execute(); - - dialog.dismiss(); - } - }); - } - - public static void deleteUser(final Context context, final User user, final ArrayAdapter adapter) { - Util.confirmDialog(context, R.string.common_delete, user.getUsername(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.deleteUser(user.getUsername(), context, null); - return null; - } - - @Override - protected void done(Void v) { - if(adapter != null) { - adapter.remove(user); - adapter.notifyDataSetChanged(); - } - - Util.toast(context, context.getResources().getString(R.string.admin_delete_user_success, user.getUsername())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.admin_delete_user_error, user.getUsername()); - } - - Util.toast(context, msg); - } - }.execute(); - } - }); - } - - public static void addNewUser(final Activity context, final SubsonicFragment fragment) { - final User user = new User(); - for(String role: User.ROLES) { - if(role.equals(User.SETTINGS) || role.equals(User.STREAM)) { - user.addSetting(role, true); - } else { - user.addSetting(role, false); - } - } - - View layout = context.getLayoutInflater().inflate(R.layout.create_user, null); - final TextView usernameView = (TextView) layout.findViewById(R.id.username); - final TextView emailView = (TextView) layout.findViewById(R.id.email); - final TextView passwordView = (TextView) layout.findViewById(R.id.password); - final ListView listView = (ListView) layout.findViewById(R.id.settings_list); - listView.setAdapter(new SettingsAdapter(context, user, true)); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.menu_add_user) - .setView(layout) - .setPositiveButton(R.string.common_save, null) - .setNegativeButton(R.string.common_cancel, null) - .setCancelable(true); - - final AlertDialog dialog = builder.create(); - dialog.show(); - - dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - final String username = usernameView.getText().toString(); - // Don't allow blank emails - if ("".equals(username)) { - Util.toast(context, R.string.admin_change_username_invalid); - return; - } - - final String email = emailView.getText().toString(); - // Don't allow blank emails - if ("".equals(email)) { - Util.toast(context, R.string.admin_change_email_invalid); - return; - } - - final String password = passwordView.getText().toString(); - if ("".equals(password)) { - Util.toast(context, R.string.admin_change_password_invalid); - return; - } - - user.setUsername(username); - user.setEmail(email); - user.setPassword(password); - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.createUser(user, context, null); - return null; - } - - @Override - protected void done(Void v) { - fragment.onRefresh(); - Util.toast(context, context.getResources().getString(R.string.admin_create_user_success)); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.admin_create_user_error); - } - - Util.toast(context, msg); - } - }.execute(); - - dialog.dismiss(); - } - }); - } -} diff --git a/src/github/daneren2005/dsub/util/Util.java b/src/github/daneren2005/dsub/util/Util.java deleted file mode 100644 index 75d8d5dd..00000000 --- a/src/github/daneren2005/dsub/util/Util.java +++ /dev/null @@ -1,1339 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.util; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.app.AlertDialog; -import android.content.ComponentName; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.media.AudioManager; -import android.media.AudioManager.OnAudioFocusChangeListener; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.wifi.WifiManager; -import android.os.Build; -import android.os.Environment; -import android.text.Html; -import android.text.SpannableString; -import android.text.method.LinkMovementMethod; -import android.text.util.Linkify; -import android.util.Log; -import android.view.Gravity; -import android.widget.TextView; -import android.widget.Toast; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.domain.RepeatMode; -import github.daneren2005.dsub.receiver.MediaButtonIntentReceiver; -import github.daneren2005.dsub.service.DownloadService; - -import org.apache.http.HttpEntity; - -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.security.MessageDigest; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.Locale; - -/** - * @author Sindre Mehus - * @version $Id$ - */ -public final class Util { - private static final String TAG = Util.class.getSimpleName(); - - private static final DecimalFormat GIGA_BYTE_FORMAT = new DecimalFormat("0.00 GB"); - private static final DecimalFormat MEGA_BYTE_FORMAT = new DecimalFormat("0.00 MB"); - private static final DecimalFormat KILO_BYTE_FORMAT = new DecimalFormat("0 KB"); - - private static DecimalFormat GIGA_BYTE_LOCALIZED_FORMAT = null; - private static DecimalFormat MEGA_BYTE_LOCALIZED_FORMAT = null; - private static DecimalFormat KILO_BYTE_LOCALIZED_FORMAT = null; - private static DecimalFormat BYTE_LOCALIZED_FORMAT = null; - private static SimpleDateFormat DATE_FORMAT_SHORT = new SimpleDateFormat("MMM d h:mm a"); - private static SimpleDateFormat DATE_FORMAT_LONG = new SimpleDateFormat("MMM d, yyyy h:mm a"); - private static int CURRENT_YEAR = new Date().getYear(); - - public static final String EVENT_META_CHANGED = "github.daneren2005.dsub.EVENT_META_CHANGED"; - public static final String EVENT_PLAYSTATE_CHANGED = "github.daneren2005.dsub.EVENT_PLAYSTATE_CHANGED"; - - public static final String AVRCP_PLAYSTATE_CHANGED = "com.android.music.playstatechanged"; - public static final String AVRCP_METADATA_CHANGED = "com.android.music.metachanged"; - - private static OnAudioFocusChangeListener focusListener; - private static boolean pauseFocus = false; - private static boolean lowerFocus = false; - - // Used by hexEncode() - private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - - private static Toast toast; - - private Util() { - } - - public static boolean isOffline(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_OFFLINE, false); - } - - public static void setOffline(Context context, boolean offline) { - SharedPreferences prefs = getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(Constants.PREFERENCES_KEY_OFFLINE, offline); - editor.commit(); - } - - public static boolean isScreenLitOnDownload(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_SCREEN_LIT_ON_DOWNLOAD, false); - } - - public static RepeatMode getRepeatMode(Context context) { - SharedPreferences prefs = getPreferences(context); - return RepeatMode.valueOf(prefs.getString(Constants.PREFERENCES_KEY_REPEAT_MODE, RepeatMode.OFF.name())); - } - - public static void setRepeatMode(Context context, RepeatMode repeatMode) { - SharedPreferences prefs = getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - editor.putString(Constants.PREFERENCES_KEY_REPEAT_MODE, repeatMode.name()); - editor.commit(); - } - - public static boolean isScrobblingEnabled(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_SCROBBLE, true) && (isOffline(context) || UserUtil.canScrobble()); - } - - public static void setActiveServer(Context context, int instance) { - SharedPreferences prefs = getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, instance); - editor.commit(); - } - - public static int getActiveServer(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_OFFLINE, false) ? 0 : prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); - } - - public static int getServerCount(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 1); - } - - public static void removeInstanceName(Context context, int instance, int activeInstance) { - SharedPreferences prefs = getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - - int newInstance = instance + 1; - - // Get what the +1 server details are - String server = prefs.getString(Constants.PREFERENCES_KEY_SERVER_KEY + newInstance, null); - String serverName = prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + newInstance, null); - String serverUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + newInstance, null); - String userName = prefs.getString(Constants.PREFERENCES_KEY_USERNAME + newInstance, null); - String password = prefs.getString(Constants.PREFERENCES_KEY_PASSWORD + newInstance, null); - String musicFolderId = prefs.getString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + newInstance, null); - - // Store the +1 server details in the to be deleted instance - editor.putString(Constants.PREFERENCES_KEY_SERVER_KEY + instance, server); - editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, serverName); - editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + instance, serverUrl); - editor.putString(Constants.PREFERENCES_KEY_USERNAME + instance, userName); - editor.putString(Constants.PREFERENCES_KEY_PASSWORD + instance, password); - editor.putString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + instance, musicFolderId); - - // Delete the +1 server instance - // Calling method will loop up to fill this in if +2 server exists - editor.putString(Constants.PREFERENCES_KEY_SERVER_KEY + newInstance, null); - editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + newInstance, null); - editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + newInstance, null); - editor.putString(Constants.PREFERENCES_KEY_USERNAME + newInstance, null); - editor.putString(Constants.PREFERENCES_KEY_PASSWORD + newInstance, null); - editor.putString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + newInstance, null); - editor.commit(); - - if (instance == activeInstance) { - if(instance != 1) { - Util.setActiveServer(context, 1); - } else { - Util.setOffline(context, true); - } - } else if (newInstance == activeInstance) { - Util.setActiveServer(context, instance); - } - } - - public static String getServerName(Context context) { - SharedPreferences prefs = getPreferences(context); - int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); - return prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null); - } - public static String getServerName(Context context, int instance) { - SharedPreferences prefs = getPreferences(context); - return prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null); - } - - public static void setSelectedMusicFolderId(Context context, String musicFolderId) { - int instance = getActiveServer(context); - SharedPreferences prefs = getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - editor.putString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + instance, musicFolderId); - editor.commit(); - } - - public static String getSelectedMusicFolderId(Context context) { - return getSelectedMusicFolderId(context, getActiveServer(context)); - } - public static String getSelectedMusicFolderId(Context context, int instance) { - SharedPreferences prefs = getPreferences(context); - return prefs.getString(Constants.PREFERENCES_KEY_MUSIC_FOLDER_ID + instance, null); - } - - public static boolean getAlbumListsPerFolder(Context context) { - return getAlbumListsPerFolder(context, getActiveServer(context)); - } - public static boolean getAlbumListsPerFolder(Context context, int instance) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_ALBUMS_PER_FOLDER + instance, false); - } - public static void setAlbumListsPerFolder(Context context, boolean perFolder) { - int instance = getActiveServer(context); - SharedPreferences prefs = getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(Constants.PREFERENCES_KEY_ALBUMS_PER_FOLDER + instance, perFolder); - editor.commit(); - } - - public static String getTheme(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getString(Constants.PREFERENCES_KEY_THEME, null); - } - public static void setTheme(Context context, String theme) { - SharedPreferences.Editor editor = getPreferences(context).edit(); - editor.putString(Constants.PREFERENCES_KEY_THEME, theme); - editor.commit(); - } - - public static void applyTheme(Context context, String theme) { - if ("dark".equals(theme)) { - context.setTheme(R.style.Theme_DSub_Dark); - } else if ("black".equals(theme)) { - context.setTheme(R.style.Theme_DSub_Black); - } else if ("holo".equals(theme)) { - context.setTheme(R.style.Theme_DSub_Holo); - } else { - context.setTheme(R.style.Theme_DSub_Light); - } - - SharedPreferences prefs = Util.getPreferences(context); - if(prefs.getBoolean(Constants.PREFERENCES_KEY_OVERRIDE_SYSTEM_LANGUAGE, false)) { - Configuration config = new Configuration(); - config.locale = Locale.ENGLISH; - context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics()); - } - } - - public static boolean getDisplayTrack(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_DISPLAY_TRACK, false); - } - - public static int getMaxBitrate(Context context) { - ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = manager.getActiveNetworkInfo(); - if (networkInfo == null) { - return 0; - } - - boolean wifi = networkInfo.getType() == ConnectivityManager.TYPE_WIFI; - SharedPreferences prefs = getPreferences(context); - return Integer.parseInt(prefs.getString(wifi ? Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI : Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE, "0")); - } - - public static int getMaxVideoBitrate(Context context) { - ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = manager.getActiveNetworkInfo(); - if (networkInfo == null) { - return 0; - } - - boolean wifi = networkInfo.getType() == ConnectivityManager.TYPE_WIFI; - SharedPreferences prefs = getPreferences(context); - return Integer.parseInt(prefs.getString(wifi ? Constants.PREFERENCES_KEY_MAX_VIDEO_BITRATE_WIFI : Constants.PREFERENCES_KEY_MAX_VIDEO_BITRATE_MOBILE, "0")); - } - - public static int getPreloadCount(Context context) { - ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = manager.getActiveNetworkInfo(); - if (networkInfo == null) { - return 3; - } - - SharedPreferences prefs = getPreferences(context); - boolean wifi = networkInfo.getType() == ConnectivityManager.TYPE_WIFI; - int preloadCount = Integer.parseInt(prefs.getString(wifi ? Constants.PREFERENCES_KEY_PRELOAD_COUNT_WIFI : Constants.PREFERENCES_KEY_PRELOAD_COUNT_MOBILE, "-1")); - return preloadCount == -1 ? Integer.MAX_VALUE : preloadCount; - } - - public static int getCacheSizeMB(Context context) { - SharedPreferences prefs = getPreferences(context); - int cacheSize = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_CACHE_SIZE, "-1")); - return cacheSize == -1 ? Integer.MAX_VALUE : cacheSize; - } - - public static String getRestUrl(Context context, String method) { - return getRestUrl(context, method, true); - } - public static String getRestUrl(Context context, String method, boolean allowAltAddress) { - SharedPreferences prefs = getPreferences(context); - int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); - return getRestUrl(context, method, prefs, instance, allowAltAddress); - } - public static String getRestUrl(Context context, String method, int instance) { - return getRestUrl(context, method, instance, true); - } - public static String getRestUrl(Context context, String method, int instance, boolean allowAltAddress) { - SharedPreferences prefs = getPreferences(context); - return getRestUrl(context, method, prefs, instance, allowAltAddress); - } - public static String getRestUrl(Context context, String method, SharedPreferences prefs, int instance) { - return getRestUrl(context, method, prefs, instance, true); - } - public static String getRestUrl(Context context, String method, SharedPreferences prefs, int instance, boolean allowAltAddress) { - StringBuilder builder = new StringBuilder(); - - String serverUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null); - if(allowAltAddress && Util.isWifiConnected(context)) { - String SSID = prefs.getString(Constants.PREFERENCES_KEY_SERVER_LOCAL_NETWORK_SSID + instance, ""); - String currentSSID = Util.getSSID(context); - - String[] ssidParts = SSID.split(","); - if("".equals(SSID) || SSID.equals(currentSSID) || Arrays.asList(ssidParts).contains(currentSSID)) { - String internalUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_INTERNAL_URL + instance, null); - if(internalUrl != null && !"".equals(internalUrl) && !"http://".equals(internalUrl)) { - serverUrl = internalUrl; - } - } - } - - String username = prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null); - String password = prefs.getString(Constants.PREFERENCES_KEY_PASSWORD + instance, null); - - // Slightly obfuscate password - password = "enc:" + Util.utf8HexEncode(password); - - builder.append(serverUrl); - if (builder.charAt(builder.length() - 1) != '/') { - builder.append("/"); - } - builder.append("rest/").append(method).append(".view"); - builder.append("?u=").append(username); - builder.append("&p=").append(password); - builder.append("&v=").append(Constants.REST_PROTOCOL_VERSION); - builder.append("&c=").append(Constants.REST_CLIENT_ID); - - return builder.toString(); - } - - public static String replaceInternalUrl(Context context, String url) { - // Only change to internal when using https - if(url.indexOf("https") != -1) { - SharedPreferences prefs = Util.getPreferences(context); - int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); - String internalUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_INTERNAL_URL + instance, null); - if(internalUrl != null && !"".equals(internalUrl)) { - String externalUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null); - url = url.replace(internalUrl, externalUrl); - } - } - - // Use separate profile for Chromecast so users can do ogg on phone, mp3 for CC - return url.replace("c=" + Constants.REST_CLIENT_ID, "c=" + Constants.CHROMECAST_CLIENT_ID); - } - - public static boolean isTagBrowsing(Context context) { - return isTagBrowsing(context, Util.getActiveServer(context)); - } - public static boolean isTagBrowsing(Context context, int instance) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_BROWSE_TAGS + instance, false); - } - - public static boolean isSyncEnabled(Context context, int instance) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_SERVER_SYNC + instance, true); - } - - public static String getParentFromEntry(Context context, MusicDirectory.Entry entry) { - if(Util.isTagBrowsing(context)) { - if(!entry.isDirectory()) { - return entry.getAlbumId(); - } else if(entry.isAlbum()) { - return entry.getArtistId(); - } else { - return null; - } - } else { - return entry.getParent(); - } - } - - public static String openToTab(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getString(Constants.PREFERENCES_KEY_OPEN_TO_TAB, null); - } - - public static boolean disableExitPrompt(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_DISABLE_EXIT_PROMPT, false); - } - - public static String getVideoPlayerType(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getString(Constants.PREFERENCES_KEY_VIDEO_PLAYER, "raw"); - } - - public static SharedPreferences getPreferences(Context context) { - return context.getSharedPreferences(Constants.PREFERENCES_FILE_NAME, 0); - } - public static SharedPreferences getOfflineSync(Context context) { - return context.getSharedPreferences(Constants.OFFLINE_SYNC_NAME, 0); - } - - public static String getSyncDefault(Context context) { - SharedPreferences prefs = Util.getOfflineSync(context); - return prefs.getString(Constants.OFFLINE_SYNC_DEFAULT, null); - } - public static void setSyncDefault(Context context, String defaultValue) { - SharedPreferences.Editor editor = Util.getOfflineSync(context).edit(); - editor.putString(Constants.OFFLINE_SYNC_DEFAULT, defaultValue); - editor.commit(); - } - - public static String getCacheName(Context context, String name, String id) { - return getCacheName(context, getActiveServer(context), name, id); - } - public static String getCacheName(Context context, int instance, String name, String id) { - String s = getRestUrl(context, null, instance, false) + id; - return name + "-" + s.hashCode() + ".ser"; - } - public static String getCacheName(Context context, String name) { - return getCacheName(context, getActiveServer(context), name); - } - public static String getCacheName(Context context, int instance, String name) { - String s = getRestUrl(context, null, instance, false); - return name + "-" + s.hashCode() + ".ser"; - } - - public static int offlineScrobblesCount(Context context) { - SharedPreferences offline = getOfflineSync(context); - return offline.getInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); - } - public static int offlineStarsCount(Context context) { - SharedPreferences offline = getOfflineSync(context); - return offline.getInt(Constants.OFFLINE_STAR_COUNT, 0); - } - - public static String parseOfflineIDSearch(Context context, String id, String cacheLocation) { - // Try to get this info based off of tags first - String name = parseOfflineIDSearch(id); - if(name != null) { - return name; - } - - // Otherwise go nuts trying to parse from file structure - name = id.replace(cacheLocation, ""); - if(name.startsWith("/")) { - name = name.substring(1); - } - name = name.replace(".complete", "").replace(".partial", ""); - int index = name.lastIndexOf("."); - name = index == -1 ? name : name.substring(0, index); - String[] details = name.split("/"); - - String title = details[details.length - 1]; - if(index == -1) { - if(details.length > 1) { - String artist = "artist:\"" + details[details.length - 2] + "\""; - String simpleArtist = "artist:\"" + title + "\""; - title = "album:\"" + title + "\""; - if(details[details.length - 1].equals(details[details.length - 2])) { - name = title; - } else { - name = "(" + artist + " AND " + title + ")" + " OR " + simpleArtist; - } - } else { - name = "artist:\"" + title + "\" OR album:\"" + title + "\""; - } - } else { - String artist; - if(details.length > 2) { - artist = "artist:\"" + details[details.length - 3] + "\""; - } else { - artist = "(artist:\"" + details[0] + "\" OR album:\"" + details[0] + "\")"; - } - title = "title:\"" + title.substring(title.indexOf('-') + 1) + "\""; - name = artist + " AND " + title; - } - - return name; - } - - public static String parseOfflineIDSearch(String id) { - MusicDirectory.Entry entry = new MusicDirectory.Entry(); - File file = new File(id); - - if(file.exists()) { - entry.loadMetadata(file); - - if(entry.getArtist() != null) { - String title = file.getName(); - title = title.replace(".complete", "").replace(".partial", ""); - int index = title.lastIndexOf("."); - title = index == -1 ? title : title.substring(0, index); - title = title.substring(title.indexOf('-') + 1); - - String query = "artist:\"" + entry.getArtist() + "\"" + - " AND title:\"" + title + "\""; - - return query; - } else { - return null; - } - } else { - return null; - } - } - - public static String getContentType(HttpEntity entity) { - if (entity == null || entity.getContentType() == null) { - return null; - } - return entity.getContentType().getValue(); - } - - public static int getRemainingTrialDays(Context context) { - SharedPreferences prefs = getPreferences(context); - long installTime = prefs.getLong(Constants.PREFERENCES_KEY_INSTALL_TIME, 0L); - - if (installTime == 0L) { - installTime = System.currentTimeMillis(); - SharedPreferences.Editor editor = prefs.edit(); - editor.putLong(Constants.PREFERENCES_KEY_INSTALL_TIME, installTime); - editor.commit(); - } - - long now = System.currentTimeMillis(); - long millisPerDay = 24L * 60L * 60L * 1000L; - int daysSinceInstall = (int) ((now - installTime) / millisPerDay); - return Math.max(0, Constants.FREE_TRIAL_DAYS - daysSinceInstall); - } - - public static boolean isCastProxy(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_CAST_PROXY, false); - } - - public static boolean isFirstLevelArtist(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_FIRST_LEVEL_ARTIST + getActiveServer(context), true); - } - public static void toggleFirstLevelArtist(Context context) { - SharedPreferences prefs = Util.getPreferences(context); - SharedPreferences.Editor editor = prefs.edit(); - - if(prefs.getBoolean(Constants.PREFERENCES_KEY_FIRST_LEVEL_ARTIST + getActiveServer(context), true)) { - editor.putBoolean(Constants.PREFERENCES_KEY_FIRST_LEVEL_ARTIST + getActiveServer(context), false); - } else { - editor.putBoolean(Constants.PREFERENCES_KEY_FIRST_LEVEL_ARTIST + getActiveServer(context), true); - } - - editor.commit(); - } - - public static boolean shouldStartOnHeadphones(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_START_ON_HEADPHONES, false); - } - - /** - * Get the contents of an InputStream as a byte[]. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - * - * @param input the InputStream to read from - * @return the requested byte array - * @throws NullPointerException if the input is null - * @throws IOException if an I/O error occurs - */ - public static byte[] toByteArray(InputStream input) throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - copy(input, output); - return output.toByteArray(); - } - - public static long copy(InputStream input, OutputStream output) - throws IOException { - byte[] buffer = new byte[1024 * 4]; - long count = 0; - int n; - while (-1 != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - public static void renameFile(File from, File to) throws IOException { - if(!from.renameTo(to)) { - Log.i(TAG, "Failed to rename " + from + " to " + to); - } - } - - public static void close(Closeable closeable) { - try { - if (closeable != null) { - closeable.close(); - } - } catch (Throwable x) { - // Ignored - } - } - - public static boolean delete(File file) { - if (file != null && file.exists()) { - if (!file.delete()) { - Log.w(TAG, "Failed to delete file " + file); - return false; - } - Log.i(TAG, "Deleted file " + file); - } - return true; - } - - public static void toast(Context context, int messageId) { - toast(context, messageId, true); - } - - public static void toast(Context context, int messageId, boolean shortDuration) { - toast(context, context.getString(messageId), shortDuration); - } - - public static void toast(Context context, String message) { - toast(context, message, true); - } - - public static void toast(Context context, String message, boolean shortDuration) { - if (toast == null) { - toast = Toast.makeText(context, message, shortDuration ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG); - toast.setGravity(Gravity.CENTER, 0, 0); - } else { - toast.setText(message); - toast.setDuration(shortDuration ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG); - } - toast.show(); - } - - public static void confirmDialog(Context context, int action, int subject, DialogInterface.OnClickListener onClick) { - Util.confirmDialog(context, context.getResources().getString(action).toLowerCase(), context.getResources().getString(subject), onClick, null); - } - public static void confirmDialog(Context context, int action, int subject, DialogInterface.OnClickListener onClick, DialogInterface.OnClickListener onCancel) { - Util.confirmDialog(context, context.getResources().getString(action).toLowerCase(), context.getResources().getString(subject), onClick, onCancel); - } - public static void confirmDialog(Context context, int action, String subject, DialogInterface.OnClickListener onClick) { - Util.confirmDialog(context, context.getResources().getString(action).toLowerCase(), subject, onClick, null); - } - public static void confirmDialog(Context context, int action, String subject, DialogInterface.OnClickListener onClick, DialogInterface.OnClickListener onCancel) { - Util.confirmDialog(context, context.getResources().getString(action).toLowerCase(), subject, onClick, onCancel); - } - public static void confirmDialog(Context context, String action, String subject, DialogInterface.OnClickListener onClick, DialogInterface.OnClickListener onCancel) { - new AlertDialog.Builder(context) - .setIcon(android.R.drawable.ic_dialog_alert) - .setTitle(R.string.common_confirm) - .setMessage(context.getResources().getString(R.string.common_confirm_message, action, subject)) - .setPositiveButton(R.string.common_ok, onClick) - .setNegativeButton(R.string.common_cancel, onCancel) - .show(); - } - - /** - * Converts a byte-count to a formatted string suitable for display to the user. - * For instance: - *

    - *
  • format(918) returns "918 B".
  • - *
  • format(98765) returns "96 KB".
  • - *
  • format(1238476) returns "1.2 MB".
  • - *
- * This method assumes that 1 KB is 1024 bytes. - * To get a localized string, please use formatLocalizedBytes instead. - * - * @param byteCount The number of bytes. - * @return The formatted string. - */ - public static synchronized String formatBytes(long byteCount) { - - // More than 1 GB? - if (byteCount >= 1024 * 1024 * 1024) { - NumberFormat gigaByteFormat = GIGA_BYTE_FORMAT; - return gigaByteFormat.format((double) byteCount / (1024 * 1024 * 1024)); - } - - // More than 1 MB? - if (byteCount >= 1024 * 1024) { - NumberFormat megaByteFormat = MEGA_BYTE_FORMAT; - return megaByteFormat.format((double) byteCount / (1024 * 1024)); - } - - // More than 1 KB? - if (byteCount >= 1024) { - NumberFormat kiloByteFormat = KILO_BYTE_FORMAT; - return kiloByteFormat.format((double) byteCount / 1024); - } - - return byteCount + " B"; - } - - /** - * Converts a byte-count to a formatted string suitable for display to the user. - * For instance: - *
    - *
  • format(918) returns "918 B".
  • - *
  • format(98765) returns "96 KB".
  • - *
  • format(1238476) returns "1.2 MB".
  • - *
- * This method assumes that 1 KB is 1024 bytes. - * This version of the method returns a localized string. - * - * @param byteCount The number of bytes. - * @return The formatted string. - */ - public static synchronized String formatLocalizedBytes(long byteCount, Context context) { - - // More than 1 GB? - if (byteCount >= 1024 * 1024 * 1024) { - if (GIGA_BYTE_LOCALIZED_FORMAT == null) { - GIGA_BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_gigabyte)); - } - - return GIGA_BYTE_LOCALIZED_FORMAT.format((double) byteCount / (1024 * 1024 * 1024)); - } - - // More than 1 MB? - if (byteCount >= 1024 * 1024) { - if (MEGA_BYTE_LOCALIZED_FORMAT == null) { - MEGA_BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_megabyte)); - } - - return MEGA_BYTE_LOCALIZED_FORMAT.format((double) byteCount / (1024 * 1024)); - } - - // More than 1 KB? - if (byteCount >= 1024) { - if (KILO_BYTE_LOCALIZED_FORMAT == null) { - KILO_BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_kilobyte)); - } - - return KILO_BYTE_LOCALIZED_FORMAT.format((double) byteCount / 1024); - } - - if (BYTE_LOCALIZED_FORMAT == null) { - BYTE_LOCALIZED_FORMAT = new DecimalFormat(context.getResources().getString(R.string.util_bytes_format_byte)); - } - - return BYTE_LOCALIZED_FORMAT.format((double) byteCount); - } - - public static String formatDuration(Integer seconds) { - if (seconds == null) { - return null; - } - - int hours = seconds / 3600; - int minutes = (seconds / 60) % 60; - int secs = seconds % 60; - - StringBuilder builder = new StringBuilder(7); - if(hours > 0) { - builder.append(hours).append(":"); - if(minutes < 10) { - builder.append("0"); - } - } - builder.append(minutes).append(":"); - if (secs < 10) { - builder.append("0"); - } - builder.append(secs); - return builder.toString(); - } - - public static String formatDate(Date date) { - if(date == null) { - return "Never"; - } else { - if(date.getYear() != CURRENT_YEAR) { - return DATE_FORMAT_LONG.format(date); - } else { - return DATE_FORMAT_SHORT.format(date); - } - } - } - - public static boolean equals(Object object1, Object object2) { - if (object1 == object2) { - return true; - } - if (object1 == null || object2 == null) { - return false; - } - return object1.equals(object2); - - } - - /** - * Encodes the given string by using the hexadecimal representation of its UTF-8 bytes. - * - * @param s The string to encode. - * @return The encoded string. - */ - public static String utf8HexEncode(String s) { - if (s == null) { - return null; - } - byte[] utf8; - try { - utf8 = s.getBytes(Constants.UTF_8); - } catch (UnsupportedEncodingException x) { - throw new RuntimeException(x); - } - return hexEncode(utf8); - } - - /** - * Converts an array of bytes into an array of characters representing the hexadecimal values of each byte in order. - * The returned array will be double the length of the passed array, as it takes two characters to represent any - * given byte. - * - * @param data Bytes to convert to hexadecimal characters. - * @return A string containing hexadecimal characters. - */ - public static String hexEncode(byte[] data) { - int length = data.length; - char[] out = new char[length << 1]; - // two characters form the hex value. - for (int i = 0, j = 0; i < length; i++) { - out[j++] = HEX_DIGITS[(0xF0 & data[i]) >>> 4]; - out[j++] = HEX_DIGITS[0x0F & data[i]]; - } - return new String(out); - } - - /** - * Calculates the MD5 digest and returns the value as a 32 character hex string. - * - * @param s Data to digest. - * @return MD5 digest as a hex string. - */ - public static String md5Hex(String s) { - if (s == null) { - return null; - } - - try { - MessageDigest md5 = MessageDigest.getInstance("MD5"); - return hexEncode(md5.digest(s.getBytes(Constants.UTF_8))); - } catch (Exception x) { - throw new RuntimeException(x.getMessage(), x); - } - } - - public static boolean isNullOrWhiteSpace(String string) { - return string == null || "".equals(string) || "".equals(string.trim()); - } - - public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { - // Raw height and width of image - final int height = options.outHeight; - final int width = options.outWidth; - int inSampleSize = 1; - - if (height > reqHeight || width > reqWidth) { - - // Calculate ratios of height and width to requested height and - // width - final int heightRatio = Math.round((float) height / (float) reqHeight); - final int widthRatio = Math.round((float) width / (float) reqWidth); - - // Choose the smallest ratio as inSampleSize value, this will - // guarantee - // a final image with both dimensions larger than or equal to the - // requested height and width. - inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; - } - - return inSampleSize; - } - - public static int getScaledHeight(double height, double width, int newWidth) { - // Try to keep correct aspect ratio of the original image, do not force a square - double aspectRatio = height / width; - - // Assume the size given refers to the width of the image, so calculate the new height using - // the previously determined aspect ratio - return (int) Math.round(newWidth * aspectRatio); - } - - public static int getScaledHeight(Bitmap bitmap, int width) { - return Util.getScaledHeight((double) bitmap.getHeight(), (double) bitmap.getWidth(), width); - } - - public static int getStringDistance(CharSequence s, CharSequence t) { - if (s == null || t == null) { - throw new IllegalArgumentException("Strings must not be null"); - } - - if(t.toString().toLowerCase().indexOf(s.toString().toLowerCase()) != -1) { - return 1; - } - - int n = s.length(); - int m = t.length(); - - if (n == 0) { - return m; - } else if (m == 0) { - return n; - } - - if (n > m) { - final CharSequence tmp = s; - s = t; - t = tmp; - n = m; - m = t.length(); - } - - int p[] = new int[n + 1]; - int d[] = new int[n + 1]; - int _d[]; - - int i; - int j; - char t_j; - int cost; - - for (i = 0; i <= n; i++) { - p[i] = i; - } - - for (j = 1; j <= m; j++) { - t_j = t.charAt(j - 1); - d[0] = j; - - for (i = 1; i <= n; i++) { - cost = s.charAt(i - 1) == t_j ? 0 : 1; - d[i] = Math.min(Math.min(d[i - 1] + 1, p[i] + 1), p[i - 1] + cost); - } - - _d = p; - p = d; - d = _d; - } - - return p[n]; - } - - public static boolean isNetworkConnected(Context context) { - return isNetworkConnected(context, false); - } - public static boolean isNetworkConnected(Context context, boolean streaming) { - ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = manager.getActiveNetworkInfo(); - boolean connected = networkInfo != null && networkInfo.isConnected(); - - if(streaming) { - boolean wifiConnected = connected && networkInfo.getType() == ConnectivityManager.TYPE_WIFI; - boolean wifiRequired = isWifiRequiredForDownload(context); - - return connected && (!wifiRequired || wifiConnected); - } else { - return connected; - } - } - public static boolean isWifiConnected(Context context) { - ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = manager.getActiveNetworkInfo(); - boolean connected = networkInfo != null && networkInfo.isConnected(); - return connected && (networkInfo.getType() == ConnectivityManager.TYPE_WIFI); - } - public static String getSSID(Context context) { - if (isWifiConnected(context)) { - WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - if (wifiManager.getConnectionInfo() != null && wifiManager.getConnectionInfo().getSSID() != null) { - return wifiManager.getConnectionInfo().getSSID().replace("\"", ""); - } - return null; - } - return null; - } - - public static boolean isExternalStoragePresent() { - return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); - } - - private static boolean isWifiRequiredForDownload(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_WIFI_REQUIRED_FOR_DOWNLOAD, false); - } - - public static void info(Context context, int titleId, int messageId) { - info(context, titleId, messageId, true); - } - public static void info(Context context, int titleId, String message) { - info(context, titleId, message, true); - } - public static void info(Context context, String title, String message) { - info(context, title, message, true); - } - public static void info(Context context, int titleId, int messageId, boolean linkify) { - showDialog(context, android.R.drawable.ic_dialog_info, titleId, messageId, linkify); - } - public static void info(Context context, int titleId, String message, boolean linkify) { - showDialog(context, android.R.drawable.ic_dialog_info, titleId, message, linkify); - } - public static void info(Context context, String title, String message, boolean linkify) { - showDialog(context, android.R.drawable.ic_dialog_info, title, message, linkify); - } - - private static void showDialog(Context context, int icon, int titleId, int messageId) { - showDialog(context, icon, titleId, messageId, true); - } - private static void showDialog(Context context, int icon, int titleId, String message) { - showDialog(context, icon, titleId, message, true); - } - private static void showDialog(Context context, int icon, String title, String message) { - showDialog(context, icon, title, message, true); - } - private static void showDialog(Context context, int icon, int titleId, int messageId, boolean linkify) { - showDialog(context, icon, context.getResources().getString(titleId), context.getResources().getString(messageId), linkify); - } - private static void showDialog(Context context, int icon, int titleId, String message, boolean linkify) { - showDialog(context, icon, context.getResources().getString(titleId), message, linkify); - } - private static void showDialog(Context context, int icon, String title, String message, boolean linkify) { - SpannableString ss = new SpannableString(message); - if(linkify) { - Linkify.addLinks(ss, Linkify.ALL); - } - - AlertDialog dialog = new AlertDialog.Builder(context) - .setIcon(icon) - .setTitle(title) - .setMessage(ss) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int i) { - dialog.dismiss(); - } - }) - .show(); - - ((TextView)dialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); - } - public static void showHTMLDialog(Context context, int title, int message) { - showHTMLDialog(context, title, context.getResources().getString(message)); - } - public static void showHTMLDialog(Context context, int title, String message) { - AlertDialog dialog = new AlertDialog.Builder(context) - .setIcon(android.R.drawable.ic_dialog_info) - .setTitle(title) - .setMessage(Html.fromHtml(message)) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int i) { - dialog.dismiss(); - } - }) - .show(); - - ((TextView)dialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); - } - - public static void sleepQuietly(long millis) { - try { - Thread.sleep(millis); - } catch (InterruptedException x) { - Log.w(TAG, "Interrupted from sleep.", x); - } - } - - public static void startActivityWithoutTransition(Activity currentActivity, Class newActivitiy) { - startActivityWithoutTransition(currentActivity, new Intent(currentActivity, newActivitiy)); - } - - public static void startActivityWithoutTransition(Activity currentActivity, Intent intent) { - currentActivity.startActivity(intent); - disablePendingTransition(currentActivity); - } - - public static void disablePendingTransition(Activity activity) { - - // Activity.overridePendingTransition() was introduced in Android 2.0. Use reflection to maintain - // compatibility with 1.5. - try { - Method method = Activity.class.getMethod("overridePendingTransition", int.class, int.class); - method.invoke(activity, 0, 0); - } catch (Throwable x) { - // Ignored - } - } - - public static Drawable createDrawableFromBitmap(Context context, Bitmap bitmap) { - // BitmapDrawable(Resources, Bitmap) was introduced in Android 1.6. Use reflection to maintain - // compatibility with 1.5. - try { - Constructor constructor = BitmapDrawable.class.getConstructor(Resources.class, Bitmap.class); - return constructor.newInstance(context.getResources(), bitmap); - } catch (Throwable x) { - return new BitmapDrawable(bitmap); - } - } - - public static int getAttribute(Context context, int attr) { - int res; - int[] attrs = new int[] {attr}; - TypedArray typedArray = context.obtainStyledAttributes(attrs); - res = typedArray.getResourceId(0, 0); - typedArray.recycle(); - return res; - } - - public static void registerMediaButtonEventReceiver(Context context) { - - // Only do it if enabled in the settings. - SharedPreferences prefs = getPreferences(context); - boolean enabled = prefs.getBoolean(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true); - - if (enabled) { - - // AudioManager.registerMediaButtonEventReceiver() was introduced in Android 2.2. - // Use reflection to maintain compatibility with 1.5. - try { - AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - ComponentName componentName = new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName()); - Method method = AudioManager.class.getMethod("registerMediaButtonEventReceiver", ComponentName.class); - method.invoke(audioManager, componentName); - } catch (Throwable x) { - // Ignored. - } - } - } - - public static void unregisterMediaButtonEventReceiver(Context context) { - // AudioManager.unregisterMediaButtonEventReceiver() was introduced in Android 2.2. - // Use reflection to maintain compatibility with 1.5. - try { - AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - ComponentName componentName = new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName()); - Method method = AudioManager.class.getMethod("unregisterMediaButtonEventReceiver", ComponentName.class); - method.invoke(audioManager, componentName); - } catch (Throwable x) { - // Ignored. - } - } - - @TargetApi(8) - public static void requestAudioFocus(final Context context) { - if (Build.VERSION.SDK_INT >= 8 && focusListener == null) { - final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - audioManager.requestAudioFocus(focusListener = new OnAudioFocusChangeListener() { - public void onAudioFocusChange(int focusChange) { - DownloadService downloadService = (DownloadService)context; - if((focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) && !downloadService.isRemoteEnabled()) { - if(downloadService.getPlayerState() == PlayerState.STARTED) { - Log.i(TAG, "Temporary loss of focus"); - SharedPreferences prefs = getPreferences(context); - int lossPref = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_TEMP_LOSS, "1")); - if(lossPref == 2 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK)) { - lowerFocus = true; - downloadService.setVolume(0.1f); - } else if(lossPref == 0 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT)) { - pauseFocus = true; - downloadService.pause(true); - } - } - } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { - if(pauseFocus) { - pauseFocus = false; - downloadService.start(); - } else if(lowerFocus) { - lowerFocus = false; - downloadService.setVolume(1.0f); - } - } else if(focusChange == AudioManager.AUDIOFOCUS_LOSS && !downloadService.isRemoteEnabled()) { - Log.i(TAG, "Permanently lost focus"); - focusListener = null; - downloadService.pause(); - audioManager.abandonAudioFocus(this); - } - } - }, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); - } - } - - public static void abandonAudioFocus(Context context) { - if(focusListener != null) { - final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - audioManager.abandonAudioFocus(focusListener); - focusListener = null; - } - } - - /** - *

Broadcasts the given song info as the new song being played.

- */ - public static void broadcastNewTrackInfo(Context context, MusicDirectory.Entry song) { - DownloadService downloadService = (DownloadService)context; - Intent intent = new Intent(EVENT_META_CHANGED); - Intent avrcpIntent = new Intent(AVRCP_METADATA_CHANGED); - - if (song != null) { - intent.putExtra("title", song.getTitle()); - intent.putExtra("artist", song.getArtist()); - intent.putExtra("album", song.getAlbum()); - - File albumArtFile = FileUtil.getAlbumArtFile(context, song); - intent.putExtra("coverart", albumArtFile.getAbsolutePath()); - avrcpIntent.putExtra("playing", true); - } else { - intent.putExtra("title", ""); - intent.putExtra("artist", ""); - intent.putExtra("album", ""); - intent.putExtra("coverart", ""); - avrcpIntent.putExtra("playing", false); - } - addTrackInfo(context, song, avrcpIntent); - - context.sendBroadcast(intent); - context.sendBroadcast(avrcpIntent); - } - - /** - *

Broadcasts the given player state as the one being set.

- */ - public static void broadcastPlaybackStatusChange(Context context, MusicDirectory.Entry song, PlayerState state) { - Intent intent = new Intent(EVENT_PLAYSTATE_CHANGED); - Intent avrcpIntent = new Intent(AVRCP_PLAYSTATE_CHANGED); - - switch (state) { - case STARTED: - intent.putExtra("state", "play"); - avrcpIntent.putExtra("playing", true); - break; - case STOPPED: - intent.putExtra("state", "stop"); - avrcpIntent.putExtra("playing", false); - break; - case PAUSED: - intent.putExtra("state", "pause"); - avrcpIntent.putExtra("playing", false); - break; - case PREPARED: - // Only send quick pause event for samsung devices, causes issues for others - if(Build.MANUFACTURER.toLowerCase().indexOf("samsung") != -1) { - avrcpIntent.putExtra("playing", false); - } else { - return; // Don't broadcast anything - } - break; - case COMPLETED: - intent.putExtra("state", "complete"); - avrcpIntent.putExtra("playing", false); - break; - default: - return; // No need to broadcast. - } - addTrackInfo(context, song, avrcpIntent); - - if(state != PlayerState.PREPARED) { - context.sendBroadcast(intent); - } - context.sendBroadcast(avrcpIntent); - } - - private static void addTrackInfo(Context context, MusicDirectory.Entry song, Intent intent) { - if (song != null) { - DownloadService downloadService = (DownloadService)context; - File albumArtFile = FileUtil.getAlbumArtFile(context, song); - - intent.putExtra("track", song.getTitle()); - intent.putExtra("artist", song.getArtist()); - intent.putExtra("album", song.getAlbum()); - intent.putExtra("ListSize", (long) downloadService.getSongs().size()); - intent.putExtra("id", (long) downloadService.getCurrentPlayingIndex() + 1); - intent.putExtra("duration", (long) downloadService.getPlayerDuration()); - intent.putExtra("position", (long) downloadService.getPlayerPosition()); - intent.putExtra("coverart", albumArtFile.getAbsolutePath()); - } else { - intent.putExtra("track", ""); - intent.putExtra("artist", ""); - intent.putExtra("album", ""); - intent.putExtra("ListSize", (long) 0); - intent.putExtra("id", (long) 0); - intent.putExtra("duration", (long) 0); - intent.putExtra("position", (long) 0); - intent.putExtra("coverart", ""); - } - } - - public static WifiManager.WifiLock createWifiLock(Context context, String tag) { - WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - int lockType = WifiManager.WIFI_MODE_FULL; - if (Build.VERSION.SDK_INT >= 12) { - lockType = 3; - } - return wm.createWifiLock(lockType, tag); - } -} diff --git a/src/github/daneren2005/dsub/util/compat/CastCompat.java b/src/github/daneren2005/dsub/util/compat/CastCompat.java deleted file mode 100644 index ab64bca9..00000000 --- a/src/github/daneren2005/dsub/util/compat/CastCompat.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.util.compat; - -import android.support.v7.media.MediaRouter; - -import com.google.android.gms.cast.CastDevice; -import com.google.android.gms.cast.CastMediaControlIntent; - -import github.daneren2005.dsub.service.ChromeCastController; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.RemoteController; - -/** - * Created by owner on 2/9/14. - */ -public final class CastCompat { - public static final String APPLICATION_ID = "5F85EBEB"; - - static { - try { - Class.forName("com.google.android.gms.cast.CastDevice"); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - public static void checkAvailable() throws Throwable { - // Calling here forces class initialization. - } - - public static RemoteController getController(DownloadService downloadService, MediaRouter.RouteInfo info) { - CastDevice device = CastDevice.getFromBundle(info.getExtras()); - if(device != null) { - return new ChromeCastController(downloadService, device); - } else { - return null; - } - } - - public static String getCastControlCategory() { - return CastMediaControlIntent.categoryForCast(APPLICATION_ID); - } -} diff --git a/src/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java b/src/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java deleted file mode 100644 index 320092e9..00000000 --- a/src/github/daneren2005/dsub/util/compat/RemoteControlClientBase.java +++ /dev/null @@ -1,43 +0,0 @@ -package github.daneren2005.dsub.util.compat; - -import github.daneren2005.dsub.domain.MusicDirectory.Entry; -import android.content.ComponentName; -import android.content.Context; -import android.support.v7.media.MediaRouter; -import android.util.Log; - -public class RemoteControlClientBase extends RemoteControlClientHelper { - - private static final String TAG = RemoteControlClientBase.class.getSimpleName(); - - @Override - public void register(Context context, ComponentName mediaButtonReceiverComponent) { - - } - - @Override - public void unregister(Context context) { - - } - - @Override - public void setPlaybackState(int state) { - - } - - @Override - public void updateMetadata(Context context, Entry currentSong) { - - } - - @Override - public void registerRoute(MediaRouter router) { - - } - - @Override - public void unregisterRoute(MediaRouter router) { - - } - -} diff --git a/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java b/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java deleted file mode 100644 index 93075a28..00000000 --- a/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java +++ /dev/null @@ -1,32 +0,0 @@ -package github.daneren2005.dsub.util.compat; - -import github.daneren2005.dsub.domain.MusicDirectory; -import android.content.ComponentName; -import android.content.Context; -import android.support.v7.media.MediaRouter; -import android.os.Build; - -public abstract class RemoteControlClientHelper { - - public static RemoteControlClientHelper createInstance() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - return new RemoteControlClientBase(); - } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - return new RemoteControlClientJB(); - } else { - return new RemoteControlClientICS(); - } - } - - protected RemoteControlClientHelper() { - // Avoid instantiation - } - - public abstract void register(final Context context, final ComponentName mediaButtonReceiverComponent); - public abstract void unregister(final Context context); - public abstract void setPlaybackState(final int state); - public abstract void updateMetadata(final Context context, final MusicDirectory.Entry currentSong); - public abstract void registerRoute(MediaRouter router); - public abstract void unregisterRoute(MediaRouter router); - -} diff --git a/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java b/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java deleted file mode 100644 index 50283da6..00000000 --- a/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java +++ /dev/null @@ -1,104 +0,0 @@ -package github.daneren2005.dsub.util.compat; - -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.util.ImageLoader; -import android.annotation.TargetApi; -import android.app.PendingIntent; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.media.AudioManager; -import android.media.MediaMetadataRetriever; -import android.media.RemoteControlClient; -import android.support.v7.media.MediaRouter; - -import github.daneren2005.dsub.activity.SubsonicActivity; - -@TargetApi(14) -public class RemoteControlClientICS extends RemoteControlClientHelper { - private static String TAG = RemoteControlClientICS.class.getSimpleName(); - - protected RemoteControlClient mRemoteControl; - protected ImageLoader imageLoader; - protected DownloadService downloadService; - - public void register(final Context context, final ComponentName mediaButtonReceiverComponent) { - downloadService = (DownloadService) context; - AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - - // build the PendingIntent for the remote control client - Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); - mediaButtonIntent.setComponent(mediaButtonReceiverComponent); - PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(context.getApplicationContext(), 0, mediaButtonIntent, 0); - - // create and register the remote control client - mRemoteControl = new RemoteControlClient(mediaPendingIntent); - audioManager.registerRemoteControlClient(mRemoteControl); - - mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED); - mRemoteControl.setTransportControlFlags(getTransportFlags()); - imageLoader = SubsonicActivity.getStaticImageLoader(context); - } - - public void unregister(final Context context) { - if (mRemoteControl != null) { - AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - audioManager.unregisterRemoteControlClient(mRemoteControl); - } - } - - public void setPlaybackState(final int state) { - mRemoteControl.setPlaybackState(state); - } - - public void updateMetadata(final Context context, final MusicDirectory.Entry currentSong) { - if(imageLoader == null) { - imageLoader = SubsonicActivity.getStaticImageLoader(context); - } - - // Update the remote controls - RemoteControlClient.MetadataEditor editor = mRemoteControl.editMetadata(true); - updateMetadata(currentSong, editor); - editor.apply(); - if (currentSong == null || imageLoader == null) { - mRemoteControl.editMetadata(true) - .putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, null) - .apply(); - } else { - imageLoader.loadImage(context, mRemoteControl, currentSong); - } - } - - @Override - public void registerRoute(MediaRouter router) { - router.addRemoteControlClient(mRemoteControl); - } - - @Override - public void unregisterRoute(MediaRouter router) { - router.removeRemoteControlClient(mRemoteControl); - } - - protected void updateMetadata(final MusicDirectory.Entry currentSong, final RemoteControlClient.MetadataEditor editor) { - editor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, (currentSong == null) ? null : currentSong.getArtist()) - .putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, (currentSong == null) ? null : currentSong.getAlbum()) - .putString(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, (currentSong == null) ? null : currentSong.getArtist()) - .putString(MediaMetadataRetriever.METADATA_KEY_TITLE, (currentSong) == null ? null : currentSong.getTitle()) - .putString(MediaMetadataRetriever.METADATA_KEY_GENRE, (currentSong) == null ? null : currentSong.getGenre()) - .putLong(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, (currentSong == null) ? - 0 : ((currentSong.getTrack() == null) ? 0 : currentSong.getTrack())) - .putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, (currentSong == null) ? - 0 : ((currentSong.getDuration() == null) ? 0 : (currentSong.getDuration() * 1000))); - } - - protected int getTransportFlags() { - return RemoteControlClient.FLAG_KEY_MEDIA_PLAY | - RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | - RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE | - RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | - RemoteControlClient.FLAG_KEY_MEDIA_NEXT | - RemoteControlClient.FLAG_KEY_MEDIA_STOP; - } - -} diff --git a/src/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java b/src/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java deleted file mode 100644 index c27df2ba..00000000 --- a/src/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java +++ /dev/null @@ -1,58 +0,0 @@ -package github.daneren2005.dsub.util.compat; - -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ImageLoader; -import android.annotation.TargetApi; -import android.app.PendingIntent; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.media.AudioManager; -import android.media.MediaMetadataRetriever; -import android.media.RemoteControlClient; -import github.daneren2005.dsub.activity.SubsonicActivity; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.util.SilentBackgroundTask; - -@TargetApi(18) -public class RemoteControlClientJB extends RemoteControlClientICS { - @Override - public void register(final Context context, final ComponentName mediaButtonReceiverComponent) { - super.register(context, mediaButtonReceiverComponent); - - mRemoteControl.setOnGetPlaybackPositionListener(new RemoteControlClient.OnGetPlaybackPositionListener() { - @Override - public long onGetPlaybackPosition() { - return downloadService.getPlayerPosition(); - } - }); - mRemoteControl.setPlaybackPositionUpdateListener(new RemoteControlClient.OnPlaybackPositionUpdateListener() { - @Override - public void onPlaybackPositionUpdate(final long newPosition) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - downloadService.seekTo((int) newPosition); - return null; - } - }.execute(); - setPlaybackState(RemoteControlClient.PLAYSTATE_PLAYING); - } - }); - } - - @Override - public void setPlaybackState(final int state) { - long position = -1; - if(state == RemoteControlClient.PLAYSTATE_PLAYING || state == RemoteControlClient.PLAYSTATE_PAUSED) { - position = downloadService.getPlayerPosition(); - } - mRemoteControl.setPlaybackState(state, position, 1.0f); - } - - @Override - protected int getTransportFlags() { - return super.getTransportFlags() | RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE; - } - -} diff --git a/src/github/daneren2005/dsub/util/tags/Bastp.java b/src/github/daneren2005/dsub/util/tags/Bastp.java deleted file mode 100644 index aa0a2e25..00000000 --- a/src/github/daneren2005/dsub/util/tags/Bastp.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2013 Adrian Ulrich - * - * This program 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 - * (at your option) any later version. - * - * This program 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 this program. If not, see . - */ - - -package github.daneren2005.dsub.util.tags; - -import java.io.RandomAccessFile; -import java.io.IOException; -import java.util.HashMap; - - -public class Bastp { - - public Bastp() { - } - - public HashMap getTags(String fname) { - HashMap tags = new HashMap(); - try { - RandomAccessFile ra = new RandomAccessFile(fname, "r"); - tags = getTags(ra); - ra.close(); - } - catch(Exception e) { - /* we dont' care much: SOMETHING went wrong. d'oh! */ - } - - return tags; - } - - public HashMap getTags(RandomAccessFile s) { - HashMap tags = new HashMap(); - byte[] file_ff = new byte[4]; - - try { - s.read(file_ff); - String magic = new String(file_ff); - if(magic.equals("fLaC")) { - tags = (new FlacFile()).getTags(s); - } - else if(magic.equals("OggS")) { - tags = (new OggFile()).getTags(s); - } - else if(file_ff[0] == -1 && file_ff[1] == -5) { /* aka 0xfffb in real languages */ - tags = (new LameHeader()).getTags(s); - } - else if(magic.substring(0,3).equals("ID3")) { - tags = (new ID3v2File()).getTags(s); - if(tags.containsKey("_hdrlen")) { - Long hlen = Long.parseLong( tags.get("_hdrlen").toString(), 10 ); - HashMap lameInfo = (new LameHeader()).parseLameHeader(s, hlen); - /* add gain tags if not already present */ - inheritTag("REPLAYGAIN_TRACK_GAIN", lameInfo, tags); - inheritTag("REPLAYGAIN_ALBUM_GAIN", lameInfo, tags); - } - } - tags.put("_magic", magic); - } - catch (IOException e) { - } - return tags; - } - - private void inheritTag(String key, HashMap from, HashMap to) { - if(!to.containsKey(key) && from.containsKey(key)) { - to.put(key, from.get(key)); - } - } - -} - diff --git a/src/github/daneren2005/dsub/util/tags/BastpUtil.java b/src/github/daneren2005/dsub/util/tags/BastpUtil.java deleted file mode 100644 index 7ff517fd..00000000 --- a/src/github/daneren2005/dsub/util/tags/BastpUtil.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2013 Adrian Ulrich - * - * This program 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 - * (at your option) any later version. - * - * This program 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 this program. If not, see . - */ - -package github.daneren2005.dsub.util.tags; - -import android.support.v4.util.LruCache; -import java.util.HashMap; -import java.util.Vector; - -public final class BastpUtil { - private static final RGLruCache rgCache = new RGLruCache(16); - - /** Returns the ReplayGain values of 'path' as - */ - public static float[] getReplayGainValues(String path) { - float[] cached = rgCache.get(path); - - if(cached == null) { - cached = getReplayGainValuesFromFile(path); - rgCache.put(path, cached); - } - return cached; - } - - - - /** Parse given file and return track,album replay gain values - */ - private static float[] getReplayGainValuesFromFile(String path) { - String[] keys = { "REPLAYGAIN_TRACK_GAIN", "REPLAYGAIN_ALBUM_GAIN" }; - float[] adjust= { 0f , 0f }; - HashMap tags = (new Bastp()).getTags(path); - - for (int i=0; i { - public RGLruCache(int size) { - super(size); - } - } - -} - diff --git a/src/github/daneren2005/dsub/util/tags/Common.java b/src/github/daneren2005/dsub/util/tags/Common.java deleted file mode 100644 index 51344d90..00000000 --- a/src/github/daneren2005/dsub/util/tags/Common.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2013 Adrian Ulrich - * - * This program 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 - * (at your option) any later version. - * - * This program 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 this program. If not, see . - */ - - -package github.daneren2005.dsub.util.tags; - -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.HashMap; -import java.util.Vector; - -public class Common { - private static final long MAX_PKT_SIZE = 524288; - - public void xdie(String reason) throws IOException { - throw new IOException(reason); - } - - /* - ** Returns a 32bit int from given byte offset in LE - */ - public int b2le32(byte[] b, int off) { - int r = 0; - for(int i=0; i<4; i++) { - r |= ( b2u(b[off+i]) << (8*i) ); - } - return r; - } - - public int b2be32(byte[] b, int off) { - return swap32(b2le32(b, off)); - } - - public int swap32(int i) { - return((i&0xff)<<24)+((i&0xff00)<<8)+((i&0xff0000)>>8)+((i>>24)&0xff); - } - - /* - ** convert 'byte' value into unsigned int - */ - public int b2u(byte x) { - return (x & 0xFF); - } - - /* - ** Printout debug message to STDOUT - */ - public void debug(String s) { - System.out.println("DBUG "+s); - } - - public HashMap parse_vorbis_comment(RandomAccessFile s, long offset, long payload_len) throws IOException { - HashMap tags = new HashMap(); - int comments = 0; // number of found comments - int xoff = 0; // offset within 'scratch' - int can_read = (int)(payload_len > MAX_PKT_SIZE ? MAX_PKT_SIZE : payload_len); - byte[] scratch = new byte[can_read]; - - // seek to given position and slurp in the payload - s.seek(offset); - s.read(scratch); - - // skip vendor string in format: [LEN][VENDOR_STRING] - xoff += 4 + b2le32(scratch, xoff); // 4 = LEN = 32bit int - comments = b2le32(scratch, xoff); - xoff += 4; - - // debug("comments count = "+comments); - for(int i=0; i scratch.length) - xdie("string out of bounds"); - - String tag_raw = new String(scratch, xoff-clen, clen); - String[] tag_vec = tag_raw.split("=",2); - String tag_key = tag_vec[0].toUpperCase(); - - addTagEntry(tags, tag_key, tag_vec[1]); - } - return tags; - } - - public void addTagEntry(HashMap tags, String key, String value) { - if(tags.containsKey(key)) { - ((Vector)tags.get(key)).add(value); // just add to existing vector - } - else { - Vector vx = new Vector(); - vx.add(value); - tags.put(key, vx); - } - } - -} diff --git a/src/github/daneren2005/dsub/util/tags/FlacFile.java b/src/github/daneren2005/dsub/util/tags/FlacFile.java deleted file mode 100644 index de3584d1..00000000 --- a/src/github/daneren2005/dsub/util/tags/FlacFile.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2013 Adrian Ulrich - * - * This program 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 - * (at your option) any later version. - * - * This program 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 this program. If not, see . - */ - -package github.daneren2005.dsub.util.tags; - -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.HashMap; -import java.util.Enumeration; - - -public class FlacFile extends Common { - private static final int FLAC_TYPE_COMMENT = 4; // ID of 'VorbisComment's - - public FlacFile() { - } - - public HashMap getTags(RandomAccessFile s) throws IOException { - int xoff = 4; // skip file magic - int retry = 64; - int r[]; - HashMap tags = new HashMap(); - - for(; retry > 0; retry--) { - r = parse_metadata_block(s, xoff); - - if(r[2] == FLAC_TYPE_COMMENT) { - tags = parse_vorbis_comment(s, xoff+r[0], r[1]); - break; - } - - if(r[3] != 0) - break; // eof reached - - // else: calculate next offset - xoff += r[0] + r[1]; - } - return tags; - } - - /* Parses the metadata block at 'offset' and returns - ** [header_size, payload_size, type, stop_after] - */ - private int[] parse_metadata_block(RandomAccessFile s, long offset) throws IOException { - int[] result = new int[4]; - byte[] mb_head = new byte[4]; - int stop_after = 0; - int block_type = 0; - int block_size = 0; - - s.seek(offset); - - if( s.read(mb_head) != 4 ) - xdie("failed to read metadata block header"); - - block_size = b2be32(mb_head,0); // read whole header as 32 big endian - block_type = (block_size >> 24) & 127; // BIT 1-7 are the type - stop_after = (((block_size >> 24) & 128) > 0 ? 1 : 0 ); // BIT 0 indicates the last-block flag - block_size = (block_size & 0x00FFFFFF); // byte 1-7 are the size - - // debug("size="+block_size+", type="+block_type+", is_last="+stop_after); - - result[0] = 4; // hardcoded - only returned to be consistent with OGG parser - result[1] = block_size; - result[2] = block_type; - result[3] = stop_after; - - return result; - } - -} diff --git a/src/github/daneren2005/dsub/util/tags/ID3v2File.java b/src/github/daneren2005/dsub/util/tags/ID3v2File.java deleted file mode 100644 index ea61f36c..00000000 --- a/src/github/daneren2005/dsub/util/tags/ID3v2File.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2013 Adrian Ulrich - * - * This program 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 - * (at your option) any later version. - * - * This program 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 this program. If not, see . - */ - -package github.daneren2005.dsub.util.tags; - -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Locale; - - -public class ID3v2File extends Common { - private static int ID3_ENC_LATIN = 0x00; - private static int ID3_ENC_UTF16LE = 0x01; - private static int ID3_ENC_UTF16BE = 0x02; - private static int ID3_ENC_UTF8 = 0x03; - - public ID3v2File() { - } - - public HashMap getTags(RandomAccessFile s) throws IOException { - HashMap tags = new HashMap(); - - final int v2hdr_len = 10; - byte[] v2hdr = new byte[v2hdr_len]; - - // read the whole 10 byte header into memory - s.seek(0); - s.read(v2hdr); - - int id3v = ((b2be32(v2hdr,0))) & 0xFF; // swapped ID3\04 -> ver. ist the first byte - int v3len = ((b2be32(v2hdr,6))); // total size EXCLUDING the this 10 byte header - v3len = ((v3len & 0x7f000000) >> 3) | // for some funky reason, this is encoded as 7*4 bits - ((v3len & 0x007f0000) >> 2) | - ((v3len & 0x00007f00) >> 1) | - ((v3len & 0x0000007f) >> 0) ; - - // debug(">> tag version ID3v2."+id3v); - // debug(">> LEN= "+v3len+" // "+v3len); - - // we should already be at the first frame - // so we can start the parsing right now - tags = parse_v3_frames(s, v3len); - tags.put("_hdrlen", v3len+v2hdr_len); - return tags; - } - - /* Parses all ID3v2 frames at the current position up until payload_len - ** bytes were read - */ - public HashMap parse_v3_frames(RandomAccessFile s, long payload_len) throws IOException { - HashMap tags = new HashMap(); - byte[] frame = new byte[10]; // a frame header is always 10 bytes - long bread = 0; // total amount of read bytes - - while(bread < payload_len) { - bread += s.read(frame); - String framename = new String(frame, 0, 4); - int slen = b2be32(frame, 4); - - /* Abort on silly sizes */ - if(slen < 1 || slen > 524288) - break; - - byte[] xpl = new byte[slen]; - bread += s.read(xpl); - - if(framename.substring(0,1).equals("T")) { - String[] nmzInfo = normalizeTaginfo(framename, xpl); - - for(int i = 0; i < nmzInfo.length; i += 2) { - String oggKey = nmzInfo[i]; - String decPld = nmzInfo[i + 1]; - - if (oggKey.length() > 0 && !tags.containsKey(oggKey)) { - addTagEntry(tags, oggKey, decPld); - } - } - } - else if(framename.equals("RVA2")) { - // - } - - } - return tags; - } - - /* Converts ID3v2 sillyframes to OggNames */ - private String[] normalizeTaginfo(String k, byte[] v) { - String[] rv = new String[] {"",""}; - HashMap lu = new HashMap(); - lu.put("TIT2", "TITLE"); - lu.put("TALB", "ALBUM"); - lu.put("TPE1", "ARTIST"); - - if(lu.containsKey(k)) { - /* A normal, known key: translate into Ogg-Frame name */ - rv[0] = (String)lu.get(k); - rv[1] = getDecodedString(v); - } - else if(k.equals("TXXX")) { - /* A freestyle field, ieks! */ - String txData[] = getDecodedString(v).split(Character.toString('\0'), 2); - /* Check if we got replaygain info in key\0value style */ - if(txData.length == 2) { - if(txData[0].matches("^(?i)REPLAYGAIN_(ALBUM|TRACK)_GAIN$")) { - rv[0] = txData[0].toUpperCase(); /* some tagwriters use lowercase for this */ - rv[1] = txData[1]; - } else { - // Check for replaygain tags just thrown randomly in field - int nextStartIndex = 1; - int startName = txData[1].toLowerCase(Locale.US).indexOf("replaygain_"); - ArrayList parts = new ArrayList(); - while(startName != -1) { - int endName = txData[1].indexOf((char) 0, startName); - if(endName != -1) { - parts.add(txData[1].substring(startName, endName).toUpperCase()); - int endValue = txData[1].indexOf((char) 0, endName + 1); - if(endValue != -1) { - parts.add(txData[1].substring(endName + 1, endValue)); - nextStartIndex = endValue + 1; - } - } - - startName = txData[1].toLowerCase(Locale.US).indexOf("replaygain_", nextStartIndex); - } - - if(parts.size() > 0) { - rv = new String[parts.size()]; - rv = parts.toArray(rv); - } - } - } - } - - return rv; - } - - /* Converts a raw byte-stream text into a java String */ - private String getDecodedString(byte[] raw) { - int encid = raw[0] & 0xFF; - int len = raw.length; - String v = ""; - try { - if(encid == ID3_ENC_LATIN) { - v = new String(raw, 1, len-1, "ISO-8859-1"); - } - else if (encid == ID3_ENC_UTF8) { - v = new String(raw, 1, len-1, "UTF-8"); - } - else if (encid == ID3_ENC_UTF16LE) { - v = new String(raw, 3, len-3, "UTF-16LE"); - } - else if (encid == ID3_ENC_UTF16BE) { - v = new String(raw, 3, len-3, "UTF-16BE"); - } - } catch(Exception e) {} - return v; - } - -} diff --git a/src/github/daneren2005/dsub/util/tags/LameHeader.java b/src/github/daneren2005/dsub/util/tags/LameHeader.java deleted file mode 100644 index 720ee87f..00000000 --- a/src/github/daneren2005/dsub/util/tags/LameHeader.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2013 Adrian Ulrich - * - * This program 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 - * (at your option) any later version. - * - * This program 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 this program. If not, see . - */ - -package github.daneren2005.dsub.util.tags; - -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.HashMap; -import java.util.Enumeration; - - -public class LameHeader extends Common { - - public LameHeader() { - } - - public HashMap getTags(RandomAccessFile s) throws IOException { - return parseLameHeader(s, 0); - } - - public HashMap parseLameHeader(RandomAccessFile s, long offset) throws IOException { - HashMap tags = new HashMap(); - byte[] chunk = new byte[4]; - - s.seek(offset + 0x24); - s.read(chunk); - - String lameMark = new String(chunk, 0, chunk.length, "ISO-8859-1"); - - if(lameMark.equals("Info") || lameMark.equals("Xing")) { - s.seek(offset+0xAB); - s.read(chunk); - - int raw = b2be32(chunk, 0); - int gtrk_raw = raw >> 16; /* first 16 bits are the raw track gain value */ - int galb_raw = raw & 0xFFFF; /* the rest is for the album gain value */ - - float gtrk_val = (float)(gtrk_raw & 0x01FF)/10; - float galb_val = (float)(galb_raw & 0x01FF)/10; - - gtrk_val = ((gtrk_raw&0x0200)!=0 ? -1*gtrk_val : gtrk_val); - galb_val = ((galb_raw&0x0200)!=0 ? -1*galb_val : galb_val); - - if( (gtrk_raw&0xE000) == 0x2000 ) { - addTagEntry(tags, "REPLAYGAIN_TRACK_GAIN", gtrk_val+" dB"); - } - if( (gtrk_raw&0xE000) == 0x4000 ) { - addTagEntry(tags, "REPLAYGAIN_ALBUM_GAIN", galb_val+" dB"); - } - - } - - return tags; - } - -} diff --git a/src/github/daneren2005/dsub/util/tags/OggFile.java b/src/github/daneren2005/dsub/util/tags/OggFile.java deleted file mode 100644 index d0b31671..00000000 --- a/src/github/daneren2005/dsub/util/tags/OggFile.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2013 Adrian Ulrich - * - * This program 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 - * (at your option) any later version. - * - * This program 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 this program. If not, see . - */ - -package github.daneren2005.dsub.util.tags; - - -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.HashMap; - - -public class OggFile extends Common { - - private static final int OGG_PAGE_SIZE = 27; // Static size of an OGG Page - private static final int OGG_TYPE_COMMENT = 3; // ID of 'VorbisComment's - - public OggFile() { - } - - public HashMap getTags(RandomAccessFile s) throws IOException { - long offset = 0; - int retry = 64; - HashMap tags = new HashMap(); - - for( ; retry > 0 ; retry-- ) { - long res[] = parse_ogg_page(s, offset); - if(res[2] == OGG_TYPE_COMMENT) { - tags = parse_ogg_vorbis_comment(s, offset+res[0], res[1]); - break; - } - offset += res[0] + res[1]; - } - return tags; - } - - - /* Parses the ogg page at offset 'offset' and returns - ** [header_size, payload_size, type] - */ - private long[] parse_ogg_page(RandomAccessFile s, long offset) throws IOException { - long[] result = new long[3]; // [header_size, payload_size] - byte[] p_header = new byte[OGG_PAGE_SIZE]; // buffer for the page header - byte[] scratch; - int bread = 0; // number of bytes read - int psize = 0; // payload-size - int nsegs = 0; // Number of segments - - s.seek(offset); - bread = s.read(p_header); - if(bread != OGG_PAGE_SIZE) - xdie("Unable to read() OGG_PAGE_HEADER"); - if((new String(p_header, 0, 5)).equals("OggS\0") != true) - xdie("Invalid magic - not an ogg file?"); - - nsegs = b2u(p_header[26]); - // debug("> file seg: "+nsegs); - if(nsegs > 0) { - scratch = new byte[nsegs]; - bread = s.read(scratch); - if(bread != nsegs) - xdie("Failed to read segtable"); - - for(int i=0; i pre-read */ - if(psize >= 1 && s.read(p_header, 0, 1) == 1) { - result[2] = b2u(p_header[0]); - } - - return result; - } - - /* In 'vorbiscomment' field is prefixed with \3vorbis in OGG files - ** we check that this marker is present and call the generic comment - ** parset with the correct offset (+7) */ - private HashMap parse_ogg_vorbis_comment(RandomAccessFile s, long offset, long pl_len) throws IOException { - final int pfx_len = 7; - byte[] pfx = new byte[pfx_len]; - - if(pl_len < pfx_len) - xdie("ogg vorbis comment field is too short!"); - - s.seek(offset); - s.read(pfx); - - if( (new String(pfx, 0, pfx_len)).equals("\3vorbis") == false ) - xdie("Damaged packet found!"); - - return parse_vorbis_comment(s, offset+pfx_len, pl_len-pfx_len); - } - -}; diff --git a/src/github/daneren2005/dsub/view/AlbumCell.java b/src/github/daneren2005/dsub/view/AlbumCell.java deleted file mode 100644 index 110456e7..00000000 --- a/src/github/daneren2005/dsub/view/AlbumCell.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.RatingBar; -import android.widget.TextView; - -import java.io.File; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ImageLoader; - -public class AlbumCell extends UpdateView { - private static final String TAG = AlbumCell.class.getSimpleName(); - - private Context context; - private MusicDirectory.Entry album; - private File file; - - private View coverArtView; - private TextView titleView; - private TextView artistView; - private boolean showArtist = true; - - public AlbumCell(Context context) { - super(context); - this.context = context; - LayoutInflater.from(context).inflate(R.layout.album_cell_item, this, true); - - coverArtView = findViewById(R.id.album_coverart); - titleView = (TextView) findViewById(R.id.album_title); - artistView = (TextView) findViewById(R.id.album_artist); - - ratingBar = (RatingBar) findViewById(R.id.album_rating); - ratingBar.setFocusable(false); - starButton = (ImageButton) findViewById(R.id.album_star); - starButton.setFocusable(false); - moreButton = (ImageView) findViewById(R.id.album_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - } - - public void setShowArtist(boolean showArtist) { - this.showArtist = showArtist; - } - - protected void setObjectImpl(Object obj1, Object obj2) { - this.album = (MusicDirectory.Entry) obj1; - titleView.setText(album.getAlbumDisplay()); - String artist = ""; - if(showArtist) { - artist = album.getArtist(); - if (artist == null) { - artist = ""; - } - if (album.getYear() != null) { - artist += " - " + album.getYear(); - } - } else if(album.getYear() != null) { - artist += album.getYear(); - } - artistView.setText(album.getArtist() == null ? "" : artist); - imageTask = ((ImageLoader)obj2).loadImage(coverArtView, album, false, true); - file = null; - } - - @Override - protected void updateBackground() { - if(file == null) { - file = FileUtil.getAlbumDirectory(context, album); - } - - exists = file.exists(); - isStarred = album.isStarred(); - isRated = album.getRating(); - } - - public MusicDirectory.Entry getEntry() { - return album; - } - - public File getFile() { - return file; - } -} diff --git a/src/github/daneren2005/dsub/view/AlbumView.java b/src/github/daneren2005/dsub/view/AlbumView.java deleted file mode 100644 index 70c1e049..00000000 --- a/src/github/daneren2005/dsub/view/AlbumView.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.RatingBar; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.util.Util; -import java.io.File; -import java.util.List; - -/** - * Used to display albums in a {@code ListView}. - * - * @author Sindre Mehus - */ -public class AlbumView extends UpdateView { - private static final String TAG = AlbumView.class.getSimpleName(); - - private Context context; - private MusicDirectory.Entry album; - private File file; - - private TextView titleView; - private TextView artistView; - private View coverArtView; - - public AlbumView(Context context) { - super(context); - this.context = context; - LayoutInflater.from(context).inflate(R.layout.album_list_item, this, true); - - titleView = (TextView) findViewById(R.id.album_title); - artistView = (TextView) findViewById(R.id.album_artist); - coverArtView = findViewById(R.id.album_coverart); - ratingBar = (RatingBar) findViewById(R.id.album_rating); - starButton = (ImageButton) findViewById(R.id.album_star); - starButton.setFocusable(false); - - moreButton = (ImageView) findViewById(R.id.album_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - } - - protected void setObjectImpl(Object obj1, Object obj2) { - this.album = (MusicDirectory.Entry) obj1; - titleView.setText(album.getAlbumDisplay()); - String artist = album.getArtist(); - if(artist == null) { - artist = ""; - } - if(album.getYear() != null) { - artist += " - " + album.getYear(); - } - artistView.setText(artist); - artistView.setVisibility(album.getArtist() == null ? View.GONE : View.VISIBLE); - imageTask = ((ImageLoader)obj2).loadImage(coverArtView, album, false, true); - file = null; - } - - @Override - protected void updateBackground() { - if(file == null) { - file = FileUtil.getAlbumDirectory(context, album); - } - - exists = file.exists(); - isStarred = album.isStarred(); - isRated = album.getRating(); - } - - public MusicDirectory.Entry getEntry() { - return album; - } - - public File getFile() { - return file; - } -} diff --git a/src/github/daneren2005/dsub/view/ArtistEntryView.java b/src/github/daneren2005/dsub/view/ArtistEntryView.java deleted file mode 100644 index 157b25a9..00000000 --- a/src/github/daneren2005/dsub/view/ArtistEntryView.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.util.Util; -import java.io.File; -/** - * Used to display albums in a {@code ListView}. - * - * @author Sindre Mehus - */ -public class ArtistEntryView extends UpdateView { - private static final String TAG = ArtistEntryView.class.getSimpleName(); - - private Context context; - private MusicDirectory.Entry artist; - private File file; - - private TextView titleView; - - public ArtistEntryView(Context context) { - super(context); - this.context = context; - LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); - - titleView = (TextView) findViewById(R.id.item_name); - starButton = (ImageButton) findViewById(R.id.item_star); - starButton.setFocusable(false); - moreButton = (ImageView) findViewById(R.id.item_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - } - - protected void setObjectImpl(Object obj) { - this.artist = (MusicDirectory.Entry) obj; - titleView.setText(artist.getTitle()); - file = FileUtil.getArtistDirectory(context, artist); - } - - @Override - protected void updateBackground() { - exists = file.exists(); - isStarred = artist.isStarred(); - } - - public File getFile() { - return file; - } -} diff --git a/src/github/daneren2005/dsub/view/ArtistView.java b/src/github/daneren2005/dsub/view/ArtistView.java deleted file mode 100644 index b8a87c20..00000000 --- a/src/github/daneren2005/dsub/view/ArtistView.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Artist; -import github.daneren2005.dsub.util.FileUtil; - -import java.io.File; - -/** - * Used to display albums in a {@code ListView}. - * - * @author Sindre Mehus - */ -public class ArtistView extends UpdateView { - private static final String TAG = ArtistView.class.getSimpleName(); - - private Context context; - private Artist artist; - private File file; - - private TextView titleView; - - public ArtistView(Context context) { - super(context); - this.context = context; - LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); - - titleView = (TextView) findViewById(R.id.item_name); - starButton = (ImageButton) findViewById(R.id.item_star); - starButton.setFocusable(false); - moreButton = (ImageView) findViewById(R.id.item_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - } - - protected void setObjectImpl(Object obj) { - this.artist = (Artist) obj; - titleView.setText(artist.getName()); - file = FileUtil.getArtistDirectory(context, artist); - } - - @Override - protected void updateBackground() { - exists = file.exists(); - isStarred = artist.isStarred(); - } - - public File getFile() { - return file; - } -} diff --git a/src/github/daneren2005/dsub/view/AutoRepeatButton.java b/src/github/daneren2005/dsub/view/AutoRepeatButton.java deleted file mode 100644 index cb2d2a51..00000000 --- a/src/github/daneren2005/dsub/view/AutoRepeatButton.java +++ /dev/null @@ -1,86 +0,0 @@ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.widget.ImageButton; - -public class AutoRepeatButton extends ImageButton { - - private static final long initialRepeatDelay = 1000; - private static final long repeatIntervalInMilliseconds = 300; - private boolean doClick = true; - private Runnable repeatEvent = null; - - private Runnable repeatClickWhileButtonHeldRunnable = new Runnable() { - @Override - public void run() { - doClick = false; - //Perform the present repetition of the click action provided by the user - // in setOnClickListener(). - if(repeatEvent != null) - repeatEvent.run(); - - //Schedule the next repetitions of the click action, using a faster repeat - // interval than the initial repeat delay interval. - postDelayed(repeatClickWhileButtonHeldRunnable, repeatIntervalInMilliseconds); - } - }; - - private void commonConstructorCode() { - this.setOnTouchListener(new OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - int action = event.getAction(); - if(action == MotionEvent.ACTION_DOWN) - { - doClick = true; - //Just to be sure that we removed all callbacks, - // which should have occurred in the ACTION_UP - removeCallbacks(repeatClickWhileButtonHeldRunnable); - - //Schedule the start of repetitions after a one half second delay. - postDelayed(repeatClickWhileButtonHeldRunnable, initialRepeatDelay); - - setPressed(true); - } - else if(action == MotionEvent.ACTION_UP) { - //Cancel any repetition in progress. - removeCallbacks(repeatClickWhileButtonHeldRunnable); - - if(doClick || repeatEvent == null) { - performClick(); - } - - setPressed(false); - } - - //Returning true here prevents performClick() from getting called - // in the usual manner, which would be redundant, given that we are - // already calling it above. - return true; - } - }); - } - - public void setOnRepeatListener(Runnable runnable) { - repeatEvent = runnable; - } - - public AutoRepeatButton(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - commonConstructorCode(); - } - - - public AutoRepeatButton(Context context, AttributeSet attrs) { - super(context, attrs); - commonConstructorCode(); - } - - public AutoRepeatButton(Context context) { - super(context); - commonConstructorCode(); - } -} diff --git a/src/github/daneren2005/dsub/view/ChangeLog.java b/src/github/daneren2005/dsub/view/ChangeLog.java deleted file mode 100644 index 096583c7..00000000 --- a/src/github/daneren2005/dsub/view/ChangeLog.java +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Copyright (C) 2012 Christian Ketterer (cketti) - * - * Portions Copyright (C) 2012 Martin van Zuilekom (http://martin.cubeactive.com) - * - * 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. - * - * - * Based on android-change-log: - * - * Copyright (C) 2011, Karsten Priegnitz - * - * Permission to use, copy, modify, and distribute this piece of software - * for any purpose with or without fee is hereby granted, provided that - * the above copyright notice and this permission notice appear in the - * source code of all copies. - * - * It would be appreciated if you mention the author in your change log, - * contributors list or the like. - * - * http://code.google.com/p/android-change-log/ - */ -package github.daneren2005.dsub.view; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.SharedPreferences; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Resources; -import android.content.res.XmlResourceParser; -import android.preference.PreferenceManager; -import android.util.Log; -import android.util.SparseArray; -import android.webkit.WebView; -import github.daneren2005.dsub.R; - - -/** - * Display a dialog showing a full or partial (What's New) change log. - */ -public class ChangeLog { - /** - * Tag that is used when sending error/debug messages to the log. - */ - protected static final String LOG_TAG = "ckChangeLog"; - - /** - * This is the key used when storing the version code in SharedPreferences. - */ - protected static final String VERSION_KEY = "ckChangeLog_last_version_code"; - - /** - * Constant that used when no version code is available. - */ - protected static final int NO_VERSION = -1; - - /** - * Default CSS styles used to format the change log. - */ - private static final String DEFAULT_CSS = - "div.title { margin-left: 0px; font-size: 1.2em; text-align: center;}" + - "div.subtitle {margin-left: 0px; font-size: .8em; text-align: center;}" + - "li { margin-left: 0px;}" + - "ul { padding-left: 2em;}"; - - - /** - * Context that is used to access the resources and to create the ChangeLog dialogs. - */ - protected final Context mContext; - - /** - * Contains the CSS rules used to format the change log. - */ - protected final String mCss; - - /** - * Last version code read from {@code SharedPreferences} or {@link #NO_VERSION}. - */ - private int mLastVersionCode; - - /** - * Version code of the current installation. - */ - private int mCurrentVersionCode; - - /** - * Version name of the current installation. - */ - private String mCurrentVersionName; - - - /** - * Contains constants for the root element of {@code changelog.xml}. - */ - protected interface ChangeLogTag { - static final String NAME = "changelog"; - } - - /** - * Contains constants for the release element of {@code changelog.xml}. - */ - protected interface ReleaseTag { - static final String NAME = "release"; - static final String ATTRIBUTE_VERSION = "version"; - static final String ATTRIBUTE_VERSION_CODE = "versioncode"; - static final String ATTRIBUTE_RELEASE_DATE = "releasedate"; - } - - /** - * Contains constants for the change element of {@code changelog.xml}. - */ - protected interface ChangeTag { - static final String NAME = "change"; - } - - /** - * Create a {@code ChangeLog} instance using the default {@link SharedPreferences} file. - * - * @param context - * Context that is used to access the resources and to create the ChangeLog dialogs. - */ - public ChangeLog(Context context) { - this(context, PreferenceManager.getDefaultSharedPreferences(context), DEFAULT_CSS); - } - - /** - * Create a {@code ChangeLog} instance using the default {@link SharedPreferences} file. - * - * @param context - * Context that is used to access the resources and to create the ChangeLog dialogs. - * @param css - * CSS styles that will be used to format the change log. - */ - public ChangeLog(Context context, String css) { - this(context, PreferenceManager.getDefaultSharedPreferences(context), css); - } - - public ChangeLog(Context context, SharedPreferences preferences) { - this(context, preferences, DEFAULT_CSS); - } - - /** - * Create a {@code ChangeLog} instance using the supplied {@code SharedPreferences} instance. - * - * @param context - * Context that is used to access the resources and to create the ChangeLog dialogs. - * @param preferences - * {@code SharedPreferences} instance that is used to persist the last version code. - * @param css - * CSS styles used to format the change log (excluding {@code }). - * - */ - public ChangeLog(Context context, SharedPreferences preferences, String css) { - mContext = context; - mCss = css; - - // Get last version code - mLastVersionCode = preferences.getInt(VERSION_KEY, NO_VERSION); - - // Get current version code and version name - try { - PackageInfo packageInfo = context.getPackageManager().getPackageInfo( - context.getPackageName(), 0); - - mCurrentVersionCode = packageInfo.versionCode; - mCurrentVersionName = packageInfo.versionName; - } catch (NameNotFoundException e) { - mCurrentVersionCode = NO_VERSION; - Log.e(LOG_TAG, "Could not get version information from manifest!", e); - } - } - - /** - * Get version code of last installation. - * - * @return The version code of the last installation of this app (as described in the former - * manifest). This will be the same as returned by {@link #getCurrentVersionCode()} the - * second time this version of the app is launched (more precisely: the second time - * {@code ChangeLog} is instantiated). - * - * @see AndroidManifest.xml#android:versionCode - */ - public int getLastVersionCode() { - return mLastVersionCode; - } - - /** - * Get version code of current installation. - * - * @return The version code of this app as described in the manifest. - * - * @see AndroidManifest.xml#android:versionCode - */ - public int getCurrentVersionCode() { - return mCurrentVersionCode; - } - - /** - * Get version name of current installation. - * - * @return The version name of this app as described in the manifest. - * - * @see AndroidManifest.xml#android:versionName - */ - public String getCurrentVersionName() { - return mCurrentVersionName; - } - - /** - * Check if this is the first execution of this app version. - * - * @return {@code true} if this version of your app is started the first time. - */ - public boolean isFirstRun() { - return mLastVersionCode < mCurrentVersionCode; - } - - /** - * Check if this is a new installation. - * - * @return {@code true} if your app including {@code ChangeLog} is started the first time ever. - * Also {@code true} if your app was uninstalled and installed again. - */ - public boolean isFirstRunEver() { - return mLastVersionCode == NO_VERSION; - } - - /** - * Get the "What's New" dialog. - * - * @return An AlertDialog displaying the changes since the previous installed version of your - * app (What's New). But when this is the first run of your app including - * {@code ChangeLog} then the full log dialog is show. - */ - public AlertDialog getLogDialog() { - return getDialog(isFirstRunEver()); - } - - /** - * Get a dialog with the full change log. - * - * @return An AlertDialog with a full change log displayed. - */ - public AlertDialog getFullLogDialog() { - return getDialog(true); - } - - /** - * Create a dialog containing (parts of the) change log. - * - * @param full - * If this is {@code true} the full change log is displayed. Otherwise only changes for - * versions newer than the last version are displayed. - * - * @return A dialog containing the (partial) change log. - */ - protected AlertDialog getDialog(boolean full) { - WebView wv = new WebView(mContext); - //wv.setBackgroundColor(0); // transparent - String log = getLog(full); - // No changes to show - if(log == null) { - return null; - } - - wv.loadDataWithBaseURL(null, log, "text/html", "UTF-8", null); - - AlertDialog.Builder builder = new AlertDialog.Builder(mContext); - builder.setTitle( - mContext.getResources().getString( - full ? R.string.changelog_full_title : R.string.changelog_title)) - .setView(wv) - .setCancelable(false) - // OK button - .setPositiveButton( - mContext.getResources().getString(R.string.changelog_ok_button), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // The user clicked "OK" so save the current version code as - // "last version code". - updateVersionInPreferences(); - } - }); - - if (!full) { - // Show "More…" button if we're only displaying a partial change log. - builder.setNegativeButton(R.string.changelog_show_full, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - getFullLogDialog().show(); - } - }); - } - - return builder.create(); - } - - /** - * Write current version code to the preferences. - */ - public void updateVersionInPreferences() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext); - SharedPreferences.Editor editor = sp.edit(); - editor.putInt(VERSION_KEY, mCurrentVersionCode); - - // TODO: Update preferences from a background thread - editor.commit(); - } - - /** - * Get changes since last version as HTML string. - * - * @return HTML string containing the changes since the previous installed version of your app - * (What's New). - */ - public String getLog() { - return getLog(false); - } - - /** - * Get full change log as HTML string. - * - * @return HTML string containing the full change log. - */ - public String getFullLog() { - return getLog(true); - } - - /** - * Get (partial) change log as HTML string. - * - * @param full - * If this is {@code true} the full change log is returned. Otherwise only changes for - * versions newer than the last version are returned. - * - * @return The (partial) change log. - */ - private String getLog(boolean full) { - StringBuilder sb = new StringBuilder(); - - sb.append(""); - - Resources resources = mContext.getResources(); - - // Read master change log from xml/changelog.xml - SparseArray changelog; - XmlResourceParser resXml = mContext.getResources().getXml(R.xml.changelog); - try { - changelog = readChangeLog(resXml, full); - } finally { - resXml.close(); - } - - String versionFormat = resources.getString(R.string.changelog_version_format); - - // Get all version codes from the master change log... - List versions = new ArrayList(changelog.size()); - for (int i = 0, len = changelog.size(); i < len; i++) { - int key = changelog.keyAt(i); - versions.add(key); - } - - // ... and sort them (newest version first). - Collections.sort(versions, Collections.reverseOrder()); - - if(versions.size() == 0) { - return null; - } - - for (Integer version : versions) { - int key = version.intValue(); - - // Use release information from localized change log and fall back to the master file - // if necessary. - ReleaseItem release = changelog.get(key); - - sb.append("
"); - sb.append(String.format(versionFormat, release.versionName)); - sb.append("
"); - if(release.releaseDate != null) { - sb.append("
"); - sb.append(release.releaseDate); - sb.append("
"); - } - sb.append("
    "); - for (String change : release.changes) { - sb.append("
  • "); - sb.append(change); - sb.append("
  • "); - } - sb.append("
"); - } - - sb.append(""); - - return sb.toString(); - } - - /** - * Read the change log from an XML file. - * - * @param xml - * The {@code XmlPullParser} instance used to read the change log. - * @param full - * If {@code true} the full change log is read. Otherwise only the changes since the - * last (saved) version are read. - * - * @return A {@code SparseArray} mapping the version codes to release information. - */ - protected SparseArray readChangeLog(XmlPullParser xml, boolean full) { - SparseArray result = new SparseArray(); - - try { - int eventType = xml.getEventType(); - while (eventType != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG && xml.getName().equals(ReleaseTag.NAME)) { - if (parseReleaseTag(xml, full, result)) { - // Stop reading more elements if this entry is not newer than the last - // version. - break; - } - } - eventType = xml.next(); - } - } catch (XmlPullParserException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } catch (IOException e) { - Log.e(LOG_TAG, e.getMessage(), e); - } - - return result; - } - - /** - * Parse the {@code release} tag of a change log XML file. - * - * @param xml - * The {@code XmlPullParser} instance used to read the change log. - * @param full - * If {@code true} the contents of the {@code release} tag are always added to - * {@code changelog}. Otherwise only if the item's {@code versioncode} attribute is - * higher than the last version code. - * @param changelog - * The {@code SparseArray} to add a new {@link ReleaseItem} instance to. - * - * @return {@code true} if the {@code release} element is describing changes of a version older - * or equal to the last version. In that case {@code changelog} won't be modified and - * {@link #readChangeLog(XmlPullParser, boolean)} will stop reading more elements from - * the change log file. - * - * @throws XmlPullParserException - * @throws IOException - */ - private boolean parseReleaseTag(XmlPullParser xml, boolean full, - SparseArray changelog) throws XmlPullParserException, IOException { - - String version = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_VERSION); - - int versionCode; - try { - String versionCodeStr = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_VERSION_CODE); - versionCode = Integer.parseInt(versionCodeStr); - } catch (NumberFormatException e) { - versionCode = NO_VERSION; - } - - String releaseDate = xml.getAttributeValue(null, ReleaseTag.ATTRIBUTE_RELEASE_DATE); - - if (!full && versionCode <= mLastVersionCode) { - return true; - } - - int eventType = xml.getEventType(); - List changes = new ArrayList(); - while (eventType != XmlPullParser.END_TAG || xml.getName().equals(ChangeTag.NAME)) { - if (eventType == XmlPullParser.START_TAG && xml.getName().equals(ChangeTag.NAME)) { - eventType = xml.next(); - - changes.add(xml.getText()); - } - eventType = xml.next(); - } - - ReleaseItem release = new ReleaseItem(versionCode, version, releaseDate, changes); - changelog.put(versionCode, release); - - return false; - } - - /** - * Container used to store information about a release/version. - */ - protected static class ReleaseItem { - /** - * Version code of the release. - */ - public final int versionCode; - - /** - * Version name of the release. - */ - public final String versionName; - - public final String releaseDate; - - /** - * List of changes introduced with that release. - */ - public final List changes; - - ReleaseItem(int versionCode, String versionName, String releaseDate, List changes) { - this.versionCode = versionCode; - this.versionName = versionName; - this.releaseDate = releaseDate; - this.changes = changes; - } - } -} diff --git a/src/github/daneren2005/dsub/view/ErrorDialog.java b/src/github/daneren2005/dsub/view/ErrorDialog.java deleted file mode 100644 index 0b9d05a0..00000000 --- a/src/github/daneren2005/dsub/view/ErrorDialog.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.SubsonicFragmentActivity; -import github.daneren2005.dsub.util.Util; - -/** - * @author Sindre Mehus - */ -public class ErrorDialog { - - public ErrorDialog(Activity activity, int messageId, boolean finishActivityOnCancel) { - this(activity, activity.getResources().getString(messageId), finishActivityOnCancel); - } - - public ErrorDialog(final Activity activity, String message, final boolean finishActivityOnClose) { - - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setIcon(android.R.drawable.ic_dialog_alert); - builder.setTitle(R.string.error_label); - builder.setMessage(message); - builder.setCancelable(true); - builder.setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialogInterface) { - if (finishActivityOnClose) { - restart(activity); - } - } - }); - builder.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (finishActivityOnClose) { - restart(activity); - } - } - }); - - try { - builder.create().show(); - } catch(Exception e) { - // Don't care, just means no activity to attach to - } - } - - private void restart(Activity activity) { - Intent intent = new Intent(activity, SubsonicFragmentActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - Util.startActivityWithoutTransition(activity, intent); - } -} diff --git a/src/github/daneren2005/dsub/view/FadeOutAnimation.java b/src/github/daneren2005/dsub/view/FadeOutAnimation.java deleted file mode 100644 index 292529e6..00000000 --- a/src/github/daneren2005/dsub/view/FadeOutAnimation.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.view.View; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; - -/** - * Fades a view out by changing its alpha value. - * - * @author Sindre Mehus - * @version $Id: Util.java 3203 2012-10-04 09:12:08Z sindre_mehus $ - */ -public class FadeOutAnimation extends AlphaAnimation { - - private boolean cancelled; - - /** - * Creates and starts the fade out animation. - * - * @param view The view to fade out (or display). - * @param fadeOut If true, the view is faded out. Otherwise it is immediately made visible. - * @param durationMillis Fade duration. - */ - public static void createAndStart(View view, boolean fadeOut, long durationMillis) { - if (fadeOut) { - view.clearAnimation(); - view.startAnimation(new FadeOutAnimation(view, durationMillis)); - } else { - Animation animation = view.getAnimation(); - if (animation instanceof FadeOutAnimation) { - ((FadeOutAnimation) animation).cancelFadeOut(); - } - view.clearAnimation(); - view.setVisibility(View.VISIBLE); - } - } - - FadeOutAnimation(final View view, long durationMillis) { - super(1.0F, 0.0F); - setDuration(durationMillis); - setAnimationListener(new AnimationListener() { - public void onAnimationStart(Animation animation) { - } - - public void onAnimationRepeat(Animation animation) { - } - - public void onAnimationEnd(Animation animation) { - if (!cancelled) { - view.setVisibility(View.INVISIBLE); - } - } - }); - } - - private void cancelFadeOut() { - cancelled = true; - } -} diff --git a/src/github/daneren2005/dsub/view/GenreView.java b/src/github/daneren2005/dsub/view/GenreView.java deleted file mode 100644 index 6cd779c5..00000000 --- a/src/github/daneren2005/dsub/view/GenreView.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Genre; - -public class GenreView extends UpdateView { - private static final String TAG = GenreView.class.getSimpleName(); - - private TextView titleView; - private TextView songsView; - private TextView albumsView; - - public GenreView(Context context) { - super(context, false); - LayoutInflater.from(context).inflate(R.layout.genre_list_item, this, true); - - titleView = (TextView) findViewById(R.id.genre_name); - songsView = (TextView) findViewById(R.id.genre_songs); - albumsView = (TextView) findViewById(R.id.genre_albums); - } - - public void setObjectImpl(Object obj) { - Genre genre = (Genre) obj; - titleView.setText(genre.getName()); - - if(genre.getAlbumCount() != null) { - songsView.setVisibility(View.VISIBLE); - albumsView.setVisibility(View.VISIBLE); - songsView.setText(context.getResources().getString(R.string.select_genre_songs, genre.getSongCount())); - albumsView.setText(context.getResources().getString(R.string.select_genre_albums, genre.getAlbumCount())); - } else { - songsView.setVisibility(View.GONE); - albumsView.setVisibility(View.GONE); - } - } -} diff --git a/src/github/daneren2005/dsub/view/HeaderGridView.java b/src/github/daneren2005/dsub/view/HeaderGridView.java deleted file mode 100644 index 8a82f353..00000000 --- a/src/github/daneren2005/dsub/view/HeaderGridView.java +++ /dev/null @@ -1,836 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ -package github.daneren2005.dsub.view; - -import android.annotation.TargetApi; -import android.content.Context; -import android.database.DataSetObservable; -import android.database.DataSetObserver; -import android.os.Build; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.widget.*; - -import java.lang.reflect.Field; -import java.util.ArrayList; - -/** - * A {@link GridView} that supports adding header rows in a - * very similar way to {@link android.widget.ListView}. - * See {@link HeaderGridView#addHeaderView(View, Object, boolean)} - * See {@link HeaderGridView#addFooterView(View, Object, boolean)} - */ -public class HeaderGridView extends GridView { - private static final String TAG = HeaderGridView.class.getSimpleName(); - public static boolean DEBUG = false; - - /** - * A class that represents a fixed view in a list, for example a header at the top - * or a footer at the bottom. - */ - private static class FixedViewInfo { - /** - * The view to add to the grid - */ - public View view; - public ViewGroup viewContainer; - /** - * The data backing the view. This is returned from {@link ListAdapter#getItem(int)}. - */ - public Object data; - /** - * true if the fixed view should be selectable in the grid - */ - public boolean isSelectable; - } - - private int mNumColumns = AUTO_FIT; - private View mViewForMeasureRowHeight = null; - private int mRowHeight = -1; - private static final String LOG_TAG = HeaderGridView.class.getSimpleName(); - - private ArrayList mHeaderViewInfos = new ArrayList(); - private ArrayList mFooterViewInfos = new ArrayList(); - - private void initHeaderGridView() { - } - - public HeaderGridView(Context context) { - super(context); - initHeaderGridView(); - } - - public HeaderGridView(Context context, AttributeSet attrs) { - super(context, attrs); - initHeaderGridView(); - } - - public HeaderGridView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initHeaderGridView(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - ListAdapter adapter = getAdapter(); - if (adapter != null && adapter instanceof HeaderViewGridAdapter) { - ((HeaderViewGridAdapter) adapter).setNumColumns(getNumColumnsCompatible()); - ((HeaderViewGridAdapter) adapter).setRowHeight(getRowHeight()); - } - } - - @Override - public void setClipChildren(boolean clipChildren) { - // Ignore, since the header rows depend on not being clipped - } - - /** - * Do not call this method unless you know how it works. - * - * @param clipChildren - */ - public void setClipChildrenSupper(boolean clipChildren) { - super.setClipChildren(false); - } - - /** - * Add a fixed view to appear at the top of the grid. If addHeaderView is - * called more than once, the views will appear in the order they were - * added. Views added using this call can take focus if they want. - *

- * NOTE: Call this before calling setAdapter. This is so HeaderGridView can wrap - * the supplied cursor with one that will also account for header views. - * - * @param v The view to add. - */ - public void addHeaderView(View v) { - addHeaderView(v, null, true); - } - - /** - * Add a fixed view to appear at the top of the grid. If addHeaderView is - * called more than once, the views will appear in the order they were - * added. Views added using this call can take focus if they want. - *

- * NOTE: Call this before calling setAdapter. This is so HeaderGridView can wrap - * the supplied cursor with one that will also account for header views. - * - * @param v The view to add. - * @param data Data to associate with this view - * @param isSelectable whether the item is selectable - */ - public void addHeaderView(View v, Object data, boolean isSelectable) { - ListAdapter adapter = getAdapter(); - if (adapter != null && !(adapter instanceof HeaderViewGridAdapter)) { - throw new IllegalStateException( - "Cannot add header view to grid -- setAdapter has already been called."); - } - - ViewGroup.LayoutParams lyp = v.getLayoutParams(); - - FixedViewInfo info = new FixedViewInfo(); - FrameLayout fl = new FullWidthFixedViewLayout(getContext()); - - if (lyp != null) { - v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height)); - fl.setLayoutParams(new AbsListView.LayoutParams(lyp.width, lyp.height)); - } - fl.addView(v); - info.view = v; - info.viewContainer = fl; - info.data = data; - info.isSelectable = isSelectable; - mHeaderViewInfos.add(info); - // in the case of re-adding a header view, or adding one later on, - // we need to notify the observer - if (adapter != null) { - ((HeaderViewGridAdapter) adapter).notifyDataSetChanged(); - } - } - - public void addFooterView(View v) { - addFooterView(v, null, true); - } - - public void addFooterView(View v, Object data, boolean isSelectable) { - ListAdapter mAdapter = getAdapter(); - if (mAdapter != null && !(mAdapter instanceof HeaderViewGridAdapter)) { - throw new IllegalStateException( - "Cannot add header view to grid -- setAdapter has already been called."); - } - - ViewGroup.LayoutParams lyp = v.getLayoutParams(); - - FixedViewInfo info = new FixedViewInfo(); - FrameLayout fl = new FullWidthFixedViewLayout(getContext()); - - if (lyp != null) { - v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height)); - fl.setLayoutParams(new AbsListView.LayoutParams(lyp.width, lyp.height)); - } - fl.addView(v); - info.view = v; - info.viewContainer = fl; - info.data = data; - info.isSelectable = isSelectable; - mFooterViewInfos.add(info); - - if (mAdapter != null) { - ((HeaderViewGridAdapter) mAdapter).notifyDataSetChanged(); - } - } - - public int getHeaderViewCount() { - return mHeaderViewInfos.size(); - } - - public int getFooterViewCount() { - return mFooterViewInfos.size(); - } - - /** - * Removes a previously-added header view. - * - * @param v The view to remove - * @return true if the view was removed, false if the view was not a header - * view - */ - public boolean removeHeaderView(View v) { - if (mHeaderViewInfos.size() > 0) { - boolean result = false; - ListAdapter adapter = getAdapter(); - if (adapter != null && ((HeaderViewGridAdapter) adapter).removeHeader(v)) { - result = true; - } - removeFixedViewInfo(v, mHeaderViewInfos); - return result; - } - return false; - } - - /** - * Removes a previously-added footer view. - * - * @param v The view to remove - * @return true if the view was removed, false if the view was not a header - * view - */ - public boolean removeFooterView(View v) { - if (mFooterViewInfos.size() > 0) { - boolean result = false; - ListAdapter adapter = getAdapter(); - if (adapter != null && ((HeaderViewGridAdapter) adapter).removeFooter(v)) { - result = true; - } - removeFixedViewInfo(v, mFooterViewInfos); - return result; - } - return false; - } - - private void removeFixedViewInfo(View v, ArrayList where) { - int len = where.size(); - for (int i = 0; i < len; ++i) { - FixedViewInfo info = where.get(i); - if (info.view == v) { - where.remove(i); - break; - } - } - } - - @TargetApi(11) - private int getNumColumnsCompatible() { - if (Build.VERSION.SDK_INT >= 11) { - return super.getNumColumns(); - } else { - try { - Field numColumns = GridView.class.getSuperclass().getDeclaredField("mNumColumns"); - numColumns.setAccessible(true); - return numColumns.getInt(this); - } catch (Exception e) { - if (mNumColumns != -1) { - return mNumColumns; - } else { - return 2; - } - } - } - } - - @TargetApi(16) - private int getColumnWidthCompatible() { - if (Build.VERSION.SDK_INT >= 16) { - return super.getColumnWidth(); - } else { - try { - Field numColumns = getClass().getSuperclass().getDeclaredField("mColumnWidth"); - numColumns.setAccessible(true); - return numColumns.getInt(this); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mViewForMeasureRowHeight = null; - } - - public void invalidateRowHeight() { - mRowHeight = -1; - } - - public int getHeaderHeight(int row) { - if (row >= 0) { - return mHeaderViewInfos.get(row).view.getMeasuredHeight(); - } - - return 0; - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - public int getVerticalSpacing(){ - int value = 0; - - try { - int currentapiVersion = android.os.Build.VERSION.SDK_INT; - if (currentapiVersion < Build.VERSION_CODES.JELLY_BEAN){ - Field field = this.getClass().getSuperclass().getDeclaredField("mVerticalSpacing"); - field.setAccessible(true); - value = field.getInt(this); - } else{ - value = super.getVerticalSpacing(); - } - - }catch (Exception ex){ - - } - - return value; - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - public int getHorizontalSpacing(){ - int value = 0; - - try { - int currentapiVersion = android.os.Build.VERSION.SDK_INT; - if (currentapiVersion < Build.VERSION_CODES.JELLY_BEAN){ - Field field = this.getClass().getSuperclass().getDeclaredField("mHorizontalSpacing"); - field.setAccessible(true); - value = field.getInt(this); - } else{ - value = super.getHorizontalSpacing(); - } - - }catch (Exception ex){ - - } - - return value; - } - - public int getRowHeight() { - if (mRowHeight > 0) { - // return mRowHeight; - } - ListAdapter adapter = getAdapter(); - int numColumns = getNumColumnsCompatible(); - - // adapter has not been set or has no views in it; - if (adapter == null || adapter.getCount() <= numColumns * (mHeaderViewInfos.size() + mFooterViewInfos.size()) || numColumns == -1) { - return -1; - } - int mColumnWidth = getColumnWidthCompatible(); - View view = getAdapter().getView(numColumns * mHeaderViewInfos.size(), mViewForMeasureRowHeight, this); - AbsListView.LayoutParams p = (AbsListView.LayoutParams) view.getLayoutParams(); - if (p == null) { - p = new AbsListView.LayoutParams(-1, -2, 0); - view.setLayoutParams(p); - } - int childHeightSpec = getChildMeasureSpec( - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height); - int childWidthSpec = getChildMeasureSpec( - MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width); - view.measure(childWidthSpec, childHeightSpec); - mViewForMeasureRowHeight = view; - mRowHeight = view.getMeasuredHeight(); - return mRowHeight; - } - - @TargetApi(11) - public void tryToScrollToBottomSmoothly() { - int lastPos = getAdapter().getCount() - 1; - if (Build.VERSION.SDK_INT >= 11) { - smoothScrollToPositionFromTop(lastPos, 0); - } else { - setSelection(lastPos); - } - } - - @TargetApi(11) - public void tryToScrollToBottomSmoothly(int duration) { - int lastPos = getAdapter().getCount() - 1; - if (Build.VERSION.SDK_INT >= 11) { - smoothScrollToPositionFromTop(lastPos, 0, duration); - } else { - setSelection(lastPos); - } - } - - @Override - public void setAdapter(ListAdapter adapter) { - if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) { - HeaderViewGridAdapter headerViewGridAdapter = new HeaderViewGridAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); - int numColumns = getNumColumnsCompatible(); - if (numColumns > 1) { - headerViewGridAdapter.setNumColumns(numColumns); - } - headerViewGridAdapter.setRowHeight(getRowHeight()); - super.setAdapter(headerViewGridAdapter); - } else { - super.setAdapter(adapter); - } - } - - /** - * full width - */ - private class FullWidthFixedViewLayout extends FrameLayout { - - public FullWidthFixedViewLayout(Context context) { - super(context); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int realLeft = HeaderGridView.this.getPaddingLeft() + getPaddingLeft(); - // Try to make where it should be, from left, full width - if (realLeft != left) { - offsetLeftAndRight(realLeft - left); - } - super.onLayout(changed, left, top, right, bottom); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int targetWidth = HeaderGridView.this.getMeasuredWidth() - - HeaderGridView.this.getPaddingLeft() - - HeaderGridView.this.getPaddingRight(); - widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth, - MeasureSpec.getMode(widthMeasureSpec)); - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - } - - @Override - public void setNumColumns(int numColumns) { - super.setNumColumns(numColumns); - mNumColumns = numColumns; - ListAdapter adapter = getAdapter(); - if (adapter != null && adapter instanceof HeaderViewGridAdapter) { - ((HeaderViewGridAdapter) adapter).setNumColumns(numColumns); - } - } - - /** - * ListAdapter used when a HeaderGridView has header views. This ListAdapter - * wraps another one and also keeps track of the header views and their - * associated data objects. - *

This is intended as a base class; you will probably not need to - * use this class directly in your own code. - */ - private static class HeaderViewGridAdapter extends BaseAdapter implements WrapperListAdapter, Filterable { - // This is used to notify the container of updates relating to number of columns - // or headers changing, which changes the number of placeholders needed - private final DataSetObservable mDataSetObservable = new DataSetObservable(); - private final ListAdapter mAdapter; - static final ArrayList EMPTY_INFO_LIST = - new ArrayList(); - - // This ArrayList is assumed to NOT be null. - ArrayList mHeaderViewInfos; - ArrayList mFooterViewInfos; - private int mNumColumns = 1; - private int mRowHeight = -1; - boolean mAreAllFixedViewsSelectable; - private final boolean mIsFilterable; - private boolean mCachePlaceHoldView = true; - // From Recycle Bin or calling getView, this a question... - private boolean mCacheFirstHeaderView = false; - - public HeaderViewGridAdapter(ArrayList headerViewInfos, ArrayList footViewInfos, ListAdapter adapter) { - mAdapter = adapter; - mIsFilterable = adapter instanceof Filterable; - if (headerViewInfos == null) { - mHeaderViewInfos = EMPTY_INFO_LIST; - } else { - mHeaderViewInfos = headerViewInfos; - } - - if (footViewInfos == null) { - mFooterViewInfos = EMPTY_INFO_LIST; - } else { - mFooterViewInfos = footViewInfos; - } - mAreAllFixedViewsSelectable = areAllListInfosSelectable(mHeaderViewInfos) - && areAllListInfosSelectable(mFooterViewInfos); - } - - public void setNumColumns(int numColumns) { - if (numColumns < 1) { - return; - } - if (mNumColumns != numColumns) { - mNumColumns = numColumns; - notifyDataSetChanged(); - } - } - - public void setRowHeight(int height) { - mRowHeight = height; - } - - public int getHeadersCount() { - return mHeaderViewInfos.size(); - } - - public int getFootersCount() { - return mFooterViewInfos.size(); - } - - @Override - public boolean isEmpty() { - return (mAdapter == null || mAdapter.isEmpty()) && getHeadersCount() == 0 && getFootersCount() == 0; - } - - private boolean areAllListInfosSelectable(ArrayList infos) { - if (infos != null) { - for (FixedViewInfo info : infos) { - if (!info.isSelectable) { - return false; - } - } - } - return true; - } - - public boolean removeHeader(View v) { - for (int i = 0; i < mHeaderViewInfos.size(); i++) { - FixedViewInfo info = mHeaderViewInfos.get(i); - if (info.view == v) { - mHeaderViewInfos.remove(i); - mAreAllFixedViewsSelectable = - areAllListInfosSelectable(mHeaderViewInfos) && areAllListInfosSelectable(mFooterViewInfos); - mDataSetObservable.notifyChanged(); - return true; - } - } - return false; - } - - public boolean removeFooter(View v) { - for (int i = 0; i < mFooterViewInfos.size(); i++) { - FixedViewInfo info = mFooterViewInfos.get(i); - if (info.view == v) { - mFooterViewInfos.remove(i); - mAreAllFixedViewsSelectable = - areAllListInfosSelectable(mHeaderViewInfos) && areAllListInfosSelectable(mFooterViewInfos); - mDataSetObservable.notifyChanged(); - return true; - } - } - return false; - } - - @Override - public int getCount() { - if (mAdapter != null) { - return (getFootersCount() + getHeadersCount()) * mNumColumns + getAdapterAndPlaceHolderCount(); - } else { - return (getFootersCount() + getHeadersCount()) * mNumColumns; - } - } - - @Override - public boolean areAllItemsEnabled() { - if (mAdapter != null) { - return mAreAllFixedViewsSelectable && mAdapter.areAllItemsEnabled(); - } else { - return true; - } - } - - private int getAdapterAndPlaceHolderCount() { - final int adapterCount = (int) (Math.ceil(1f * mAdapter.getCount() / mNumColumns) * mNumColumns); - return adapterCount; - } - - @Override - public boolean isEnabled(int position) { - // Header (negative positions will throw an IndexOutOfBoundsException) - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (position < numHeadersAndPlaceholders) { - return position % mNumColumns == 0 - && mHeaderViewInfos.get(position / mNumColumns).isSelectable; - } - - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition < adapterCount) { - return adjPosition < mAdapter.getCount() && mAdapter.isEnabled(adjPosition); - } - } - - // Footer (off-limits positions will throw an IndexOutOfBoundsException) - final int footerPosition = adjPosition - adapterCount; - return footerPosition % mNumColumns == 0 - && mFooterViewInfos.get(footerPosition / mNumColumns).isSelectable; - } - - @Override - public Object getItem(int position) { - // Header (negative positions will throw an ArrayIndexOutOfBoundsException) - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (position < numHeadersAndPlaceholders) { - if (position % mNumColumns == 0) { - return mHeaderViewInfos.get(position / mNumColumns).data; - } - return null; - } - - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition < adapterCount) { - if (adjPosition < mAdapter.getCount()) { - return mAdapter.getItem(adjPosition); - } else { - return null; - } - } - } - - // Footer (off-limits positions will throw an IndexOutOfBoundsException) - final int footerPosition = adjPosition - adapterCount; - if (footerPosition % mNumColumns == 0) { - return mFooterViewInfos.get(footerPosition).data; - } else { - return null; - } - } - - @Override - public long getItemId(int position) { - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (mAdapter != null && position >= numHeadersAndPlaceholders) { - int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = mAdapter.getCount(); - if (adjPosition < adapterCount) { - return mAdapter.getItemId(adjPosition); - } - } - return -1; - } - - @Override - public boolean hasStableIds() { - if (mAdapter != null) { - return mAdapter.hasStableIds(); - } - return false; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (DEBUG) { - Log.d(LOG_TAG, String.format("getView: %s, reused: %s", position, convertView == null)); - } - // Header (negative positions will throw an ArrayIndexOutOfBoundsException) - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (position < numHeadersAndPlaceholders) { - View headerViewContainer = mHeaderViewInfos - .get(position / mNumColumns).viewContainer; - if (position % mNumColumns == 0) { - return headerViewContainer; - } else { - if (convertView == null) { - convertView = new View(parent.getContext()); - } - // We need to do this because GridView uses the height of the last item - // in a row to determine the height for the entire row. - convertView.setVisibility(View.INVISIBLE); - convertView.setMinimumHeight(headerViewContainer.getHeight()); - return convertView; - } - } - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition < adapterCount) { - if (adjPosition < mAdapter.getCount()) { - View view = mAdapter.getView(adjPosition, convertView, parent); - return view; - } else { - if (convertView == null) { - convertView = new View(parent.getContext()); - } - convertView.setVisibility(View.INVISIBLE); - convertView.setMinimumHeight(mRowHeight); - return convertView; - } - } - } - // Footer - final int footerPosition = adjPosition - adapterCount; - if (footerPosition < getCount()) { - View footViewContainer = mFooterViewInfos - .get(footerPosition / mNumColumns).viewContainer; - if (position % mNumColumns == 0) { - return footViewContainer; - } else { - if (convertView == null) { - convertView = new View(parent.getContext()); - } - // We need to do this because GridView uses the height of the last item - // in a row to determine the height for the entire row. - convertView.setVisibility(View.INVISIBLE); - convertView.setMinimumHeight(footViewContainer.getHeight()); - return convertView; - } - } - throw new ArrayIndexOutOfBoundsException(position); - } - - @Override - public int getItemViewType(int position) { - - final int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - final int adapterViewTypeStart = mAdapter == null ? 0 : mAdapter.getViewTypeCount() - 1; - int type = AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER; - if (mCachePlaceHoldView) { - // Header - if (position < numHeadersAndPlaceholders) { - if (position == 0) { - if (mCacheFirstHeaderView) { - type = adapterViewTypeStart + mHeaderViewInfos.size() + mFooterViewInfos.size() + 1 + 1; - } - } - if (position % mNumColumns != 0) { - type = adapterViewTypeStart + (position / mNumColumns + 1); - } - } - } - - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition >= 0 && adjPosition < adapterCount) { - if (adjPosition < mAdapter.getCount()) { - type = mAdapter.getItemViewType(adjPosition); - } else { - if (mCachePlaceHoldView) { - type = adapterViewTypeStart + mHeaderViewInfos.size() + 1; - } - } - } - } - - if (mCachePlaceHoldView) { - // Footer - final int footerPosition = adjPosition - adapterCount; - if (footerPosition >= 0 && footerPosition < getCount() && (footerPosition % mNumColumns) != 0) { - type = adapterViewTypeStart + mHeaderViewInfos.size() + 1 + (footerPosition / mNumColumns + 1); - } - } - if (DEBUG) { - Log.d(LOG_TAG, String.format("getItemViewType: pos: %s, result: %s", position, type, mCachePlaceHoldView, mCacheFirstHeaderView)); - } - return type; - } - - /** - * content view, content view holder, header[0], header and footer placeholder(s) - * - * @return - */ - @Override - public int getViewTypeCount() { - int count = mAdapter == null ? 1 : mAdapter.getViewTypeCount(); - if (mCachePlaceHoldView) { - int offset = mHeaderViewInfos.size() + 1 + mFooterViewInfos.size(); - if (mCacheFirstHeaderView) { - offset += 1; - } - count += offset; - } - if (DEBUG) { - Log.d(LOG_TAG, String.format("getViewTypeCount: %s", count)); - } - return count; - } - - @Override - public void registerDataSetObserver(DataSetObserver observer) { - mDataSetObservable.registerObserver(observer); - if (mAdapter != null) { - mAdapter.registerDataSetObserver(observer); - } - } - - @Override - public void unregisterDataSetObserver(DataSetObserver observer) { - mDataSetObservable.unregisterObserver(observer); - if (mAdapter != null) { - mAdapter.unregisterDataSetObserver(observer); - } - } - - @Override - public Filter getFilter() { - if (mIsFilterable) { - return ((Filterable) mAdapter).getFilter(); - } - return null; - } - - @Override - public ListAdapter getWrappedAdapter() { - return mAdapter; - } - - public void notifyDataSetChanged() { - mDataSetObservable.notifyChanged(); - } - } -} diff --git a/src/github/daneren2005/dsub/view/MyLeadingMarginSpan2.java b/src/github/daneren2005/dsub/view/MyLeadingMarginSpan2.java deleted file mode 100644 index 20281a28..00000000 --- a/src/github/daneren2005/dsub/view/MyLeadingMarginSpan2.java +++ /dev/null @@ -1,34 +0,0 @@ -package github.daneren2005.dsub.view; - -import android.graphics.Canvas; -import android.graphics.Paint; -import android.text.Layout; -import android.text.style.LeadingMarginSpan; - -/** - * Created by Scott on 1/13/2015. - */ -public class MyLeadingMarginSpan2 implements LeadingMarginSpan.LeadingMarginSpan2 { - private int margin; - private int lines; - - public MyLeadingMarginSpan2(int lines, int margin) { - this.margin = margin; - this.lines = lines; - } - - @Override - public int getLeadingMargin(boolean first) { - return first ? margin : 0; - } - - @Override - public int getLeadingMarginLineCount() { - return lines; - } - - @Override - public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, - int top, int baseline, int bottom, CharSequence text, - int start, int end, boolean first, Layout layout) {} -} diff --git a/src/github/daneren2005/dsub/view/MyViewFlipper.java b/src/github/daneren2005/dsub/view/MyViewFlipper.java deleted file mode 100644 index 26a3de08..00000000 --- a/src/github/daneren2005/dsub/view/MyViewFlipper.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.ViewFlipper; - -/** - * Work-around for Android Issue 6191 (http://code.google.com/p/android/issues/detail?id=6191) - * - * @author Sindre Mehus - * @version $Id$ - */ -public class MyViewFlipper extends ViewFlipper { - - public MyViewFlipper(Context context) { - super(context); - } - - public MyViewFlipper(Context context, AttributeSet attrs) { - super(context, attrs); - } - - - @Override - protected void onDetachedFromWindow() { - try { - super.onDetachedFromWindow(); - } - catch (IllegalArgumentException e) { - // Call stopFlipping() in order to kick off updateRunning() - stopFlipping(); - } - } -} - diff --git a/src/github/daneren2005/dsub/view/PlaylistSongView.java b/src/github/daneren2005/dsub/view/PlaylistSongView.java deleted file mode 100644 index 53e9fafc..00000000 --- a/src/github/daneren2005/dsub/view/PlaylistSongView.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; - -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.util.Util; - -public class PlaylistSongView extends UpdateView { - private static final String TAG = PlaylistSongView.class.getSimpleName(); - - private Context context; - private Playlist playlist; - - private TextView titleView; - private TextView countView; - private int count = 0; - private List songs; - - public PlaylistSongView(Context context) { - super(context, false); - this.context = context; - LayoutInflater.from(context).inflate(R.layout.basic_count_item, this, true); - - titleView = (TextView) findViewById(R.id.basic_count_name); - countView = (TextView) findViewById(R.id.basic_count_count); - } - - protected void setObjectImpl(Object obj1, Object obj2) { - this.playlist = (Playlist) obj1; - this.songs = (List) obj2; - count = 0; - titleView.setText(playlist.getName()); - // Make sure to hide initially so it's not present briefly before update - countView.setVisibility(View.GONE); - } - - @Override - protected void updateBackground() { - // Make sure to reset when starting count - count = 0; - - // Don't try to lookup playlist for Create New - if(!"-1".equals(playlist.getId())) { - MusicDirectory cache = FileUtil.deserialize(context, Util.getCacheName(context, "playlist", playlist.getId()), MusicDirectory.class); - if(cache != null) { - // Try to find song instances in the given playlists - for(MusicDirectory.Entry song: songs) { - if(cache.getChildren().contains(song)) { - count++; - } - } - } - } - } - - @Override - protected void update() { - // Update count display with appropriate information - if(count <= 0) { - countView.setVisibility(View.GONE); - } else { - String displayName; - if(count < 10) { - displayName = "0" + count; - } else { - displayName = "" + count; - } - - countView.setText(displayName); - countView.setVisibility(View.VISIBLE); - } - } -} diff --git a/src/github/daneren2005/dsub/view/PlaylistView.java b/src/github/daneren2005/dsub/view/PlaylistView.java deleted file mode 100644 index 8b5e8ca9..00000000 --- a/src/github/daneren2005/dsub/view/PlaylistView.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Playlist; -import github.daneren2005.dsub.util.SyncUtil; - -/** - * Used to display albums in a {@code ListView}. - * - * @author Sindre Mehus - */ -public class PlaylistView extends UpdateView { - private static final String TAG = PlaylistView.class.getSimpleName(); - - private Context context; - private Playlist playlist; - - private TextView titleView; - - public PlaylistView(Context context) { - super(context); - this.context = context; - LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); - - titleView = (TextView) findViewById(R.id.item_name); - starButton = (ImageButton) findViewById(R.id.item_star); - starButton.setFocusable(false); - moreButton = (ImageView) findViewById(R.id.item_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - } - - protected void setObjectImpl(Object obj) { - this.playlist = (Playlist) obj; - titleView.setText(playlist.getName()); - } - - @Override - protected void updateBackground() { - pinned = SyncUtil.isSyncedPlaylist(context, playlist.getId()); - } -} diff --git a/src/github/daneren2005/dsub/view/PodcastChannelView.java b/src/github/daneren2005/dsub/view/PodcastChannelView.java deleted file mode 100644 index 0e773d14..00000000 --- a/src/github/daneren2005/dsub/view/PodcastChannelView.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.PodcastChannel; -import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.util.FileUtil; -import java.io.File; - -public class PodcastChannelView extends UpdateView { - private static final String TAG = PodcastChannelView.class.getSimpleName(); - - private Context context; - private PodcastChannel channel; - private File file; - - private TextView titleView; - - public PodcastChannelView(Context context) { - super(context); - this.context = context; - LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); - - titleView = (TextView) findViewById(R.id.item_name); - starButton = (ImageButton) findViewById(R.id.item_star); - starButton.setFocusable(false); - moreButton = (ImageView) findViewById(R.id.item_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - } - - protected void setObjectImpl(Object obj) { - channel = (PodcastChannel) obj; - if(channel.getName() != null) { - titleView.setText(channel.getName()); - } else { - titleView.setText(channel.getUrl()); - } - file = FileUtil.getPodcastDirectory(context, channel); - } - - @Override - protected void updateBackground() { - if(SyncUtil.isSyncedPodcast(context, channel.getId())) { - if(exists) { - shaded = false; - exists = false; - } - pinned = true; - } else if(file.exists()) { - if(pinned) { - shaded = false; - pinned = false; - } - exists = true; - } else { - pinned = false; - exists = false; - } - } -} diff --git a/src/github/daneren2005/dsub/view/RecyclingImageView.java b/src/github/daneren2005/dsub/view/RecyclingImageView.java deleted file mode 100644 index 0c85697f..00000000 --- a/src/github/daneren2005/dsub/view/RecyclingImageView.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2015 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.view; - -import android.annotation.TargetApi; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.TransitionDrawable; -import android.os.Build; -import android.util.AttributeSet; -import android.widget.ImageView; - -public class RecyclingImageView extends ImageView { - public RecyclingImageView(Context context) { - super(context); - } - - public RecyclingImageView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public RecyclingImageView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public RecyclingImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - @Override - public void onDraw(Canvas canvas) { - Drawable drawable = this.getDrawable(); - if(drawable != null) { - if(drawable instanceof BitmapDrawable) { - if (isBitmapRecycled(drawable)) { - this.setImageDrawable(null); - } - } else if(drawable instanceof TransitionDrawable) { - TransitionDrawable transitionDrawable = (TransitionDrawable) drawable; - - // If last bitmap in chain is recycled, just blank this out since it would be invalid anyways - Drawable lastDrawable = transitionDrawable.getDrawable(transitionDrawable.getNumberOfLayers() - 1); - if(isBitmapRecycled(lastDrawable)) { - this.setImageDrawable(null); - } else { - // Go through earlier bitmaps and make sure that they are not recycled - for (int i = 0; i < transitionDrawable.getNumberOfLayers(); i++) { - Drawable layerDrawable = transitionDrawable.getDrawable(i); - if (isBitmapRecycled(layerDrawable)) { - // If anything in the chain is broken, just get rid of transition and go to last drawable - this.setImageDrawable(lastDrawable); - break; - } - } - } - } - } - - super.onDraw(canvas); - } - - private boolean isBitmapRecycled(Drawable drawable) { - if(!(drawable instanceof BitmapDrawable)) { - return false; - } - - BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; - if (bitmapDrawable.getBitmap() != null && bitmapDrawable.getBitmap().isRecycled()) { - return true; - } else { - return false; - } - } -} diff --git a/src/github/daneren2005/dsub/view/SeekBarPreference.java b/src/github/daneren2005/dsub/view/SeekBarPreference.java deleted file mode 100644 index a22d049b..00000000 --- a/src/github/daneren2005/dsub/view/SeekBarPreference.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2012 Christopher Eby - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.content.res.TypedArray; -import android.preference.DialogPreference; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.widget.SeekBar; -import android.widget.TextView; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.util.Constants; - -/** - * SeekBar preference to set the shake force threshold. - */ -public class SeekBarPreference extends DialogPreference implements SeekBar.OnSeekBarChangeListener { - private static final String TAG = SeekBarPreference.class.getSimpleName(); - /** - * The current value. - */ - private String mValue; - private int mMin; - private int mMax; - private float mStepSize; - private String mDisplay; - - /** - * Our context (needed for getResources()) - */ - private Context mContext; - - /** - * TextView to display current threshold. - */ - private TextView mValueText; - - public SeekBarPreference(Context context, AttributeSet attrs) - { - super(context, attrs); - mContext = context; - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SeekBarPreference); - mMin = a.getInteger(R.styleable.SeekBarPreference_min, 0); - mMax = a.getInteger(R.styleable.SeekBarPreference_max, 100); - mStepSize = a.getFloat(R.styleable.SeekBarPreference_stepSize, 1f); - mDisplay = a.getString(R.styleable.SeekBarPreference_display); - if(mDisplay == null) { - mDisplay = "%.0f"; - } - } - - @Override - public CharSequence getSummary() - { - return getSummary(mValue); - } - - @Override - protected Object onGetDefaultValue(TypedArray a, int index) - { - return a.getString(index); - } - - @Override - protected void onSetInitialValue(boolean restoreValue, Object defaultValue) - { - mValue = restoreValue ? getPersistedString((String) defaultValue) : (String)defaultValue; - } - - /** - * Create the summary for the given value. - * - * @param value The force threshold. - * @return A string representation of the threshold. - */ - private String getSummary(String value) { - try { - int val = Integer.parseInt(value); - return String.format(mDisplay, (val + mMin) / mStepSize); - } catch (Exception e) { - return ""; - } - } - - @Override - protected View onCreateDialogView() - { - View view = super.onCreateDialogView(); - - mValueText = (TextView)view.findViewById(R.id.value); - mValueText.setText(getSummary(mValue)); - - SeekBar seekBar = (SeekBar)view.findViewById(R.id.seek_bar); - seekBar.setMax(mMax - mMin); - try { - seekBar.setProgress(Integer.parseInt(mValue)); - } catch(Exception e) { - seekBar.setProgress(0); - } - seekBar.setOnSeekBarChangeListener(this); - - return view; - } - - @Override - protected void onDialogClosed(boolean positiveResult) - { - if(positiveResult) { - persistString(mValue); - notifyChanged(); - } - } - - @Override - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) - { - if (fromUser) { - mValue = String.valueOf(progress); - mValueText.setText(getSummary(mValue)); - } - } - - @Override - public void onStartTrackingTouch(SeekBar seekBar) - { - } - - @Override - public void onStopTrackingTouch(SeekBar seekBar) - { - } -} diff --git a/src/github/daneren2005/dsub/view/SettingView.java b/src/github/daneren2005/dsub/view/SettingView.java deleted file mode 100644 index 95452408..00000000 --- a/src/github/daneren2005/dsub/view/SettingView.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.CheckedTextView; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.User; - -import static github.daneren2005.dsub.domain.User.Setting; - -public class SettingView extends UpdateView { - Setting setting; - - CheckedTextView view; - - public SettingView(Context context) { - super(context, false); - this.context = context; - LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_multiple_choice, this, true); - - view = (CheckedTextView) findViewById(android.R.id.text1); - } - - protected void setObjectImpl(Object obj, Object editable) { - this.setting = (Setting) obj; - - // Can't edit non-role parts - String name = setting.getName(); - if(name.indexOf("Role") == -1) { - editable = false; - } - - int res = -1; - if(User.SCROBBLING.equals(name)) { - res = R.string.admin_scrobblingEnabled; - } else if(User.ADMIN.equals(name)) { - res = R.string.admin_role_admin; - } else if(User.SETTINGS.equals(name)) { - res = R.string.admin_role_settings; - } else if(User.DOWNLOAD.equals(name)) { - res = R.string.admin_role_download; - } else if(User.UPLOAD.equals(name)) { - res = R.string.admin_role_upload; - } else if(User.COVERART.equals(name)) { - res = R.string.admin_role_coverArt; - } else if(User.COMMENT.equals(name)) { - res = R.string.admin_role_comment; - } else if(User.PODCAST.equals(name)) { - res = R.string.admin_role_podcast; - } else if(User.STREAM.equals(name)) { - res = R.string.admin_role_stream; - } else if(User.JUKEBOX.equals(name)) { - res = R.string.admin_role_jukebox; - } else if(User.SHARE.equals(name)) { - res = R.string.admin_role_share; - } else if(User.LASTFM.equals(name)) { - res = R.string.admin_role_lastfm; - } else { - // Last resort to display the raw value - view.setText(name); - } - - if(res != -1) { - view.setText(res); - } - - if(setting.getValue()) { - view.setChecked(setting.getValue()); - } else { - view.setChecked(false); - } - - if((Boolean) editable) { - view.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - view.toggle(); - setting.setValue(view.isChecked()); - } - }); - } else { - view.setOnClickListener(null); - } - } -} diff --git a/src/github/daneren2005/dsub/view/ShareView.java b/src/github/daneren2005/dsub/view/ShareView.java deleted file mode 100644 index 2b2fbee4..00000000 --- a/src/github/daneren2005/dsub/view/ShareView.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; - -import java.text.SimpleDateFormat; -import java.util.Locale; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.Share; - -public class ShareView extends UpdateView { - private static final String TAG = ShareView.class.getSimpleName(); - - private TextView titleView; - private TextView descriptionView; - - public ShareView(Context context) { - super(context, false); - LayoutInflater.from(context).inflate(R.layout.complex_list_item, this, true); - - titleView = (TextView) findViewById(R.id.item_name); - descriptionView = (TextView) findViewById(R.id.item_description); - starButton = (ImageButton) findViewById(R.id.item_star); - starButton.setFocusable(false); - moreButton = (ImageView) findViewById(R.id.item_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - } - - public void setObjectImpl(Object obj) { - Share share = (Share) obj; - titleView.setText(share.getName()); - if(share.getExpires() != null) { - descriptionView.setText(context.getResources().getString(R.string.share_expires, new SimpleDateFormat("E MMM d, yyyy", Locale.ENGLISH).format(share.getExpires()))); - } else { - descriptionView.setText(context.getResources().getString(R.string.share_expires_never)); - } - } -} diff --git a/src/github/daneren2005/dsub/view/SongView.java b/src/github/daneren2005/dsub/view/SongView.java deleted file mode 100644 index 2fbaedc3..00000000 --- a/src/github/daneren2005/dsub/view/SongView.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.*; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.DownloadFile; -import github.daneren2005.dsub.util.Util; - -import java.io.File; - -/** - * Used to display songs in a {@code ListView}. - * - * @author Sindre Mehus - */ -public class SongView extends UpdateView implements Checkable { - private static final String TAG = SongView.class.getSimpleName(); - - private MusicDirectory.Entry song; - - private CheckedTextView checkedTextView; - private TextView titleTextView; - private TextView artistTextView; - private TextView durationTextView; - private TextView statusTextView; - private ImageView statusImageView; - private ImageView bookmarkButton; - private View bottomRowView; - - private DownloadService downloadService; - private long revision = -1; - private DownloadFile downloadFile; - private boolean dontChangeDownloadFile = false; - - private boolean playing = false; - private boolean rightImage = false; - private int moreImage = 0; - private boolean isWorkDone = false; - private boolean isSaved = false; - private File partialFile; - private boolean partialFileExists = false; - private boolean loaded = false; - private boolean isBookmarked = false; - private boolean bookmarked = false; - - public SongView(Context context) { - super(context); - LayoutInflater.from(context).inflate(R.layout.song_list_item, this, true); - - checkedTextView = (CheckedTextView) findViewById(R.id.song_check); - titleTextView = (TextView) findViewById(R.id.song_title); - artistTextView = (TextView) findViewById(R.id.song_artist); - durationTextView = (TextView) findViewById(R.id.song_duration); - statusTextView = (TextView) findViewById(R.id.song_status); - statusImageView = (ImageView) findViewById(R.id.song_status_icon); - ratingBar = (RatingBar) findViewById(R.id.song_rating); - starButton = (ImageButton) findViewById(R.id.song_star); - starButton.setFocusable(false); - bookmarkButton = (ImageButton) findViewById(R.id.song_bookmark); - bookmarkButton.setFocusable(false); - moreButton = (ImageView) findViewById(R.id.artist_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - bottomRowView = findViewById(R.id.song_bottom); - } - - public void setObjectImpl(Object obj1, Object obj2) { - this.song = (MusicDirectory.Entry) obj1; - boolean checkable = (Boolean) obj2; - - StringBuilder artist = new StringBuilder(40); - - boolean isPodcast = song instanceof PodcastEpisode; - if(!song.isVideo() || isPodcast) { - if(isPodcast) { - String date = ((PodcastEpisode)song).getDate(); - if(date != null) { - int index = date.indexOf(" "); - artist.append(date.substring(0, index != -1 ? index : date.length())); - } - } - else if(song.getArtist() != null) { - artist.append(song.getArtist()); - } - - if(isPodcast) { - String status = ((PodcastEpisode) song).getStatus(); - int statusRes = -1; - - if("error".equals(status)) { - statusRes = R.string.song_details_error; - } else if("skipped".equals(status)) { - statusRes = R.string.song_details_skipped; - } else if("downloading".equals(status)) { - statusRes = R.string.song_details_downloading; - } - - if(statusRes != -1) { - artist.append(" ("); - artist.append(getContext().getString(statusRes)); - artist.append(")"); - } - } - - durationTextView.setText(Util.formatDuration(song.getDuration())); - bottomRowView.setVisibility(View.VISIBLE); - } else { - bottomRowView.setVisibility(View.GONE); - statusTextView.setText(Util.formatDuration(song.getDuration())); - } - - String title = song.getTitle(); - Integer track = song.getTrack(); - if(track != null && Util.getDisplayTrack(context)) { - title = String.format("%02d", track) + " " + title; - } - - titleTextView.setText(title); - artistTextView.setText(artist); - checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE); - - this.setBackgroundColor(0x00000000); - ratingBar.setVisibility(View.GONE); - rating = 0; - - revision = -1; - loaded = false; - dontChangeDownloadFile = false; - } - - public void setDownloadFile(DownloadFile downloadFile) { - this.downloadFile = downloadFile; - dontChangeDownloadFile = true; - } - - public DownloadFile getDownloadFile() { - return downloadFile; - } - - @Override - protected void updateBackground() { - if (downloadService == null) { - downloadService = DownloadService.getInstance(); - if(downloadService == null) { - return; - } - } - - long newRevision = downloadService.getDownloadListUpdateRevision(); - if((revision != newRevision && dontChangeDownloadFile == false) || downloadFile == null) { - downloadFile = downloadService.forSong(song); - revision = newRevision; - } - - isWorkDone = downloadFile.isWorkDone(); - isSaved = downloadFile.isSaved(); - partialFile = downloadFile.getPartialFile(); - partialFileExists = partialFile.exists(); - isStarred = song.isStarred(); - isBookmarked = song.getBookmark() != null; - isRated = song.getRating(); - - // Check if needs to load metadata: check against all fields that we know are null in offline mode - if(song.getBitRate() == null && song.getDuration() == null && song.getDiscNumber() == null && isWorkDone) { - song.loadMetadata(downloadFile.getCompleteFile()); - loaded = true; - } - } - - @Override - protected void update() { - if(loaded) { - setObjectImpl(song, checkedTextView.getVisibility() == View.VISIBLE); - } - if (downloadService == null || downloadFile == null) { - return; - } - - if(song.isStarred()) { - if(!starred) { - starButton.setVisibility(View.VISIBLE); - starred = true; - } - } else { - if(starred) { - starButton.setVisibility(View.GONE); - starred = false; - } - } - - if (isWorkDone) { - int moreImage = isSaved ? R.drawable.download_pinned : R.drawable.download_cached; - if(moreImage != this.moreImage) { - moreButton.setImageResource(moreImage); - this.moreImage = moreImage; - } - } else if(this.moreImage != R.drawable.download_none_light) { - int[] attrs = new int[] {R.attr.download_none}; - TypedArray typedArray = context.obtainStyledAttributes(attrs); - moreButton.setImageResource(typedArray.getResourceId(0, 0)); - typedArray.recycle(); - this.moreImage = R.drawable.download_none_light; - } - - if (downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && partialFileExists) { - double percentage = (partialFile.length() * 100.0) / downloadFile.getEstimatedSize(); - percentage = Math.min(percentage, 100); - statusTextView.setText((int)percentage + " %"); - if(!rightImage) { - statusImageView.setVisibility(View.VISIBLE); - rightImage = true; - } - } else if(rightImage) { - statusTextView.setText(null); - statusImageView.setVisibility(View.GONE); - rightImage = false; - } - - boolean playing = downloadService.getCurrentPlaying() == downloadFile; - if (playing) { - if(!this.playing) { - this.playing = playing; - int[] attrs = new int[] {R.attr.media_button_start}; - TypedArray typedArray = context.obtainStyledAttributes(attrs); - titleTextView.setCompoundDrawablesWithIntrinsicBounds(typedArray.getResourceId(0, 0), 0, 0, 0); - } - } else { - if(this.playing) { - this.playing = playing; - titleTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); - } - } - - if(isBookmarked) { - if(!bookmarked) { - bookmarkButton.setVisibility(View.VISIBLE); - bookmarked = true; - } - } else { - if(bookmarked) { - bookmarkButton.setVisibility(View.GONE); - bookmarked = false; - } - } - - if(isRated != rating) { - if(isRated > 1) { - if(rating <= 1) { - ratingBar.setVisibility(View.VISIBLE); - } - - ratingBar.setNumStars(isRated); - ratingBar.setRating(isRated); - } else if(isRated <= 1) { - if(rating > 1) { - ratingBar.setVisibility(View.GONE); - } - } - - // Still highlight red if a 1-star - if(isRated == 1) { - this.setBackgroundColor(Color.RED); - this.getBackground().setAlpha(20); - } else if(rating == 1) { - this.setBackgroundColor(0x00000000); - } - - rating = isRated; - } - } - - @Override - public void setChecked(boolean b) { - checkedTextView.setChecked(b); - } - - @Override - public boolean isChecked() { - return checkedTextView.isChecked(); - } - - @Override - public void toggle() { - checkedTextView.toggle(); - } - - public MusicDirectory.Entry getEntry() { - return song; - } -} diff --git a/src/github/daneren2005/dsub/view/SquareImageView.java b/src/github/daneren2005/dsub/view/SquareImageView.java deleted file mode 100644 index 44a74e16..00000000 --- a/src/github/daneren2005/dsub/view/SquareImageView.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.ImageView; - -public class SquareImageView extends RecyclingImageView { - public SquareImageView(final Context context, final AttributeSet attrs) { - super(context, attrs); - } - - @Override - public void onMeasure(final int widthSpec, final int heightSpec) { - super.onMeasure(widthSpec, heightSpec); - setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth()); - } -} diff --git a/src/github/daneren2005/dsub/view/UnscrollableGridView.java b/src/github/daneren2005/dsub/view/UnscrollableGridView.java deleted file mode 100644 index 1e18f032..00000000 --- a/src/github/daneren2005/dsub/view/UnscrollableGridView.java +++ /dev/null @@ -1,128 +0,0 @@ -package github.daneren2005.dsub.view; - -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.widget.AbsListView; -import android.widget.GridView; -import android.widget.ListAdapter; - -import java.lang.reflect.Field; - -/** - * Created by Scott on 4/26/2014. - */ -public class UnscrollableGridView extends GridView { - private static final String TAG = UnscrollableGridView.class.getSimpleName(); - - public UnscrollableGridView(Context context) { - super(context); - } - - public UnscrollableGridView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public UnscrollableGridView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - public int getColumnWidth() { - // This method will be called from onMeasure() too. - // It's better to use getMeasuredWidth(), as it is safe in this case. - - int hSpacing = 20; - try { - Field field = GridView.class.getDeclaredField("mHorizontalSpacing"); - field.setAccessible(true); - hSpacing = field.getInt(this); - } catch(Exception e) { - - } - - final int totalHorizontalSpacing = getNumColumnsCompat() > 0 ? (getNumColumnsCompat() - 1) * hSpacing : 0; - return (getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - totalHorizontalSpacing) / getNumColumnsCompat(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // Sets the padding for this view. - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - - final int measuredWidth = getMeasuredWidth(); - final int childWidth = getColumnWidth(); - int childHeight = 0; - - // If there's an adapter, use it to calculate the height of this view. - final ListAdapter adapter = getAdapter(); - final int count; - - // There shouldn't be any inherent size (due to padding) if there are no child views. - if (adapter == null || (count = adapter.getCount()) == 0) { - setMeasuredDimension(0, 0); - return; - } - - // Get the first child from the adapter. - final View child = adapter.getView(0, null, this); - if (child != null) { - // Set a default LayoutParams on the child, if it doesn't have one on its own. - AbsListView.LayoutParams params = (AbsListView.LayoutParams) child.getLayoutParams(); - if (params == null) { - params = new AbsListView.LayoutParams(AbsListView.LayoutParams.WRAP_CONTENT, - AbsListView.LayoutParams.WRAP_CONTENT); - child.setLayoutParams(params); - } - - // Measure the exact width of the child, and the height based on the width. - // Note: the child takes care of calculating its height. - int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY); - int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - child.measure(childWidthSpec, childHeightSpec); - childHeight = child.getMeasuredHeight(); - } - - int vSpacing = 10; - try { - Field field = GridView.class.getDeclaredField("mVerticalSpacing"); - field.setAccessible(true); - vSpacing = field.getInt(this); - } catch(Exception e) { - - } - - // Number of rows required to 'mTotal' items. - final int rows = (int) Math.ceil((double) getCount() / getNumColumnsCompat()); - final int childrenHeight = childHeight * rows; - final int totalVerticalSpacing = rows > 0 ? (rows - 1) * vSpacing : 0; - - // Total height of this view. - final int measuredHeight = Math.abs(childrenHeight + getPaddingTop() + getPaddingBottom() + totalVerticalSpacing); - setMeasuredDimension(measuredWidth, measuredHeight); - } - - private int getNumColumnsCompat() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - return getNumColumnsCompat11(); - } else { - int columns = 0; - int children = getChildCount(); - if (children > 0) { - int width = getChildAt(0).getMeasuredWidth(); - if (width > 0) { - columns = getWidth() / width; - } - } - return columns > 0 ? columns : AUTO_FIT; - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - private int getNumColumnsCompat11() { - return getNumColumns(); - } -} diff --git a/src/github/daneren2005/dsub/view/UpdateView.java b/src/github/daneren2005/dsub/view/UpdateView.java deleted file mode 100644 index c491fc6d..00000000 --- a/src/github/daneren2005/dsub/view/UpdateView.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see . - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.os.Handler; -import android.os.Looper; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RatingBar; - -import java.util.ArrayList; -import java.util.List; -import java.util.WeakHashMap; - -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.util.SilentBackgroundTask; - -public class UpdateView extends LinearLayout { - private static final String TAG = UpdateView.class.getSimpleName(); - private static final WeakHashMap INSTANCES = new WeakHashMap(); - - private static Handler backgroundHandler; - private static Handler uiHandler; - private static Runnable updateRunnable; - private static int activeActivities = 0; - - protected Context context; - protected RatingBar ratingBar; - protected ImageButton starButton; - protected ImageView moreButton; - - protected boolean exists = false; - protected boolean pinned = false; - protected boolean shaded = false; - protected boolean starred = false; - protected boolean isStarred = false; - protected int isRated = 0; - protected int rating = 0; - protected SilentBackgroundTask imageTask = null; - - protected final boolean autoUpdate; - - public UpdateView(Context context) { - this(context, true); - } - public UpdateView(Context context, boolean autoUpdate) { - super(context); - this.context = context; - this.autoUpdate = autoUpdate; - - setLayoutParams(new AbsListView.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - - if(autoUpdate) { - INSTANCES.put(this, null); - } - startUpdater(); - } - - @Override - public void setPressed(boolean pressed) { - - } - - public void setObject(Object obj) { - setObjectImpl(obj); - updateBackground(); - update(); - } - public void setObject(Object obj1, Object obj2) { - if(imageTask != null) { - imageTask.cancel(); - imageTask = null; - } - - setObjectImpl(obj1, obj2); - backgroundHandler.post(new Runnable() { - @Override - public void run() { - updateBackground(); - uiHandler.post(new Runnable() { - @Override - public void run() { - update(); - } - }); - } - }); - } - protected void setObjectImpl(Object obj) { - - } - protected void setObjectImpl(Object obj1, Object obj2) { - - } - - private static synchronized void startUpdater() { - if(uiHandler != null) { - return; - } - - uiHandler = new Handler(); - // Needed so handler is never null until thread creates it - backgroundHandler = uiHandler; - updateRunnable = new Runnable() { - @Override - public void run() { - updateAll(); - } - }; - - new Thread(new Runnable() { - public void run() { - Looper.prepare(); - backgroundHandler = new Handler(Looper.myLooper()); - uiHandler.post(updateRunnable); - Looper.loop(); - } - }, "UpdateView").start(); - } - - public static synchronized void triggerUpdate() { - if(backgroundHandler != null) { - uiHandler.removeCallbacksAndMessages(null); - backgroundHandler.removeCallbacksAndMessages(null); - uiHandler.post(updateRunnable); - } - } - - private static void updateAll() { - try { - // If nothing can see this, stop updating - if(activeActivities == 0) { - activeActivities--; - return; - } - - List views = new ArrayList(); - for (UpdateView view : INSTANCES.keySet()) { - if (view.isShown()) { - views.add(view); - } - } - if(views.size() > 0) { - updateAllLive(views); - } else { - uiHandler.postDelayed(updateRunnable, 2000L); - } - } catch (Throwable x) { - Log.w(TAG, "Error when updating song views.", x); - } - } - private static void updateAllLive(final List views) { - final Runnable runnable = new Runnable() { - @Override - public void run() { - try { - for(UpdateView view: views) { - view.update(); - } - } catch (Throwable x) { - Log.w(TAG, "Error when updating song views.", x); - } - uiHandler.postDelayed(updateRunnable, 1000L); - } - }; - - backgroundHandler.post(new Runnable() { - @Override - public void run() { - try { - for(UpdateView view: views) { - view.updateBackground(); - } - uiHandler.post(runnable); - } catch (Throwable x) { - Log.w(TAG, "Error when updating song views.", x); - } - } - }); - } - - public static void addActiveActivity() { - activeActivities++; - - if(activeActivities == 0 && uiHandler != null && updateRunnable != null) { - activeActivities++; - uiHandler.post(updateRunnable); - } - } - public static void removeActiveActivity() { - activeActivities--; - } - - public static MusicDirectory.Entry findEntry(MusicDirectory.Entry entry) { - for(UpdateView view: INSTANCES.keySet()) { - MusicDirectory.Entry check = null; - if(view instanceof SongView) { - check = ((SongView) view).getEntry(); - } else if(view instanceof AlbumCell) { - check = ((AlbumCell) view).getEntry(); - } else if(view instanceof AlbumView) { - check = ((AlbumView) view).getEntry(); - } - - if(check != null && entry != check && check.getId().equals(entry.getId())) { - return check; - } - } - - return null; - } - - protected void updateBackground() { - - } - protected void update() { - if(moreButton != null) { - if(exists || pinned) { - if(!shaded) { - moreButton.setImageResource(exists ? R.drawable.download_cached : R.drawable.download_pinned); - shaded = true; - } - } else { - if(shaded) { - int[] attrs = new int[] {R.attr.download_none}; - TypedArray typedArray = context.obtainStyledAttributes(attrs); - moreButton.setImageResource(typedArray.getResourceId(0, 0)); - shaded = false; - } - } - } - - if(starButton != null) { - if(isStarred) { - if(!starred) { - starButton.setVisibility(View.VISIBLE); - starred = true; - } - } else { - if(starred) { - starButton.setVisibility(View.GONE); - starred = false; - } - } - } - - if(ratingBar != null && isRated != rating) { - if(isRated > 0 && rating == 0) { - ratingBar.setVisibility(View.VISIBLE); - } else if(isRated == 0 && rating > 0) { - ratingBar.setVisibility(View.GONE); - } - - ratingBar.setRating(isRated); - rating = isRated; - } - } -} diff --git a/src/github/daneren2005/dsub/view/UserView.java b/src/github/daneren2005/dsub/view/UserView.java deleted file mode 100644 index 1a0192a1..00000000 --- a/src/github/daneren2005/dsub/view/UserView.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic 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 - (at your option) any later version. - Subsonic 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 Subsonic. If not, see . - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.User; -import github.daneren2005.dsub.util.ImageLoader; - -public class UserView extends UpdateView { - private User user; - - private TextView usernameView; - private ImageView avatarView; - - public UserView(Context context) { - super(context, false); - this.context = context; - LayoutInflater.from(context).inflate(R.layout.user_list_item, this, true); - - usernameView = (TextView) findViewById(R.id.item_name); - avatarView = (ImageView) findViewById(R.id.item_avatar); - moreButton = (ImageView) findViewById(R.id.item_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - } - - protected void setObjectImpl(Object obj, Object obj2) { - this.user = (User) obj; - usernameView.setText(user.getUsername()); - imageTask = ((ImageLoader)obj2).loadAvatar(context, avatarView, user.getUsername()); - } -} -- cgit v1.2.3