Make StreamProxy optional, prepareAsync for MediaPlayer, code fixups in StreamProxy
This commit is contained in:
parent
d8418254ef
commit
793f5b4464
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:a="http://schemas.android.com/apk/res/android"
|
||||
package="net.sourceforge.subsonic.androidapp"
|
||||
a:versionCode="59"
|
||||
a:versionName="3.9.9.18" a:installLocation="auto">
|
||||
a:versionCode="61"
|
||||
a:versionName="3.9.9.20" a:installLocation="auto">
|
||||
|
||||
<uses-permission a:name="android.permission.INTERNET"/>
|
||||
<uses-permission a:name="android.permission.READ_PHONE_STATE"/>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,309 +1,311 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="common.appname">Subsonic</string>
|
||||
<string name="common.ok">OK</string>
|
||||
<string name="common.save">Save</string>
|
||||
<string name="common.cancel">Cancel</string>
|
||||
<string name="common.play_now">Play Now</string>
|
||||
<string name="common.play_next">Play Next</string>
|
||||
<string name="common.play_last">Play Last</string>
|
||||
<string name="common.pin">Pin</string>
|
||||
<string name="common.unpin">Unpin</string>
|
||||
<string name="common.delete">Delete</string>
|
||||
|
||||
<string name="button_bar.home">Subsonic Home</string>
|
||||
<string name="button_bar.browse">Media Library</string>
|
||||
<string name="button_bar.search">Search</string>
|
||||
<string name="button_bar.playlists">Playlists</string>
|
||||
<string name="button_bar.now_playing">Now Playing</string>
|
||||
|
||||
<string name="main.welcome_title">Welcome!</string>
|
||||
<string name="main.welcome_text">Welcome to Subsonic! The app is currently configured to use the Subsonic demo server. After you\'ve
|
||||
set up your personal server (available from <b>subsonic.org</b>), please go to <b>Settings</b> and change the configuration to connect to it.</string>
|
||||
<string name="main.select_server">Select Server</string>
|
||||
<string name="main.shuffle">Shuffle Play</string>
|
||||
<string name="main.offline">Offline</string>
|
||||
<string name="main.settings">Settings</string>
|
||||
<string name="main.albums_title">Albums</string>
|
||||
<string name="main.albums_newest">Recently Added</string>
|
||||
<string name="main.albums_recent">Recently Played</string>
|
||||
<string name="main.albums_frequent">Most Played</string>
|
||||
<string name="main.albums_highest">Top Rated</string>
|
||||
<string name="main.albums_random">Random</string>
|
||||
<string name="main.albums_starred">Starred Albums</string>
|
||||
<string name="main.albums_alphaByName">By Name</string>
|
||||
<string name="main.albums_alphaByArtist">By Artist</string>
|
||||
<string name="main.songs_title">Songs</string>
|
||||
<string name="main.songs_starred">Starred Songs</string>
|
||||
|
||||
<string name="menu.exit">Exit</string>
|
||||
<string name="menu.settings">Settings</string>
|
||||
<string name="menu.help">Help</string>
|
||||
<string name="menu.search">Search</string>
|
||||
|
||||
<string name="playlist.label">Playlists</string>
|
||||
|
||||
<string name="help.label">Help</string>
|
||||
<string name="help.title">Welcome to Subsonic!</string>
|
||||
<string name="help.back">Back</string>
|
||||
<string name="help.close">Close</string>
|
||||
<string name="help.url">file:///android_asset/html/en/index.html</string>
|
||||
<string name="help.loading">Loading…</string>
|
||||
|
||||
<string name="play_video.loading">Loading video…</string>
|
||||
<string name="play_video.noplugin">Please install Adobe Flash Player from Android Market.</string>
|
||||
|
||||
<string name="search.label">Search</string>
|
||||
<string name="search.title">Search</string>
|
||||
<string name="search.search">Click to search</string>
|
||||
<string name="search.no_match">No matches, please try again</string>
|
||||
<string name="search.artists">Artists</string>
|
||||
<string name="search.albums">Albums</string>
|
||||
<string name="search.songs">Songs</string>
|
||||
<string name="search.more">Show More</string>
|
||||
|
||||
<string name="progress.wait">Please wait…</string>
|
||||
|
||||
<string name="music_library.label">Media Library</string>
|
||||
<string name="music_library.label_offline">Offline Media</string>
|
||||
|
||||
<string name="select_album.empty">No media found</string>
|
||||
<string name="select_album.select">Select All</string>
|
||||
<string name="select_album.n_selected">%d tracks selected.</string>
|
||||
<string name="select_album.n_unselected">%d tracks unselected.</string>
|
||||
<string name="select_album.more">More</string>
|
||||
<string name="select_album.offline">Offline</string>
|
||||
<string name="select_album.searching">Searching…</string>
|
||||
<string name="select_album.play_all">Play All</string>
|
||||
<string name="select_album.no_sdcard">Error: No SD card available.</string>
|
||||
<string name="select_album.no_network">Warning: No network available.</string>
|
||||
<string name="select_album.not_licensed">Server not licensed. %d trial days left.</string>
|
||||
<string name="select_album.donate_dialog_message">Get unlimited downloads by donating to Subsonic.</string>
|
||||
<string name="select_album.donate_dialog_now">Now</string>
|
||||
<string name="select_album.donate_dialog_later">Later</string>
|
||||
<string name="select_album.donate_dialog_0_trial_days_left">Trial period is over</string>
|
||||
|
||||
|
||||
<string name="select_playlist.empty">No saved playlists on server</string>
|
||||
|
||||
<string name="download.empty">Playlist is empty</string>
|
||||
<string name="download.playerstate_downloading">Downloading - %s</string>
|
||||
<string name="download.playerstate_buffering">Buffering</string>
|
||||
<string name="download.playerstate_playing_shuffle">Playing shuffle</string>
|
||||
<string name="download.menu_show_album">Show Album</string>
|
||||
<string name="download.menu_lyrics">Lyrics</string>
|
||||
<string name="download.menu_remove">Remove Song</string>
|
||||
<string name="download.menu_remove_all">Remove All</string>
|
||||
<string name="download.menu_screen_on">Screen On</string>
|
||||
<string name="download.menu_screen_off">Screen Off</string>
|
||||
<string name="download.menu_shuffle">Shuffle</string>
|
||||
<string name="download.menu_save">Save Playlist</string>
|
||||
<string name="download.menu_equalizer">Equalizer</string>
|
||||
<string name="download.menu_visualizer">Visualizer</string>
|
||||
<string name="download.menu_jukebox">Jukebox</string>
|
||||
<string name="download.menu_shuffle_notification">Playlist was shuffled</string>
|
||||
<string name="download.playlist_title">Save Playlist</string>
|
||||
<string name="download.playlist_name">Enter the playlist name:</string>
|
||||
<string name="download.playlist_saving">Saving playlist \"%s\"…</string>
|
||||
<string name="download.playlist_done">Playlist was successfully saved.</string>
|
||||
<string name="download.playlist_error">Failed to save playlist, please try later.</string>
|
||||
<string name="download.repeat_off">Repeat Off</string>
|
||||
<string name="download.repeat_all">Repeat All</string>
|
||||
<string name="download.repeat_single">Repeat Song</string>
|
||||
<string name="download.visualizer_on">Turned on visualizer.</string>
|
||||
<string name="download.visualizer_off">Turned off visualizer.</string>
|
||||
<string name="download.jukebox_on">Turned on remote control. Music is played on server.</string>
|
||||
<string name="download.jukebox_off">Turned off remote control. Music is played on phone.</string>
|
||||
<string name="download.jukebox_volume">Remote Volume</string>
|
||||
<string name="download.jukebox_server_too_old">Remote control is not supported. Please upgrade your Subsonic server.</string>
|
||||
<string name="download.jukebox_offline">Remote control is not available in offline mode.</string>
|
||||
<string name="download.jukebox_not_authorized">Remote control is not allowed. Please enable jukebox mode in <b>Users > Settings</b> on your Subsonic server.</string>
|
||||
|
||||
<string name="song_details.all">%1$s %2$s</string>
|
||||
<string name="song_details.kbps">%d kbps</string>
|
||||
|
||||
<string name="lyrics.nomatch">No lyrics found</string>
|
||||
|
||||
<string name="error.label">Error</string>
|
||||
|
||||
<string name="settings.title">Subsonic Settings</string>
|
||||
<string name="settings.test_connection_title">Test Connection</string>
|
||||
<string name="settings.servers_title">Servers</string>
|
||||
<string name="settings.server_unused1">Unused 1</string>
|
||||
<string name="settings.server_unused2">Unused 2</string>
|
||||
<string name="settings.server_name">Name</string>
|
||||
<string name="settings.server_address">Server Address</string>
|
||||
<string name="settings.server_username">Username</string>
|
||||
<string name="settings.server_password">Password</string>
|
||||
<string name="settings.cache_title">Music Cache</string>
|
||||
<string name="settings.preload">Songs To Preload</string>
|
||||
<string name="settings.cache_size">Cache Size</string>
|
||||
<string name="settings.cache_location">Cache Location</string>
|
||||
<string name="settings.cache_location_error">Invalid cache location. Using default.</string>
|
||||
<string name="settings.testing_connection">Testing connection…</string>
|
||||
<string name="settings.testing_ok">Connection is OK</string>
|
||||
<string name="settings.testing_unlicensed">Connection is OK. Server unlicensed.</string>
|
||||
<string name="settings.connection_failure">Connection failure.</string>
|
||||
<string name="settings.invalid_url">Please specify a valid URL.</string>
|
||||
<string name="settings.invalid_username">Please specify a valid username (no trailing spaces).</string>
|
||||
<string name="settings.appearance_title">Appearance</string>
|
||||
<string name="settings.theme_title">Theme</string>
|
||||
<string name="settings.theme_fullscreen">Fullscreen Dark</string>
|
||||
<string name="settings.theme_fullscreenlight">Fullscreen Light</string>
|
||||
<string name="settings.theme_light">Light</string>
|
||||
<string name="settings.theme_dark">Dark</string>
|
||||
<string name="settings.network_title">Network</string>
|
||||
<string name="settings.max_bitrate_wifi">Max Bitrate - Wi-Fi</string>
|
||||
<string name="settings.max_bitrate_mobile">Max Bitrate - Mobile</string>
|
||||
<string name="settings.max_bitrate_32">32 Kbps</string>
|
||||
<string name="settings.max_bitrate_64">64 Kbps</string>
|
||||
<string name="settings.max_bitrate_80">80 Kbps</string>
|
||||
<string name="settings.max_bitrate_96">96 Kbps</string>
|
||||
<string name="settings.max_bitrate_112">112 Kbps</string>
|
||||
<string name="settings.max_bitrate_128">128 Kbps</string>
|
||||
<string name="settings.max_bitrate_160">160 Kbps</string>
|
||||
<string name="settings.max_bitrate_192">192 Kbps</string>
|
||||
<string name="settings.max_bitrate_256">256 Kbps</string>
|
||||
<string name="settings.max_bitrate_320">320 Kbps</string>
|
||||
<string name="settings.max_bitrate_unlimited">Unlimited</string>
|
||||
<string name="settings.wifi_required_title">Wi-Fi Streaming Only</string>
|
||||
<string name="settings.wifi_required_summary">Only stream media if connected to Wi-Fi</string>
|
||||
<string name="settings.preload_1">1 song</string>
|
||||
<string name="settings.preload_2">2 songs</string>
|
||||
<string name="settings.preload_3">3 songs</string>
|
||||
<string name="settings.preload_5">5 songs</string>
|
||||
<string name="settings.preload_10">10 songs</string>
|
||||
<string name="settings.preload_unlimited">Unlimited</string>
|
||||
<string name="settings.cache_size_100">100 MB</string>
|
||||
<string name="settings.cache_size_200">200 MB</string>
|
||||
<string name="settings.cache_size_500">500 MB</string>
|
||||
<string name="settings.cache_size_1000">1 GB</string>
|
||||
<string name="settings.cache_size_2000">2 GB</string>
|
||||
<string name="settings.cache_size_5000">5 GB</string>
|
||||
<string name="settings.cache_size_10000">10 GB</string>
|
||||
<string name="settings.cache_size_20000">20 GB</string>
|
||||
<string name="settings.cache_size_unlimited">Unlimited</string>
|
||||
<string name="settings.clear_search_history">Clear Search History</string>
|
||||
<string name="settings.search_history_cleared">Search history cleared</string>
|
||||
<string name="settings.other_title">Other Settings</string>
|
||||
<string name="settings.search_title">Search Settings</string>
|
||||
<string name="settings.scrobble_title">Scrobble To Last.fm</string>
|
||||
<string name="settings.scrobble_summary">Remember to set up your Last.fm user and password on the Subsonic server</string>
|
||||
<string name="settings.hide_media_title">Hide From Other</string>
|
||||
<string name="settings.hide_media_summary">Hide music files from other apps.</string>
|
||||
<string name="settings.hide_media_toast">Takes effect next time Android scans your phone for music.</string>
|
||||
<string name="settings.media_button_title">Media Buttons</string>
|
||||
<string name="settings.media_button_summary">Respond to phone, headset and Bluetooth media buttons</string>
|
||||
<string name="settings.screen_lit_title">Keep Screen On</string>
|
||||
<string name="settings.screen_lit_summary">Keeping the screen on while downloading improves download speed.</string>
|
||||
<string name="settings.buffer_length">Buffer Length</string>
|
||||
<string name="settings.network_timeout">Network Timeout</string>
|
||||
<string name="settings.buffer_length_2">2 seconds</string>
|
||||
<string name="settings.buffer_length_5">5 seconds</string>
|
||||
<string name="settings.buffer_length_8">8 seconds</string>
|
||||
<string name="settings.buffer_length_10">10 seconds</string>
|
||||
<string name="settings.buffer_length_12">12 seconds</string>
|
||||
<string name="settings.buffer_length_15">15 seconds</string>
|
||||
<string name="settings.buffer_length_20">20 seconds</string>
|
||||
<string name="settings.buffer_length_30">30 seconds</string>
|
||||
<string name="settings.network_timeout_15000">15 seconds</string>
|
||||
<string name="settings.network_timeout_30000">30 seconds</string>
|
||||
<string name="settings.network_timeout_45000">45 seconds</string>
|
||||
<string name="settings.network_timeout_60000">60 seconds</string>
|
||||
<string name="settings.network_timeout_75000">75 seconds</string>
|
||||
<string name="settings.network_timeout_90000">90 seconds</string>
|
||||
<string name="settings.network_timeout_105000">105 seconds</string>
|
||||
<string name="settings.network_timeout_120000">120 seconds</string>
|
||||
<string name="settings.show_notification">Show Notification</string>
|
||||
<string name="settings.show_notification_summary">Show now playing notification in the status bar</string>
|
||||
<string name="settings.show_lockscreen_controls">Show Lock Screen Controls</string>
|
||||
<string name="settings.show_lockscreen_controls_summary">Show playback controls on the lock screen</string>
|
||||
<string name="settings.max_albums">Max Albums</string>
|
||||
<string name="settings.max_albums_5">5</string>
|
||||
<string name="settings.max_albums_10">10</string>
|
||||
<string name="settings.max_albums_20">20</string>
|
||||
<string name="settings.max_albums_30">30</string>
|
||||
<string name="settings.max_albums_40">40</string>
|
||||
<string name="settings.max_albums_50">50</string>
|
||||
<string name="settings.max_albums_100">100</string>
|
||||
<string name="settings.max_albums_250">250</string>
|
||||
<string name="settings.max_albums_500">500</string>
|
||||
<string name="settings.max_songs">Max Songs</string>
|
||||
<string name="settings.max_songs_5">5</string>
|
||||
<string name="settings.max_songs_10">10</string>
|
||||
<string name="settings.max_songs_25">25</string>
|
||||
<string name="settings.max_songs_50">50</string>
|
||||
<string name="settings.max_songs_75">75</string>
|
||||
<string name="settings.max_songs_100">100</string>
|
||||
<string name="settings.max_songs_200">200</string>
|
||||
<string name="settings.max_songs_500">500</string>
|
||||
<string name="settings.max_artists">Max Artists</string>
|
||||
<string name="settings.max_artists_3">3</string>
|
||||
<string name="settings.max_artists_5">5</string>
|
||||
<string name="settings.max_artists_10">10</string>
|
||||
<string name="settings.max_artists_25">25</string>
|
||||
<string name="settings.max_artists_50">50</string>
|
||||
<string name="settings.max_artists_75">75</string>
|
||||
<string name="settings.max_artists_100">100</string>
|
||||
<string name="settings.max_artists_200">200</string>
|
||||
<string name="settings.max_artists_500">500</string>
|
||||
<string name="settings.default_artists">Default Artists</string>
|
||||
<string name="settings.default_albums">Default Albums</string>
|
||||
<string name="settings.default_songs">Default Songs</string>
|
||||
|
||||
<string name="music_service.retry">A network error occurred. Retrying %1$d of %2$d.</string>
|
||||
|
||||
<string name="background_task.wait">Please wait…</string>
|
||||
<string name="background_task.loading">Loading.</string>
|
||||
<string name="background_task.no_network">This program requires network access. Please turn on Wi-Fi or mobile network.</string>
|
||||
<string name="background_task.network_error">A network error occurred. Please check the server address or try again later.</string>
|
||||
<string name="background_task.not_found">Resource not found. Please check the server address.</string>
|
||||
<string name="background_task.parse_error">Didn\'t understand the reply. Please check the server address.</string>
|
||||
|
||||
<string name="service.connecting">Contacting server, please wait.</string>
|
||||
|
||||
<string name="parser.reading">Reading from server.</string>
|
||||
<string name="parser.reading_done">Reading from server. Done!</string>
|
||||
<string name="parser.upgrade_client">Incompatible versions. Please upgrade Subsonic Android app.</string>
|
||||
<string name="parser.upgrade_server">Incompatible versions. Please upgrade Subsonic server.</string>
|
||||
<string name="parser.not_authenticated">Wrong username or password.</string>
|
||||
<string name="parser.not_authorized">Not authorized. Check user permissions in Subsonic server.</string>
|
||||
<string name="parser.artist_count">Got %d artists.</string>
|
||||
|
||||
<string name="select_artist.refresh">Refresh</string>
|
||||
<string name="select_artist.folder">Select folder</string>
|
||||
<string name="select_artist.all_folders">All folders</string>
|
||||
|
||||
<string name="equalizer.label">Equalizer</string>
|
||||
<string name="equalizer.enabled">Enabled</string>
|
||||
<string name="equalizer.preset">Select preset</string>
|
||||
|
||||
<string name="widget.initial_text">Touch to select music</string>
|
||||
<string name="widget.sdcard_busy">SD card unavailable</string>
|
||||
<string name="widget.sdcard_missing">No SD card</string>
|
||||
|
||||
<string name="util.bytes_format.gigabyte">0.00 GB</string>
|
||||
<string name="util.bytes_format.megabyte">0.00 MB</string>
|
||||
<string name="util.bytes_format.kilobyte">0 KB</string>
|
||||
<string name="util.bytes_format.byte">0 B</string>
|
||||
|
||||
<plurals name="select_album_n_songs">
|
||||
<item quantity="zero">No songs</item>
|
||||
<item quantity="one">One song</item>
|
||||
<item quantity="other">%d songs</item>
|
||||
</plurals>
|
||||
<plurals name="select_album_n_songs_downloading">
|
||||
<item quantity="one">One song scheduled for download.</item>
|
||||
<item quantity="other">%d songs scheduled for download.</item>
|
||||
</plurals>
|
||||
<plurals name="select_album_n_songs_added">
|
||||
<item quantity="one">One song added to play queue.</item>
|
||||
<item quantity="other">%d songs added to play queue.</item>
|
||||
</plurals>
|
||||
<plurals name="select_album_donate_dialog_n_trial_days_left">
|
||||
<item quantity="one">One day left of trial period</item>
|
||||
<item quantity="other">%d days left of trial period</item>
|
||||
</plurals>
|
||||
|
||||
</resources>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="common.appname">Subsonic</string>
|
||||
<string name="common.ok">OK</string>
|
||||
<string name="common.save">Save</string>
|
||||
<string name="common.cancel">Cancel</string>
|
||||
<string name="common.play_now">Play Now</string>
|
||||
<string name="common.play_next">Play Next</string>
|
||||
<string name="common.play_last">Play Last</string>
|
||||
<string name="common.pin">Pin</string>
|
||||
<string name="common.unpin">Unpin</string>
|
||||
<string name="common.delete">Delete</string>
|
||||
|
||||
<string name="button_bar.home">Subsonic Home</string>
|
||||
<string name="button_bar.browse">Media Library</string>
|
||||
<string name="button_bar.search">Search</string>
|
||||
<string name="button_bar.playlists">Playlists</string>
|
||||
<string name="button_bar.now_playing">Now Playing</string>
|
||||
|
||||
<string name="main.welcome_title">Welcome!</string>
|
||||
<string name="main.welcome_text">Welcome to Subsonic! The app is currently configured to use the Subsonic demo server. After you\'ve
|
||||
set up your personal server (available from <b>subsonic.org</b>), please go to <b>Settings</b> and change the configuration to connect to it.</string>
|
||||
<string name="main.select_server">Select Server</string>
|
||||
<string name="main.shuffle">Shuffle Play</string>
|
||||
<string name="main.offline">Offline</string>
|
||||
<string name="main.settings">Settings</string>
|
||||
<string name="main.albums_title">Albums</string>
|
||||
<string name="main.albums_newest">Recently Added</string>
|
||||
<string name="main.albums_recent">Recently Played</string>
|
||||
<string name="main.albums_frequent">Most Played</string>
|
||||
<string name="main.albums_highest">Top Rated</string>
|
||||
<string name="main.albums_random">Random</string>
|
||||
<string name="main.albums_starred">Starred Albums</string>
|
||||
<string name="main.albums_alphaByName">By Name</string>
|
||||
<string name="main.albums_alphaByArtist">By Artist</string>
|
||||
<string name="main.songs_title">Songs</string>
|
||||
<string name="main.songs_starred">Starred Songs</string>
|
||||
|
||||
<string name="menu.exit">Exit</string>
|
||||
<string name="menu.settings">Settings</string>
|
||||
<string name="menu.help">Help</string>
|
||||
<string name="menu.search">Search</string>
|
||||
|
||||
<string name="playlist.label">Playlists</string>
|
||||
|
||||
<string name="help.label">Help</string>
|
||||
<string name="help.title">Welcome to Subsonic!</string>
|
||||
<string name="help.back">Back</string>
|
||||
<string name="help.close">Close</string>
|
||||
<string name="help.url">file:///android_asset/html/en/index.html</string>
|
||||
<string name="help.loading">Loading…</string>
|
||||
|
||||
<string name="play_video.loading">Loading video…</string>
|
||||
<string name="play_video.noplugin">Please install Adobe Flash Player from Android Market.</string>
|
||||
|
||||
<string name="search.label">Search</string>
|
||||
<string name="search.title">Search</string>
|
||||
<string name="search.search">Click to search</string>
|
||||
<string name="search.no_match">No matches, please try again</string>
|
||||
<string name="search.artists">Artists</string>
|
||||
<string name="search.albums">Albums</string>
|
||||
<string name="search.songs">Songs</string>
|
||||
<string name="search.more">Show More</string>
|
||||
|
||||
<string name="progress.wait">Please wait…</string>
|
||||
|
||||
<string name="music_library.label">Media Library</string>
|
||||
<string name="music_library.label_offline">Offline Media</string>
|
||||
|
||||
<string name="select_album.empty">No media found</string>
|
||||
<string name="select_album.select">Select All</string>
|
||||
<string name="select_album.n_selected">%d tracks selected.</string>
|
||||
<string name="select_album.n_unselected">%d tracks unselected.</string>
|
||||
<string name="select_album.more">More</string>
|
||||
<string name="select_album.offline">Offline</string>
|
||||
<string name="select_album.searching">Searching…</string>
|
||||
<string name="select_album.play_all">Play All</string>
|
||||
<string name="select_album.no_sdcard">Error: No SD card available.</string>
|
||||
<string name="select_album.no_network">Warning: No network available.</string>
|
||||
<string name="select_album.not_licensed">Server not licensed. %d trial days left.</string>
|
||||
<string name="select_album.donate_dialog_message">Get unlimited downloads by donating to Subsonic.</string>
|
||||
<string name="select_album.donate_dialog_now">Now</string>
|
||||
<string name="select_album.donate_dialog_later">Later</string>
|
||||
<string name="select_album.donate_dialog_0_trial_days_left">Trial period is over</string>
|
||||
|
||||
|
||||
<string name="select_playlist.empty">No saved playlists on server</string>
|
||||
|
||||
<string name="download.empty">Playlist is empty</string>
|
||||
<string name="download.playerstate_downloading">Downloading - %s</string>
|
||||
<string name="download.playerstate_buffering">Buffering</string>
|
||||
<string name="download.playerstate_playing_shuffle">Playing shuffle</string>
|
||||
<string name="download.menu_show_album">Show Album</string>
|
||||
<string name="download.menu_lyrics">Lyrics</string>
|
||||
<string name="download.menu_remove">Remove Song</string>
|
||||
<string name="download.menu_remove_all">Remove All</string>
|
||||
<string name="download.menu_screen_on">Screen On</string>
|
||||
<string name="download.menu_screen_off">Screen Off</string>
|
||||
<string name="download.menu_shuffle">Shuffle</string>
|
||||
<string name="download.menu_save">Save Playlist</string>
|
||||
<string name="download.menu_equalizer">Equalizer</string>
|
||||
<string name="download.menu_visualizer">Visualizer</string>
|
||||
<string name="download.menu_jukebox">Jukebox</string>
|
||||
<string name="download.menu_shuffle_notification">Playlist was shuffled</string>
|
||||
<string name="download.playlist_title">Save Playlist</string>
|
||||
<string name="download.playlist_name">Enter the playlist name:</string>
|
||||
<string name="download.playlist_saving">Saving playlist \"%s\"…</string>
|
||||
<string name="download.playlist_done">Playlist was successfully saved.</string>
|
||||
<string name="download.playlist_error">Failed to save playlist, please try later.</string>
|
||||
<string name="download.repeat_off">Repeat Off</string>
|
||||
<string name="download.repeat_all">Repeat All</string>
|
||||
<string name="download.repeat_single">Repeat Song</string>
|
||||
<string name="download.visualizer_on">Turned on visualizer.</string>
|
||||
<string name="download.visualizer_off">Turned off visualizer.</string>
|
||||
<string name="download.jukebox_on">Turned on remote control. Music is played on server.</string>
|
||||
<string name="download.jukebox_off">Turned off remote control. Music is played on phone.</string>
|
||||
<string name="download.jukebox_volume">Remote Volume</string>
|
||||
<string name="download.jukebox_server_too_old">Remote control is not supported. Please upgrade your Subsonic server.</string>
|
||||
<string name="download.jukebox_offline">Remote control is not available in offline mode.</string>
|
||||
<string name="download.jukebox_not_authorized">Remote control is not allowed. Please enable jukebox mode in <b>Users > Settings</b> on your Subsonic server.</string>
|
||||
|
||||
<string name="song_details.all">%1$s %2$s</string>
|
||||
<string name="song_details.kbps">%d kbps</string>
|
||||
|
||||
<string name="lyrics.nomatch">No lyrics found</string>
|
||||
|
||||
<string name="error.label">Error</string>
|
||||
|
||||
<string name="settings.title">Subsonic Settings</string>
|
||||
<string name="settings.test_connection_title">Test Connection</string>
|
||||
<string name="settings.servers_title">Servers</string>
|
||||
<string name="settings.server_unused1">Unused 1</string>
|
||||
<string name="settings.server_unused2">Unused 2</string>
|
||||
<string name="settings.server_name">Name</string>
|
||||
<string name="settings.server_address">Server Address</string>
|
||||
<string name="settings.server_username">Username</string>
|
||||
<string name="settings.server_password">Password</string>
|
||||
<string name="settings.cache_title">Music Cache</string>
|
||||
<string name="settings.preload">Songs To Preload</string>
|
||||
<string name="settings.cache_size">Cache Size</string>
|
||||
<string name="settings.cache_location">Cache Location</string>
|
||||
<string name="settings.cache_location_error">Invalid cache location. Using default.</string>
|
||||
<string name="settings.testing_connection">Testing connection…</string>
|
||||
<string name="settings.testing_ok">Connection is OK</string>
|
||||
<string name="settings.testing_unlicensed">Connection is OK. Server unlicensed.</string>
|
||||
<string name="settings.connection_failure">Connection failure.</string>
|
||||
<string name="settings.invalid_url">Please specify a valid URL.</string>
|
||||
<string name="settings.invalid_username">Please specify a valid username (no trailing spaces).</string>
|
||||
<string name="settings.appearance_title">Appearance</string>
|
||||
<string name="settings.theme_title">Theme</string>
|
||||
<string name="settings.theme_fullscreen">Fullscreen Dark</string>
|
||||
<string name="settings.theme_fullscreenlight">Fullscreen Light</string>
|
||||
<string name="settings.theme_light">Light</string>
|
||||
<string name="settings.theme_dark">Dark</string>
|
||||
<string name="settings.network_title">Network</string>
|
||||
<string name="settings.max_bitrate_wifi">Max Bitrate - Wi-Fi</string>
|
||||
<string name="settings.max_bitrate_mobile">Max Bitrate - Mobile</string>
|
||||
<string name="settings.max_bitrate_32">32 Kbps</string>
|
||||
<string name="settings.max_bitrate_64">64 Kbps</string>
|
||||
<string name="settings.max_bitrate_80">80 Kbps</string>
|
||||
<string name="settings.max_bitrate_96">96 Kbps</string>
|
||||
<string name="settings.max_bitrate_112">112 Kbps</string>
|
||||
<string name="settings.max_bitrate_128">128 Kbps</string>
|
||||
<string name="settings.max_bitrate_160">160 Kbps</string>
|
||||
<string name="settings.max_bitrate_192">192 Kbps</string>
|
||||
<string name="settings.max_bitrate_256">256 Kbps</string>
|
||||
<string name="settings.max_bitrate_320">320 Kbps</string>
|
||||
<string name="settings.max_bitrate_unlimited">Unlimited</string>
|
||||
<string name="settings.wifi_required_title">Wi-Fi Streaming Only</string>
|
||||
<string name="settings.wifi_required_summary">Only stream media if connected to Wi-Fi</string>
|
||||
<string name="settings.preload_1">1 song</string>
|
||||
<string name="settings.preload_2">2 songs</string>
|
||||
<string name="settings.preload_3">3 songs</string>
|
||||
<string name="settings.preload_5">5 songs</string>
|
||||
<string name="settings.preload_10">10 songs</string>
|
||||
<string name="settings.preload_unlimited">Unlimited</string>
|
||||
<string name="settings.cache_size_100">100 MB</string>
|
||||
<string name="settings.cache_size_200">200 MB</string>
|
||||
<string name="settings.cache_size_500">500 MB</string>
|
||||
<string name="settings.cache_size_1000">1 GB</string>
|
||||
<string name="settings.cache_size_2000">2 GB</string>
|
||||
<string name="settings.cache_size_5000">5 GB</string>
|
||||
<string name="settings.cache_size_10000">10 GB</string>
|
||||
<string name="settings.cache_size_20000">20 GB</string>
|
||||
<string name="settings.cache_size_unlimited">Unlimited</string>
|
||||
<string name="settings.clear_search_history">Clear Search History</string>
|
||||
<string name="settings.search_history_cleared">Search history cleared</string>
|
||||
<string name="settings.other_title">Other Settings</string>
|
||||
<string name="settings.search_title">Search Settings</string>
|
||||
<string name="settings.scrobble_title">Scrobble To Last.fm</string>
|
||||
<string name="settings.scrobble_summary">Remember to set up your Last.fm user and password on the Subsonic server</string>
|
||||
<string name="settings.hide_media_title">Hide From Other</string>
|
||||
<string name="settings.hide_media_summary">Hide music files from other apps.</string>
|
||||
<string name="settings.hide_media_toast">Takes effect next time Android scans your phone for music.</string>
|
||||
<string name="settings.media_button_title">Media Buttons</string>
|
||||
<string name="settings.media_button_summary">Respond to phone, headset and Bluetooth media buttons</string>
|
||||
<string name="settings.screen_lit_title">Keep Screen On</string>
|
||||
<string name="settings.screen_lit_summary">Keeping the screen on while downloading improves download speed.</string>
|
||||
<string name="settings.buffer_length">Buffer Length</string>
|
||||
<string name="settings.network_timeout">Network Timeout</string>
|
||||
<string name="settings.buffer_length_2">2 seconds</string>
|
||||
<string name="settings.buffer_length_5">5 seconds</string>
|
||||
<string name="settings.buffer_length_8">8 seconds</string>
|
||||
<string name="settings.buffer_length_10">10 seconds</string>
|
||||
<string name="settings.buffer_length_12">12 seconds</string>
|
||||
<string name="settings.buffer_length_15">15 seconds</string>
|
||||
<string name="settings.buffer_length_20">20 seconds</string>
|
||||
<string name="settings.buffer_length_30">30 seconds</string>
|
||||
<string name="settings.network_timeout_15000">15 seconds</string>
|
||||
<string name="settings.network_timeout_30000">30 seconds</string>
|
||||
<string name="settings.network_timeout_45000">45 seconds</string>
|
||||
<string name="settings.network_timeout_60000">60 seconds</string>
|
||||
<string name="settings.network_timeout_75000">75 seconds</string>
|
||||
<string name="settings.network_timeout_90000">90 seconds</string>
|
||||
<string name="settings.network_timeout_105000">105 seconds</string>
|
||||
<string name="settings.network_timeout_120000">120 seconds</string>
|
||||
<string name="settings.show_notification">Show Notification</string>
|
||||
<string name="settings.show_notification_summary">Show now playing notification in the status bar</string>
|
||||
<string name="settings.show_lockscreen_controls">Show Lock Screen Controls</string>
|
||||
<string name="settings.show_lockscreen_controls_summary">Show playback controls on the lock screen</string>
|
||||
<string name="settings.use_stream_proxy">Use Stream Proxy</string>
|
||||
<string name="settings.use_stream_proxy_summary">Stream media playback through a proxy (may help stutter)</string>
|
||||
<string name="settings.max_albums">Max Albums</string>
|
||||
<string name="settings.max_albums_5">5</string>
|
||||
<string name="settings.max_albums_10">10</string>
|
||||
<string name="settings.max_albums_20">20</string>
|
||||
<string name="settings.max_albums_30">30</string>
|
||||
<string name="settings.max_albums_40">40</string>
|
||||
<string name="settings.max_albums_50">50</string>
|
||||
<string name="settings.max_albums_100">100</string>
|
||||
<string name="settings.max_albums_250">250</string>
|
||||
<string name="settings.max_albums_500">500</string>
|
||||
<string name="settings.max_songs">Max Songs</string>
|
||||
<string name="settings.max_songs_5">5</string>
|
||||
<string name="settings.max_songs_10">10</string>
|
||||
<string name="settings.max_songs_25">25</string>
|
||||
<string name="settings.max_songs_50">50</string>
|
||||
<string name="settings.max_songs_75">75</string>
|
||||
<string name="settings.max_songs_100">100</string>
|
||||
<string name="settings.max_songs_200">200</string>
|
||||
<string name="settings.max_songs_500">500</string>
|
||||
<string name="settings.max_artists">Max Artists</string>
|
||||
<string name="settings.max_artists_3">3</string>
|
||||
<string name="settings.max_artists_5">5</string>
|
||||
<string name="settings.max_artists_10">10</string>
|
||||
<string name="settings.max_artists_25">25</string>
|
||||
<string name="settings.max_artists_50">50</string>
|
||||
<string name="settings.max_artists_75">75</string>
|
||||
<string name="settings.max_artists_100">100</string>
|
||||
<string name="settings.max_artists_200">200</string>
|
||||
<string name="settings.max_artists_500">500</string>
|
||||
<string name="settings.default_artists">Default Artists</string>
|
||||
<string name="settings.default_albums">Default Albums</string>
|
||||
<string name="settings.default_songs">Default Songs</string>
|
||||
|
||||
<string name="music_service.retry">A network error occurred. Retrying %1$d of %2$d.</string>
|
||||
|
||||
<string name="background_task.wait">Please wait…</string>
|
||||
<string name="background_task.loading">Loading.</string>
|
||||
<string name="background_task.no_network">This program requires network access. Please turn on Wi-Fi or mobile network.</string>
|
||||
<string name="background_task.network_error">A network error occurred. Please check the server address or try again later.</string>
|
||||
<string name="background_task.not_found">Resource not found. Please check the server address.</string>
|
||||
<string name="background_task.parse_error">Didn\'t understand the reply. Please check the server address.</string>
|
||||
|
||||
<string name="service.connecting">Contacting server, please wait.</string>
|
||||
|
||||
<string name="parser.reading">Reading from server.</string>
|
||||
<string name="parser.reading_done">Reading from server. Done!</string>
|
||||
<string name="parser.upgrade_client">Incompatible versions. Please upgrade Subsonic Android app.</string>
|
||||
<string name="parser.upgrade_server">Incompatible versions. Please upgrade Subsonic server.</string>
|
||||
<string name="parser.not_authenticated">Wrong username or password.</string>
|
||||
<string name="parser.not_authorized">Not authorized. Check user permissions in Subsonic server.</string>
|
||||
<string name="parser.artist_count">Got %d artists.</string>
|
||||
|
||||
<string name="select_artist.refresh">Refresh</string>
|
||||
<string name="select_artist.folder">Select folder</string>
|
||||
<string name="select_artist.all_folders">All folders</string>
|
||||
|
||||
<string name="equalizer.label">Equalizer</string>
|
||||
<string name="equalizer.enabled">Enabled</string>
|
||||
<string name="equalizer.preset">Select preset</string>
|
||||
|
||||
<string name="widget.initial_text">Touch to select music</string>
|
||||
<string name="widget.sdcard_busy">SD card unavailable</string>
|
||||
<string name="widget.sdcard_missing">No SD card</string>
|
||||
|
||||
<string name="util.bytes_format.gigabyte">0.00 GB</string>
|
||||
<string name="util.bytes_format.megabyte">0.00 MB</string>
|
||||
<string name="util.bytes_format.kilobyte">0 KB</string>
|
||||
<string name="util.bytes_format.byte">0 B</string>
|
||||
|
||||
<plurals name="select_album_n_songs">
|
||||
<item quantity="zero">No songs</item>
|
||||
<item quantity="one">One song</item>
|
||||
<item quantity="other">%d songs</item>
|
||||
</plurals>
|
||||
<plurals name="select_album_n_songs_downloading">
|
||||
<item quantity="one">One song scheduled for download.</item>
|
||||
<item quantity="other">%d songs scheduled for download.</item>
|
||||
</plurals>
|
||||
<plurals name="select_album_n_songs_added">
|
||||
<item quantity="one">One song added to play queue.</item>
|
||||
<item quantity="other">%d songs added to play queue.</item>
|
||||
</plurals>
|
||||
<plurals name="select_album_donate_dialog_n_trial_days_left">
|
||||
<item quantity="one">One day left of trial period</item>
|
||||
<item quantity="other">%d days left of trial period</item>
|
||||
</plurals>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,273 +1,279 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android"
|
||||
a:title="@string/settings.title">
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.servers_title">
|
||||
|
||||
<PreferenceScreen
|
||||
a:key="server1">
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverName1"
|
||||
a:title="@string/settings.server_name"
|
||||
a:defaultValue="Subsonic demo"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverUrl1"
|
||||
a:title="@string/settings.server_address"
|
||||
a:defaultValue="http://demo.subsonic.org"
|
||||
a:inputType="textUri"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="username1"
|
||||
a:title="@string/settings.server_username"
|
||||
a:defaultValue="android-guest"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="password1"
|
||||
a:title="@string/settings.server_password"
|
||||
a:password="true"
|
||||
a:defaultValue="guest"
|
||||
a:summary="****"/>
|
||||
|
||||
<Preference
|
||||
a:key="testConnection1"
|
||||
a:title="@string/settings.test_connection_title"
|
||||
a:persistent="false"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
a:key="server2">
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverName2"
|
||||
a:title="@string/settings.server_name"
|
||||
a:defaultValue="@string/settings.server_unused1"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverUrl2"
|
||||
a:title="@string/settings.server_address"
|
||||
a:defaultValue="http://yourhost"
|
||||
a:inputType="textUri"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="username2"
|
||||
a:title="@string/settings.server_username"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="password2"
|
||||
a:title="@string/settings.server_password"
|
||||
a:password="true"
|
||||
a:summary="****"/>
|
||||
|
||||
<Preference
|
||||
a:key="testConnection2"
|
||||
a:title="@string/settings.test_connection_title"
|
||||
a:persistent="false"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
a:key="server3">
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverName3"
|
||||
a:title="@string/settings.server_name"
|
||||
a:defaultValue="@string/settings.server_unused2"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverUrl3"
|
||||
a:title="@string/settings.server_address"
|
||||
a:defaultValue="http://yourhost"
|
||||
a:inputType="textUri"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="username3"
|
||||
a:title="@string/settings.server_username"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="password3"
|
||||
a:title="@string/settings.server_password"
|
||||
a:password="true"
|
||||
a:summary="****"/>
|
||||
|
||||
<Preference
|
||||
a:key="testConnection3"
|
||||
a:title="@string/settings.test_connection_title"
|
||||
a:persistent="false"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.appearance_title">
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.theme_title"
|
||||
a:key="theme"
|
||||
a:defaultValue="Dark"
|
||||
a:entryValues="@array/themeValues"
|
||||
a:entries="@array/themeNames"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.network_title">
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.max_bitrate_wifi"
|
||||
a:key="maxBitrateWifi"
|
||||
a:defaultValue="0"
|
||||
a:entryValues="@array/maxBitrateValues"
|
||||
a:entries="@array/maxBitrateNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.max_bitrate_mobile"
|
||||
a:key="maxBitrateMobile"
|
||||
a:defaultValue="0"
|
||||
a:entryValues="@array/maxBitrateValues"
|
||||
a:entries="@array/maxBitrateNames"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.wifi_required_title"
|
||||
a:summary="@string/settings.wifi_required_summary"
|
||||
a:key="wifiRequiredForDownload"
|
||||
a:defaultValue="false"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.buffer_length"
|
||||
a:key="bufferLength"
|
||||
a:defaultValue="5"
|
||||
a:entryValues="@array/bufferLengthValues"
|
||||
a:entries="@array/bufferLengthNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.network_timeout"
|
||||
a:key="networkTimeout"
|
||||
a:defaultValue="15000"
|
||||
a:entryValues="@array/networkTimeoutValues"
|
||||
a:entries="@array/networkTimeoutNames"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.cache_title">
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.cache_size"
|
||||
a:key="cacheSize"
|
||||
a:defaultValue="500"
|
||||
a:entryValues="@array/cacheSizeValues"
|
||||
a:entries="@array/cacheSizeNames"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:title="@string/settings.cache_location"
|
||||
a:key="cacheLocation"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.preload"
|
||||
a:key="preloadCount"
|
||||
a:defaultValue="3"
|
||||
a:entryValues="@array/preloadCountValues"
|
||||
a:entries="@array/preloadCountNames"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.search_title">
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.default_artists"
|
||||
a:key="defaultArtists"
|
||||
a:defaultValue="3"
|
||||
a:entryValues="@array/defaultSearchValues"
|
||||
a:entries="@array/defaultSearchNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.max_artists"
|
||||
a:key="maxArtists"
|
||||
a:defaultValue="10"
|
||||
a:entryValues="@array/maxArtistsValues"
|
||||
a:entries="@array/maxArtistsNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.default_albums"
|
||||
a:key="defaultAlbums"
|
||||
a:defaultValue="5"
|
||||
a:entryValues="@array/defaultSearchValues"
|
||||
a:entries="@array/defaultSearchNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.max_albums"
|
||||
a:key="maxAlbums"
|
||||
a:defaultValue="20"
|
||||
a:entryValues="@array/maxAlbumsValues"
|
||||
a:entries="@array/maxAlbumsNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.default_songs"
|
||||
a:key="defaultSongs"
|
||||
a:defaultValue="10"
|
||||
a:entryValues="@array/defaultSearchValues"
|
||||
a:entries="@array/defaultSearchNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.max_songs"
|
||||
a:key="maxSongs"
|
||||
a:defaultValue="25"
|
||||
a:entryValues="@array/maxSongsValues"
|
||||
a:entries="@array/maxSongsNames"/>
|
||||
|
||||
<Preference
|
||||
a:key="clearSearchHistory"
|
||||
a:title="@string/settings.clear_search_history"
|
||||
a:persistent="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.other_title">
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.scrobble_title"
|
||||
a:summary="@string/settings.scrobble_summary"
|
||||
a:key="scrobble"
|
||||
a:defaultValue="false"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.hide_media_title"
|
||||
a:summary="@string/settings.hide_media_summary"
|
||||
a:key="hideMedia"
|
||||
a:defaultValue="false"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.media_button_title"
|
||||
a:summary="@string/settings.media_button_summary"
|
||||
a:key="mediaButtons"
|
||||
a:defaultValue="true"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.screen_lit_title"
|
||||
a:summary="@string/settings.screen_lit_summary"
|
||||
a:key="screenLitOnDownload"
|
||||
a:defaultValue="true"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.show_notification"
|
||||
a:summary="@string/settings.show_notification_summary"
|
||||
a:key="showNotification"
|
||||
a:defaultValue="true"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.show_lockscreen_controls"
|
||||
a:summary="@string/settings.show_lockscreen_controls_summary"
|
||||
a:key="showLockScreen"
|
||||
a:defaultValue="true"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<PreferenceScreen xmlns:a="http://schemas.android.com/apk/res/android"
|
||||
a:title="@string/settings.title">
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.servers_title">
|
||||
|
||||
<PreferenceScreen
|
||||
a:key="server1">
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverName1"
|
||||
a:title="@string/settings.server_name"
|
||||
a:defaultValue="Subsonic demo"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverUrl1"
|
||||
a:title="@string/settings.server_address"
|
||||
a:defaultValue="http://demo.subsonic.org"
|
||||
a:inputType="textUri"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="username1"
|
||||
a:title="@string/settings.server_username"
|
||||
a:defaultValue="android-guest"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="password1"
|
||||
a:title="@string/settings.server_password"
|
||||
a:password="true"
|
||||
a:defaultValue="guest"
|
||||
a:summary="****"/>
|
||||
|
||||
<Preference
|
||||
a:key="testConnection1"
|
||||
a:title="@string/settings.test_connection_title"
|
||||
a:persistent="false"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
a:key="server2">
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverName2"
|
||||
a:title="@string/settings.server_name"
|
||||
a:defaultValue="@string/settings.server_unused1"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverUrl2"
|
||||
a:title="@string/settings.server_address"
|
||||
a:defaultValue="http://yourhost"
|
||||
a:inputType="textUri"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="username2"
|
||||
a:title="@string/settings.server_username"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="password2"
|
||||
a:title="@string/settings.server_password"
|
||||
a:password="true"
|
||||
a:summary="****"/>
|
||||
|
||||
<Preference
|
||||
a:key="testConnection2"
|
||||
a:title="@string/settings.test_connection_title"
|
||||
a:persistent="false"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
<PreferenceScreen
|
||||
a:key="server3">
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverName3"
|
||||
a:title="@string/settings.server_name"
|
||||
a:defaultValue="@string/settings.server_unused2"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="serverUrl3"
|
||||
a:title="@string/settings.server_address"
|
||||
a:defaultValue="http://yourhost"
|
||||
a:inputType="textUri"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="username3"
|
||||
a:title="@string/settings.server_username"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:key="password3"
|
||||
a:title="@string/settings.server_password"
|
||||
a:password="true"
|
||||
a:summary="****"/>
|
||||
|
||||
<Preference
|
||||
a:key="testConnection3"
|
||||
a:title="@string/settings.test_connection_title"
|
||||
a:persistent="false"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.appearance_title">
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.theme_title"
|
||||
a:key="theme"
|
||||
a:defaultValue="Dark"
|
||||
a:entryValues="@array/themeValues"
|
||||
a:entries="@array/themeNames"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.network_title">
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.max_bitrate_wifi"
|
||||
a:key="maxBitrateWifi"
|
||||
a:defaultValue="0"
|
||||
a:entryValues="@array/maxBitrateValues"
|
||||
a:entries="@array/maxBitrateNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.max_bitrate_mobile"
|
||||
a:key="maxBitrateMobile"
|
||||
a:defaultValue="0"
|
||||
a:entryValues="@array/maxBitrateValues"
|
||||
a:entries="@array/maxBitrateNames"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.wifi_required_title"
|
||||
a:summary="@string/settings.wifi_required_summary"
|
||||
a:key="wifiRequiredForDownload"
|
||||
a:defaultValue="false"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.buffer_length"
|
||||
a:key="bufferLength"
|
||||
a:defaultValue="5"
|
||||
a:entryValues="@array/bufferLengthValues"
|
||||
a:entries="@array/bufferLengthNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.network_timeout"
|
||||
a:key="networkTimeout"
|
||||
a:defaultValue="15000"
|
||||
a:entryValues="@array/networkTimeoutValues"
|
||||
a:entries="@array/networkTimeoutNames"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.cache_title">
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.cache_size"
|
||||
a:key="cacheSize"
|
||||
a:defaultValue="500"
|
||||
a:entryValues="@array/cacheSizeValues"
|
||||
a:entries="@array/cacheSizeNames"/>
|
||||
|
||||
<EditTextPreference
|
||||
a:title="@string/settings.cache_location"
|
||||
a:key="cacheLocation"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.preload"
|
||||
a:key="preloadCount"
|
||||
a:defaultValue="3"
|
||||
a:entryValues="@array/preloadCountValues"
|
||||
a:entries="@array/preloadCountNames"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.search_title">
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.default_artists"
|
||||
a:key="defaultArtists"
|
||||
a:defaultValue="3"
|
||||
a:entryValues="@array/defaultSearchValues"
|
||||
a:entries="@array/defaultSearchNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.max_artists"
|
||||
a:key="maxArtists"
|
||||
a:defaultValue="10"
|
||||
a:entryValues="@array/maxArtistsValues"
|
||||
a:entries="@array/maxArtistsNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.default_albums"
|
||||
a:key="defaultAlbums"
|
||||
a:defaultValue="5"
|
||||
a:entryValues="@array/defaultSearchValues"
|
||||
a:entries="@array/defaultSearchNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.max_albums"
|
||||
a:key="maxAlbums"
|
||||
a:defaultValue="20"
|
||||
a:entryValues="@array/maxAlbumsValues"
|
||||
a:entries="@array/maxAlbumsNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.default_songs"
|
||||
a:key="defaultSongs"
|
||||
a:defaultValue="10"
|
||||
a:entryValues="@array/defaultSearchValues"
|
||||
a:entries="@array/defaultSearchNames"/>
|
||||
|
||||
<ListPreference
|
||||
a:title="@string/settings.max_songs"
|
||||
a:key="maxSongs"
|
||||
a:defaultValue="25"
|
||||
a:entryValues="@array/maxSongsValues"
|
||||
a:entries="@array/maxSongsNames"/>
|
||||
|
||||
<Preference
|
||||
a:key="clearSearchHistory"
|
||||
a:title="@string/settings.clear_search_history"
|
||||
a:persistent="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
a:title="@string/settings.other_title">
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.scrobble_title"
|
||||
a:summary="@string/settings.scrobble_summary"
|
||||
a:key="scrobble"
|
||||
a:defaultValue="false"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.hide_media_title"
|
||||
a:summary="@string/settings.hide_media_summary"
|
||||
a:key="hideMedia"
|
||||
a:defaultValue="false"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.media_button_title"
|
||||
a:summary="@string/settings.media_button_summary"
|
||||
a:key="mediaButtons"
|
||||
a:defaultValue="true"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.screen_lit_title"
|
||||
a:summary="@string/settings.screen_lit_summary"
|
||||
a:key="screenLitOnDownload"
|
||||
a:defaultValue="true"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.show_notification"
|
||||
a:summary="@string/settings.show_notification_summary"
|
||||
a:key="showNotification"
|
||||
a:defaultValue="true"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.show_lockscreen_controls"
|
||||
a:summary="@string/settings.show_lockscreen_controls_summary"
|
||||
a:key="showLockScreen"
|
||||
a:defaultValue="true"/>
|
||||
|
||||
<CheckBoxPreference
|
||||
a:title="@string/settings.use_stream_proxy"
|
||||
a:summary="@string/settings.use_stream_proxy_summary"
|
||||
a:key="useStreamProxy"
|
||||
a:defaultValue="false"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -1,251 +1,253 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
|
||||
package net.sourceforge.subsonic.androidapp.activity;
|
||||
|
||||
import android.content.Intent;
|
||||
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.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import net.sourceforge.subsonic.androidapp.R;
|
||||
import net.sourceforge.subsonic.androidapp.domain.Artist;
|
||||
import net.sourceforge.subsonic.androidapp.domain.Indexes;
|
||||
import net.sourceforge.subsonic.androidapp.domain.MusicFolder;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicService;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
|
||||
import net.sourceforge.subsonic.androidapp.util.ArtistAdapter;
|
||||
import net.sourceforge.subsonic.androidapp.util.BackgroundTask;
|
||||
import net.sourceforge.subsonic.androidapp.util.Constants;
|
||||
import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask;
|
||||
import net.sourceforge.subsonic.androidapp.util.Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SelectArtistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener {
|
||||
|
||||
private static final int MENU_GROUP_MUSIC_FOLDER = 10;
|
||||
|
||||
private ListView artistList;
|
||||
private View folderButton;
|
||||
private TextView folderName;
|
||||
private List<MusicFolder> musicFolders;
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.select_artist);
|
||||
|
||||
artistList = (ListView) findViewById(R.id.select_artist_list);
|
||||
artistList.setOnItemClickListener(this);
|
||||
artistList.setOnTouchListener(gestureListener);
|
||||
|
||||
folderButton = LayoutInflater.from(this).inflate(R.layout.select_artist_header, artistList, false);
|
||||
folderName = (TextView) folderButton.findViewById(R.id.select_artist_folder_2);
|
||||
|
||||
if (!Util.isOffline(this)) {
|
||||
artistList.addHeaderView(folderButton);
|
||||
}
|
||||
|
||||
registerForContextMenu(artistList);
|
||||
|
||||
setTitle(Util.isOffline(this) ? R.string.music_library_label_offline : R.string.music_library_label);
|
||||
|
||||
musicFolders = null;
|
||||
load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.main, menu);
|
||||
inflater.inflate(R.menu.select_common, menu);
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
finish();
|
||||
Intent intent = getIntent();
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
|
||||
Util.startActivityWithoutTransition(this, intent);
|
||||
}
|
||||
|
||||
private void selectFolder() {
|
||||
folderButton.showContextMenu();
|
||||
}
|
||||
|
||||
private void load() {
|
||||
BackgroundTask<Indexes> task = new TabActivityBackgroundTask<Indexes>(this) {
|
||||
@Override
|
||||
protected Indexes doInBackground() throws Throwable {
|
||||
boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(SelectArtistActivity.this);
|
||||
if (!Util.isOffline(SelectArtistActivity.this)) {
|
||||
musicFolders = musicService.getMusicFolders(SelectArtistActivity.this, this);
|
||||
}
|
||||
String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
|
||||
return musicService.getIndexes(musicFolderId, refresh, SelectArtistActivity.this, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done(Indexes result) {
|
||||
List<Artist> artists = new ArrayList<Artist>(result.getShortcuts().size() + result.getArtists().size());
|
||||
artists.addAll(result.getShortcuts());
|
||||
artists.addAll(result.getArtists());
|
||||
artistList.setAdapter(new ArtistAdapter(SelectArtistActivity.this, artists));
|
||||
|
||||
// Display selected music folder
|
||||
if (musicFolders != null) {
|
||||
String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
task.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (view == folderButton) {
|
||||
selectFolder();
|
||||
} else {
|
||||
Artist artist = (Artist) parent.getItemAtPosition(position);
|
||||
Intent intent = new Intent(this, SelectAlbumActivity.class);
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
|
||||
Util.startActivityWithoutTransition(this, intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, view, menuInfo);
|
||||
|
||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
|
||||
if (artistList.getItemAtPosition(info.position) instanceof Artist) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.select_artist_context, menu);
|
||||
} else if (info.position == 0) {
|
||||
String musicFolderId = Util.getSelectedMusicFolderId(this);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem menuItem) {
|
||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
|
||||
|
||||
Artist artist = (Artist) artistList.getItemAtPosition(info.position);
|
||||
|
||||
if (artist != null) {
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.artist_menu_play_now:
|
||||
downloadRecursively(artist.getId(), false, false, true);
|
||||
break;
|
||||
case R.id.artist_menu_play_last:
|
||||
downloadRecursively(artist.getId(), false, true, false);
|
||||
break;
|
||||
case R.id.artist_menu_pin:
|
||||
downloadRecursively(artist.getId(), true, true, false);
|
||||
break;
|
||||
default:
|
||||
return super.onContextItemSelected(menuItem);
|
||||
}
|
||||
} 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 ? getString(R.string.select_artist_all_folders)
|
||||
: selectedFolder.getName();
|
||||
Util.setSelectedMusicFolderId(this, musicFolderId);
|
||||
folderName.setText(musicFolderName);
|
||||
refresh();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
|
||||
case R.id.menu_refresh:
|
||||
refresh();
|
||||
return true;
|
||||
|
||||
case R.id.main_shuffle:
|
||||
Intent intent = new Intent(this, DownloadActivity.class);
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
|
||||
Util.startActivityWithoutTransition(this, intent);
|
||||
return true;
|
||||
|
||||
case R.id.menu_exit:
|
||||
Intent intent1 = new Intent(this, MainActivity.class);
|
||||
intent1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intent1.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
|
||||
Util.startActivityWithoutTransition(this, intent1);
|
||||
return true;
|
||||
|
||||
case R.id.menu_settings:
|
||||
startActivity(new Intent(this, SettingsActivity.class));
|
||||
return true;
|
||||
|
||||
case R.id.menu_help:
|
||||
startActivity(new Intent(this, HelpActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
|
||||
package net.sourceforge.subsonic.androidapp.activity;
|
||||
|
||||
import android.content.Intent;
|
||||
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.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import net.sourceforge.subsonic.androidapp.R;
|
||||
import net.sourceforge.subsonic.androidapp.domain.Artist;
|
||||
import net.sourceforge.subsonic.androidapp.domain.Indexes;
|
||||
import net.sourceforge.subsonic.androidapp.domain.MusicFolder;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicService;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
|
||||
import net.sourceforge.subsonic.androidapp.util.ArtistAdapter;
|
||||
import net.sourceforge.subsonic.androidapp.util.BackgroundTask;
|
||||
import net.sourceforge.subsonic.androidapp.util.Constants;
|
||||
import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask;
|
||||
import net.sourceforge.subsonic.androidapp.util.Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SelectArtistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener {
|
||||
|
||||
private static final int MENU_GROUP_MUSIC_FOLDER = 10;
|
||||
|
||||
private ListView artistList;
|
||||
private View folderButton;
|
||||
private TextView folderName;
|
||||
private List<MusicFolder> musicFolders;
|
||||
|
||||
/**
|
||||
* Called when the activity is first created.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.select_artist);
|
||||
|
||||
artistList = (ListView) findViewById(R.id.select_artist_list);
|
||||
artistList.setOnItemClickListener(this);
|
||||
artistList.setOnTouchListener(gestureListener);
|
||||
|
||||
folderButton = LayoutInflater.from(this).inflate(R.layout.select_artist_header, artistList, false);
|
||||
folderName = (TextView) folderButton.findViewById(R.id.select_artist_folder_2);
|
||||
|
||||
if (!Util.isOffline(this)) {
|
||||
artistList.addHeaderView(folderButton);
|
||||
}
|
||||
|
||||
registerForContextMenu(artistList);
|
||||
|
||||
setTitle(Util.isOffline(this) ? R.string.music_library_label_offline : R.string.music_library_label);
|
||||
|
||||
musicFolders = null;
|
||||
load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.main, menu);
|
||||
inflater.inflate(R.menu.select_common, menu);
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void refresh() {
|
||||
finish();
|
||||
Intent intent = getIntent();
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true);
|
||||
Util.startActivityWithoutTransition(this, intent);
|
||||
}
|
||||
|
||||
private void selectFolder() {
|
||||
folderButton.showContextMenu();
|
||||
}
|
||||
|
||||
private void load() {
|
||||
BackgroundTask<Indexes> task = new TabActivityBackgroundTask<Indexes>(this) {
|
||||
@Override
|
||||
protected Indexes doInBackground() throws Throwable {
|
||||
boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false);
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(SelectArtistActivity.this);
|
||||
if (!Util.isOffline(SelectArtistActivity.this)) {
|
||||
musicFolders = musicService.getMusicFolders(SelectArtistActivity.this, this);
|
||||
}
|
||||
String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
|
||||
return musicService.getIndexes(musicFolderId, refresh, SelectArtistActivity.this, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done(Indexes result) {
|
||||
if (result != null) {
|
||||
List<Artist> artists = new ArrayList<Artist>(result.getShortcuts().size() + result.getArtists().size());
|
||||
artists.addAll(result.getShortcuts());
|
||||
artists.addAll(result.getArtists());
|
||||
artistList.setAdapter(new ArtistAdapter(SelectArtistActivity.this, artists));
|
||||
}
|
||||
|
||||
// Display selected music folder
|
||||
if (musicFolders != null) {
|
||||
String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
task.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
if (view == folderButton) {
|
||||
selectFolder();
|
||||
} else {
|
||||
Artist artist = (Artist) parent.getItemAtPosition(position);
|
||||
Intent intent = new Intent(this, SelectAlbumActivity.class);
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
|
||||
Util.startActivityWithoutTransition(this, intent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
super.onCreateContextMenu(menu, view, menuInfo);
|
||||
|
||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
|
||||
if (artistList.getItemAtPosition(info.position) instanceof Artist) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.select_artist_context, menu);
|
||||
} else if (info.position == 0) {
|
||||
String musicFolderId = Util.getSelectedMusicFolderId(this);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem menuItem) {
|
||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
|
||||
|
||||
Artist artist = (Artist) artistList.getItemAtPosition(info.position);
|
||||
|
||||
if (artist != null) {
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.artist_menu_play_now:
|
||||
downloadRecursively(artist.getId(), false, false, true);
|
||||
break;
|
||||
case R.id.artist_menu_play_last:
|
||||
downloadRecursively(artist.getId(), false, true, false);
|
||||
break;
|
||||
case R.id.artist_menu_pin:
|
||||
downloadRecursively(artist.getId(), true, true, false);
|
||||
break;
|
||||
default:
|
||||
return super.onContextItemSelected(menuItem);
|
||||
}
|
||||
} 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 ? getString(R.string.select_artist_all_folders)
|
||||
: selectedFolder.getName();
|
||||
Util.setSelectedMusicFolderId(this, musicFolderId);
|
||||
folderName.setText(musicFolderName);
|
||||
refresh();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
|
||||
case R.id.menu_refresh:
|
||||
refresh();
|
||||
return true;
|
||||
|
||||
case R.id.main_shuffle:
|
||||
Intent intent = new Intent(this, DownloadActivity.class);
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
|
||||
Util.startActivityWithoutTransition(this, intent);
|
||||
return true;
|
||||
|
||||
case R.id.menu_exit:
|
||||
Intent intent1 = new Intent(this, MainActivity.class);
|
||||
intent1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
intent1.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
|
||||
Util.startActivityWithoutTransition(this, intent1);
|
||||
return true;
|
||||
|
||||
case R.id.menu_settings:
|
||||
startActivity(new Intent(this, SettingsActivity.class));
|
||||
return true;
|
||||
|
||||
case R.id.menu_help:
|
||||
startActivity(new Intent(this, HelpActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,323 +1,334 @@
|
|||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
package net.sourceforge.subsonic.androidapp.activity;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.provider.SearchRecentSuggestions;
|
||||
import android.util.Log;
|
||||
import net.sourceforge.subsonic.androidapp.R;
|
||||
import net.sourceforge.subsonic.androidapp.provider.SearchSuggestionProvider;
|
||||
import net.sourceforge.subsonic.androidapp.service.DownloadService;
|
||||
import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicService;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
|
||||
import net.sourceforge.subsonic.androidapp.util.Constants;
|
||||
import net.sourceforge.subsonic.androidapp.util.ErrorDialog;
|
||||
import net.sourceforge.subsonic.androidapp.util.FileUtil;
|
||||
import net.sourceforge.subsonic.androidapp.util.ModalBackgroundTask;
|
||||
import net.sourceforge.subsonic.androidapp.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SettingsActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private static final String TAG = SettingsActivity.class.getSimpleName();
|
||||
private final Map<String, ServerSettings> serverSettings = new LinkedHashMap<String, ServerSettings>();
|
||||
private boolean testingConnection;
|
||||
private ListPreference theme;
|
||||
private ListPreference maxBitrateWifi;
|
||||
private ListPreference maxBitrateMobile;
|
||||
private ListPreference cacheSize;
|
||||
private EditTextPreference cacheLocation;
|
||||
private ListPreference preloadCount;
|
||||
private ListPreference bufferLength;
|
||||
private ListPreference networkTimeout;
|
||||
private ListPreference maxAlbums;
|
||||
private ListPreference maxSongs;
|
||||
private ListPreference maxArtists;
|
||||
private ListPreference defaultAlbums;
|
||||
private ListPreference defaultSongs;
|
||||
private ListPreference defaultArtists;
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.settings);
|
||||
|
||||
theme = (ListPreference) findPreference(Constants.PREFERENCES_KEY_THEME);
|
||||
maxBitrateWifi = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI);
|
||||
maxBitrateMobile = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE);
|
||||
cacheSize = (ListPreference) findPreference(Constants.PREFERENCES_KEY_CACHE_SIZE);
|
||||
cacheLocation = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_CACHE_LOCATION);
|
||||
preloadCount = (ListPreference) findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT);
|
||||
bufferLength = (ListPreference) findPreference(Constants.PREFERENCES_KEY_BUFFER_LENGTH);
|
||||
networkTimeout = (ListPreference) findPreference(Constants.PREFERENCES_KEY_NETWORK_TIMEOUT);
|
||||
maxAlbums = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_ALBUMS);
|
||||
maxSongs = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_SONGS);
|
||||
maxArtists = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_ARTISTS);
|
||||
defaultArtists = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_ARTISTS);
|
||||
defaultSongs = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_SONGS);
|
||||
defaultAlbums = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_ALBUMS);
|
||||
|
||||
findPreference("testConnection1").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
testConnection(1);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
findPreference("testConnection2").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
testConnection(2);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
findPreference("testConnection3").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
testConnection(3);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
findPreference("clearSearchHistory").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(SettingsActivity.this, SearchSuggestionProvider.AUTHORITY, SearchSuggestionProvider.MODE);
|
||||
suggestions.clearHistory();
|
||||
Util.toast(SettingsActivity.this, R.string.settings_search_history_cleared);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
String instance = String.valueOf(i);
|
||||
serverSettings.put(instance, new ServerSettings(instance));
|
||||
}
|
||||
|
||||
SharedPreferences prefs = Util.getPreferences(this);
|
||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
SharedPreferences prefs = Util.getPreferences(this);
|
||||
prefs.unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
Log.d(TAG, "Preference changed: " + key);
|
||||
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, ""));
|
||||
}
|
||||
}
|
||||
|
||||
private void update() {
|
||||
if (testingConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
theme.setSummary(theme.getEntry());
|
||||
maxBitrateWifi.setSummary(maxBitrateWifi.getEntry());
|
||||
maxBitrateMobile.setSummary(maxBitrateMobile.getEntry());
|
||||
cacheSize.setSummary(cacheSize.getEntry());
|
||||
cacheLocation.setSummary(cacheLocation.getText());
|
||||
preloadCount.setSummary(preloadCount.getEntry());
|
||||
bufferLength.setSummary(bufferLength.getEntry());
|
||||
networkTimeout.setSummary(networkTimeout.getEntry());
|
||||
maxAlbums.setSummary(maxAlbums.getEntry());
|
||||
maxArtists.setSummary(maxArtists.getEntry());
|
||||
maxSongs.setSummary(maxSongs.getEntry());
|
||||
defaultAlbums.setSummary(defaultAlbums.getEntry());
|
||||
defaultArtists.setSummary(defaultArtists.getEntry());
|
||||
defaultSongs.setSummary(defaultSongs.getEntry());
|
||||
|
||||
for (ServerSettings ss : serverSettings.values()) {
|
||||
ss.update();
|
||||
}
|
||||
}
|
||||
|
||||
private void setHideMedia(boolean hide) {
|
||||
File nomediaDir = new File(FileUtil.getSubsonicDirectory(), ".nomedia");
|
||||
if (hide && !nomediaDir.exists()) {
|
||||
if (!nomediaDir.mkdir()) {
|
||||
Log.w(TAG, "Failed to create " + nomediaDir);
|
||||
}
|
||||
} else if (nomediaDir.exists()) {
|
||||
if (!nomediaDir.delete()) {
|
||||
Log.w(TAG, "Failed to delete " + nomediaDir);
|
||||
}
|
||||
}
|
||||
Util.toast(this, R.string.settings_hide_media_toast, false);
|
||||
}
|
||||
|
||||
private void setMediaButtonsEnabled(boolean enabled) {
|
||||
if (enabled) {
|
||||
Util.registerMediaButtonEventReceiver(this);
|
||||
} else {
|
||||
Util.unregisterMediaButtonEventReceiver(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCacheLocation(String path) {
|
||||
File dir = new File(path);
|
||||
if (!FileUtil.ensureDirectoryExistsAndIsReadWritable(dir)) {
|
||||
Util.toast(this, R.string.settings_cache_location_error, false);
|
||||
|
||||
// Reset it to the default.
|
||||
String defaultPath = FileUtil.getDefaultMusicDirectory().getPath();
|
||||
if (!defaultPath.equals(path)) {
|
||||
SharedPreferences prefs = Util.getPreferences(this);
|
||||
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 = DownloadServiceImpl.getInstance();
|
||||
downloadService.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void testConnection(final int instance) {
|
||||
ModalBackgroundTask<Boolean> task = new ModalBackgroundTask<Boolean>(this, false) {
|
||||
private int previousInstance;
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground() throws Throwable {
|
||||
updateProgress(R.string.settings_testing_connection);
|
||||
|
||||
previousInstance = Util.getActiveServer(SettingsActivity.this);
|
||||
testingConnection = true;
|
||||
Util.setActiveServer(SettingsActivity.this, instance);
|
||||
try {
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(SettingsActivity.this);
|
||||
musicService.ping(SettingsActivity.this, this);
|
||||
return musicService.isLicenseValid(SettingsActivity.this, null);
|
||||
} finally {
|
||||
Util.setActiveServer(SettingsActivity.this, previousInstance);
|
||||
testingConnection = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done(Boolean licenseValid) {
|
||||
if (licenseValid) {
|
||||
Util.toast(SettingsActivity.this, R.string.settings_testing_ok);
|
||||
} else {
|
||||
Util.toast(SettingsActivity.this, R.string.settings_testing_unlicensed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancel() {
|
||||
super.cancel();
|
||||
Util.setActiveServer(SettingsActivity.this, previousInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void error(Throwable error) {
|
||||
Log.w(TAG, error.toString(), error);
|
||||
new ErrorDialog(SettingsActivity.this, getResources().getString(R.string.settings_connection_failure) +
|
||||
" " + getErrorMessage(error), false);
|
||||
}
|
||||
};
|
||||
task.execute();
|
||||
}
|
||||
|
||||
private class ServerSettings {
|
||||
private EditTextPreference serverName;
|
||||
private EditTextPreference serverUrl;
|
||||
private EditTextPreference username;
|
||||
private PreferenceScreen screen;
|
||||
|
||||
private ServerSettings(String instance) {
|
||||
|
||||
screen = (PreferenceScreen) findPreference("server" + instance);
|
||||
serverName = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_SERVER_NAME + instance);
|
||||
serverUrl = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_SERVER_URL + instance);
|
||||
username = (EditTextPreference) 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.equals(url.trim()) || url.contains("@")) {
|
||||
throw new Exception();
|
||||
}
|
||||
} catch (Exception x) {
|
||||
new ErrorDialog(SettingsActivity.this, 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(SettingsActivity.this, R.string.settings_invalid_username, false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void update() {
|
||||
serverName.setSummary(serverName.getText());
|
||||
serverUrl.setSummary(serverUrl.getText());
|
||||
username.setSummary(username.getText());
|
||||
screen.setSummary(serverUrl.getText());
|
||||
screen.setTitle(serverName.getText());
|
||||
}
|
||||
}
|
||||
/*
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2009 (C) Sindre Mehus
|
||||
*/
|
||||
package net.sourceforge.subsonic.androidapp.activity;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.provider.SearchRecentSuggestions;
|
||||
import android.util.Log;
|
||||
import net.sourceforge.subsonic.androidapp.R;
|
||||
import net.sourceforge.subsonic.androidapp.provider.SearchSuggestionProvider;
|
||||
import net.sourceforge.subsonic.androidapp.service.DownloadService;
|
||||
import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicService;
|
||||
import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory;
|
||||
import net.sourceforge.subsonic.androidapp.util.Constants;
|
||||
import net.sourceforge.subsonic.androidapp.util.ErrorDialog;
|
||||
import net.sourceforge.subsonic.androidapp.util.FileUtil;
|
||||
import net.sourceforge.subsonic.androidapp.util.ModalBackgroundTask;
|
||||
import net.sourceforge.subsonic.androidapp.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SettingsActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private static final String TAG = SettingsActivity.class.getSimpleName();
|
||||
private final Map<String, ServerSettings> serverSettings = new LinkedHashMap<String, ServerSettings>();
|
||||
private boolean testingConnection;
|
||||
private ListPreference theme;
|
||||
private ListPreference maxBitrateWifi;
|
||||
private ListPreference maxBitrateMobile;
|
||||
private ListPreference cacheSize;
|
||||
private EditTextPreference cacheLocation;
|
||||
private ListPreference preloadCount;
|
||||
private ListPreference bufferLength;
|
||||
private ListPreference networkTimeout;
|
||||
private ListPreference maxAlbums;
|
||||
private ListPreference maxSongs;
|
||||
private ListPreference maxArtists;
|
||||
private ListPreference defaultAlbums;
|
||||
private ListPreference defaultSongs;
|
||||
private ListPreference defaultArtists;
|
||||
private CheckBoxPreference mediaButtonsEnabled;
|
||||
private CheckBoxPreference lockScreenEnabled;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.settings);
|
||||
|
||||
theme = (ListPreference) findPreference(Constants.PREFERENCES_KEY_THEME);
|
||||
maxBitrateWifi = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI);
|
||||
maxBitrateMobile = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE);
|
||||
cacheSize = (ListPreference) findPreference(Constants.PREFERENCES_KEY_CACHE_SIZE);
|
||||
cacheLocation = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_CACHE_LOCATION);
|
||||
preloadCount = (ListPreference) findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT);
|
||||
bufferLength = (ListPreference) findPreference(Constants.PREFERENCES_KEY_BUFFER_LENGTH);
|
||||
networkTimeout = (ListPreference) findPreference(Constants.PREFERENCES_KEY_NETWORK_TIMEOUT);
|
||||
maxAlbums = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_ALBUMS);
|
||||
maxSongs = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_SONGS);
|
||||
maxArtists = (ListPreference) findPreference(Constants.PREFERENCES_KEY_MAX_ARTISTS);
|
||||
defaultArtists = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_ARTISTS);
|
||||
defaultSongs = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_SONGS);
|
||||
defaultAlbums = (ListPreference) findPreference(Constants.PREFERENCES_KEY_DEFAULT_ALBUMS);
|
||||
mediaButtonsEnabled = (CheckBoxPreference) findPreference(Constants.PREFERENCES_KEY_MEDIA_BUTTONS);
|
||||
lockScreenEnabled = (CheckBoxPreference) findPreference(Constants.PREFERENCES_KEY_SHOW_LOCK_SCREEN_CONTROLS);
|
||||
|
||||
findPreference("testConnection1").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
testConnection(1);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
findPreference("testConnection2").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
testConnection(2);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
findPreference("testConnection3").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
testConnection(3);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
findPreference("clearSearchHistory").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(SettingsActivity.this, SearchSuggestionProvider.AUTHORITY, SearchSuggestionProvider.MODE);
|
||||
suggestions.clearHistory();
|
||||
Util.toast(SettingsActivity.this, R.string.settings_search_history_cleared);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
String instance = String.valueOf(i);
|
||||
serverSettings.put(instance, new ServerSettings(instance));
|
||||
}
|
||||
|
||||
SharedPreferences prefs = Util.getPreferences(this);
|
||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
SharedPreferences prefs = Util.getPreferences(this);
|
||||
prefs.unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
Log.d(TAG, "Preference changed: " + key);
|
||||
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, ""));
|
||||
}
|
||||
}
|
||||
|
||||
private void update() {
|
||||
if (testingConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
theme.setSummary(theme.getEntry());
|
||||
maxBitrateWifi.setSummary(maxBitrateWifi.getEntry());
|
||||
maxBitrateMobile.setSummary(maxBitrateMobile.getEntry());
|
||||
cacheSize.setSummary(cacheSize.getEntry());
|
||||
cacheLocation.setSummary(cacheLocation.getText());
|
||||
preloadCount.setSummary(preloadCount.getEntry());
|
||||
bufferLength.setSummary(bufferLength.getEntry());
|
||||
networkTimeout.setSummary(networkTimeout.getEntry());
|
||||
maxAlbums.setSummary(maxAlbums.getEntry());
|
||||
maxArtists.setSummary(maxArtists.getEntry());
|
||||
maxSongs.setSummary(maxSongs.getEntry());
|
||||
defaultAlbums.setSummary(defaultAlbums.getEntry());
|
||||
defaultArtists.setSummary(defaultArtists.getEntry());
|
||||
defaultSongs.setSummary(defaultSongs.getEntry());
|
||||
|
||||
if (!mediaButtonsEnabled.isChecked()) {
|
||||
lockScreenEnabled.setChecked(false);
|
||||
lockScreenEnabled.setEnabled(false);
|
||||
}
|
||||
|
||||
for (ServerSettings ss : serverSettings.values()) {
|
||||
ss.update();
|
||||
}
|
||||
}
|
||||
|
||||
private void setHideMedia(boolean hide) {
|
||||
File nomediaDir = new File(FileUtil.getSubsonicDirectory(), ".nomedia");
|
||||
if (hide && !nomediaDir.exists()) {
|
||||
if (!nomediaDir.mkdir()) {
|
||||
Log.w(TAG, "Failed to create " + nomediaDir);
|
||||
}
|
||||
} else if (nomediaDir.exists()) {
|
||||
if (!nomediaDir.delete()) {
|
||||
Log.w(TAG, "Failed to delete " + nomediaDir);
|
||||
}
|
||||
}
|
||||
Util.toast(this, R.string.settings_hide_media_toast, false);
|
||||
}
|
||||
|
||||
private void setMediaButtonsEnabled(boolean enabled) {
|
||||
if (enabled) {
|
||||
lockScreenEnabled.setEnabled(true);
|
||||
Util.registerMediaButtonEventReceiver(this);
|
||||
} else {
|
||||
lockScreenEnabled.setEnabled(false);
|
||||
Util.unregisterMediaButtonEventReceiver(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCacheLocation(String path) {
|
||||
File dir = new File(path);
|
||||
if (!FileUtil.ensureDirectoryExistsAndIsReadWritable(dir)) {
|
||||
Util.toast(this, R.string.settings_cache_location_error, false);
|
||||
|
||||
// Reset it to the default.
|
||||
String defaultPath = FileUtil.getDefaultMusicDirectory().getPath();
|
||||
if (!defaultPath.equals(path)) {
|
||||
SharedPreferences prefs = Util.getPreferences(this);
|
||||
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 = DownloadServiceImpl.getInstance();
|
||||
downloadService.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void testConnection(final int instance) {
|
||||
ModalBackgroundTask<Boolean> task = new ModalBackgroundTask<Boolean>(this, false) {
|
||||
private int previousInstance;
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground() throws Throwable {
|
||||
updateProgress(R.string.settings_testing_connection);
|
||||
|
||||
previousInstance = Util.getActiveServer(SettingsActivity.this);
|
||||
testingConnection = true;
|
||||
Util.setActiveServer(SettingsActivity.this, instance);
|
||||
try {
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(SettingsActivity.this);
|
||||
musicService.ping(SettingsActivity.this, this);
|
||||
return musicService.isLicenseValid(SettingsActivity.this, null);
|
||||
} finally {
|
||||
Util.setActiveServer(SettingsActivity.this, previousInstance);
|
||||
testingConnection = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done(Boolean licenseValid) {
|
||||
if (licenseValid) {
|
||||
Util.toast(SettingsActivity.this, R.string.settings_testing_ok);
|
||||
} else {
|
||||
Util.toast(SettingsActivity.this, R.string.settings_testing_unlicensed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void cancel() {
|
||||
super.cancel();
|
||||
Util.setActiveServer(SettingsActivity.this, previousInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void error(Throwable error) {
|
||||
Log.w(TAG, error.toString(), error);
|
||||
new ErrorDialog(SettingsActivity.this, getResources().getString(R.string.settings_connection_failure) +
|
||||
" " + getErrorMessage(error), false);
|
||||
}
|
||||
};
|
||||
task.execute();
|
||||
}
|
||||
|
||||
private class ServerSettings {
|
||||
private EditTextPreference serverName;
|
||||
private EditTextPreference serverUrl;
|
||||
private EditTextPreference username;
|
||||
private PreferenceScreen screen;
|
||||
|
||||
private ServerSettings(String instance) {
|
||||
|
||||
screen = (PreferenceScreen) findPreference("server" + instance);
|
||||
serverName = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_SERVER_NAME + instance);
|
||||
serverUrl = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_SERVER_URL + instance);
|
||||
username = (EditTextPreference) 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.equals(url.trim()) || url.contains("@")) {
|
||||
throw new Exception();
|
||||
}
|
||||
} catch (Exception x) {
|
||||
new ErrorDialog(SettingsActivity.this, 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(SettingsActivity.this, R.string.settings_invalid_username, false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void update() {
|
||||
serverName.setSummary(serverName.getText());
|
||||
serverUrl.setSummary(serverUrl.getText());
|
||||
username.setSummary(username.getText());
|
||||
screen.setSummary(serverUrl.getText());
|
||||
screen.setTitle(serverName.getText());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -754,7 +754,6 @@ public class DownloadServiceImpl extends Service implements DownloadService {
|
|||
audioManager.requestAudioFocus(_afChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
|
||||
if (remoteControlClientCompat == null) {
|
||||
audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
|
||||
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
|
||||
intent.setComponent(new ComponentName(this.getPackageName(), MediaButtonIntentReceiver.class.getName()));
|
||||
remoteControlClientCompat = new RemoteControlClientCompat(PendingIntent.getBroadcast(this, 0, intent, 0));
|
||||
|
@ -788,14 +787,14 @@ public class DownloadServiceImpl extends Service implements DownloadService {
|
|||
if (currentSong != currentPlaying.getSong()) {
|
||||
currentSong = currentPlaying.getSong();
|
||||
|
||||
String album = currentPlaying.getSong().getAlbum();
|
||||
String title = currentPlaying.getSong().getArtist() + " - " + currentPlaying.getSong().getTitle();
|
||||
Integer duration = currentPlaying.getSong().getDuration();
|
||||
String album = currentSong.getAlbum();
|
||||
String title = currentSong.getArtist() + " - " + currentSong.getTitle();
|
||||
Integer duration = currentSong.getDuration();
|
||||
|
||||
MusicService musicService = MusicServiceFactory.getMusicService(this);
|
||||
DisplayMetrics metrics = this.getResources().getDisplayMetrics();
|
||||
int size = Math.min(metrics.widthPixels, metrics.heightPixels);
|
||||
Bitmap bitmap = musicService.getCoverArt(this, currentPlaying.getSong(), size, true, null);
|
||||
Bitmap bitmap = musicService.getCoverArt(this, currentSong, size, true, null);
|
||||
|
||||
// Update the remote controls
|
||||
remoteControlClientCompat
|
||||
|
@ -821,7 +820,7 @@ public class DownloadServiceImpl extends Service implements DownloadService {
|
|||
bufferTask.start();
|
||||
}
|
||||
|
||||
private synchronized void doPlay(final DownloadFile downloadFile, int position, boolean start) {
|
||||
private synchronized void doPlay(final DownloadFile downloadFile, final int position, final boolean start) {
|
||||
try {
|
||||
final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile();
|
||||
downloadFile.updateModificationDate();
|
||||
|
@ -834,7 +833,9 @@ public class DownloadServiceImpl extends Service implements DownloadService {
|
|||
@Override
|
||||
public void onBufferingUpdate(MediaPlayer mp, int percent) {
|
||||
SeekBar progressBar = DownloadActivity.getProgressBar();
|
||||
if (progressBar != null) {
|
||||
MusicDirectory.Entry song = downloadFile.getSong();
|
||||
|
||||
if (progressBar != null && song.getTranscodedContentType() == null && Util.getMaxBitrate(getApplicationContext()) == 0) {
|
||||
int secondaryProgress = (int) (((double)percent / (double)100) * progressBar.getMax());
|
||||
DownloadActivity.getProgressBar().setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
|
@ -846,17 +847,40 @@ public class DownloadServiceImpl extends Service implements DownloadService {
|
|||
String url = file.getPath();
|
||||
String playUrl = url;
|
||||
|
||||
if (proxy == null) {
|
||||
proxy = new StreamProxy(this);
|
||||
proxy.start();
|
||||
if (Util.isStreamProxyEnabled(this)) {
|
||||
if (proxy == null) {
|
||||
proxy = new StreamProxy();
|
||||
proxy.start();
|
||||
}
|
||||
|
||||
proxy.setDownloadFile(downloadFile);
|
||||
playUrl = String.format("http://127.0.0.1:%d/%s", proxy.getPort(), url);
|
||||
}
|
||||
|
||||
playUrl = String.format("http://127.0.0.1:%d/%s", proxy.getPort(), url);
|
||||
|
||||
mediaPlayer.setDataSource(playUrl);
|
||||
setPlayerState(PREPARING);
|
||||
mediaPlayer.prepare();
|
||||
setPlayerState(PREPARED);
|
||||
mediaPlayer.prepareAsync();
|
||||
|
||||
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
|
||||
@Override
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
setPlayerState(PREPARED);
|
||||
|
||||
if (position != 0) {
|
||||
Log.i(TAG, "Restarting player from position " + position);
|
||||
mp.seekTo(position);
|
||||
}
|
||||
|
||||
if (start) {
|
||||
mp.start();
|
||||
setPlayerState(STARTED);
|
||||
} else {
|
||||
setPlayerState(PAUSED);
|
||||
}
|
||||
|
||||
lifecycleSupport.serializeDownloadQueue();
|
||||
}
|
||||
});
|
||||
|
||||
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||
@Override
|
||||
|
@ -883,6 +907,7 @@ public class DownloadServiceImpl extends Service implements DownloadService {
|
|||
// Work-around for apparent bug on certain phones: If close (less than ten seconds) to the end
|
||||
// of the song, skip to the next rather than restarting it.
|
||||
Integer duration = downloadFile.getSong().getDuration() == null ? null : downloadFile.getSong().getDuration() * 1000;
|
||||
|
||||
if (duration != null) {
|
||||
if (Math.abs(duration - pos) < 10000) {
|
||||
Log.i(TAG, "Skipping restart from " + pos + " of " + duration);
|
||||
|
@ -898,20 +923,6 @@ public class DownloadServiceImpl extends Service implements DownloadService {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (position != 0) {
|
||||
Log.i(TAG, "Restarting player from position " + position);
|
||||
mediaPlayer.seekTo(position);
|
||||
}
|
||||
|
||||
if (start) {
|
||||
mediaPlayer.start();
|
||||
setPlayerState(STARTED);
|
||||
} else {
|
||||
setPlayerState(PAUSED);
|
||||
}
|
||||
lifecycleSupport.serializeDownloadQueue();
|
||||
|
||||
} catch (Exception x) {
|
||||
handleError(x);
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ public final class Constants {
|
|||
public static final String PREFERENCES_KEY_DEFAULT_ALBUMS = "defaultAlbums";
|
||||
public static final String PREFERENCES_KEY_DEFAULT_SONGS = "defaultSongs";
|
||||
public static final String PREFERENCES_KEY_DEFAULT_ARTISTS = "defaultArtists";
|
||||
public static final String PREFERENCES_KEY_USE_STREAM_PROXY = "useStreamProxy";
|
||||
|
||||
// Name of the preferences file.
|
||||
public static final String PREFERENCES_FILE_NAME = "net.sourceforge.subsonic.androidapp_preferences";
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.apache.http.Header;
|
|||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.message.BasicHttpRequest;
|
||||
|
||||
import net.sourceforge.subsonic.androidapp.service.DownloadFile;
|
||||
import net.sourceforge.subsonic.androidapp.service.DownloadService;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Looper;
|
||||
|
@ -34,21 +35,25 @@ public class StreamProxy implements Runnable {
|
|||
private boolean isRunning;
|
||||
private ServerSocket socket;
|
||||
private int port;
|
||||
private DownloadService downloadService;
|
||||
private DownloadFile downloadFile;
|
||||
|
||||
public StreamProxy(DownloadService downloadService) {
|
||||
public StreamProxy() {
|
||||
|
||||
// Create listening socket
|
||||
try {
|
||||
socket = new ServerSocket(0, 0, InetAddress.getByAddress(new byte[] { 127, 0, 0, 1 }));
|
||||
socket.setSoTimeout(5000);
|
||||
port = socket.getLocalPort();
|
||||
this.downloadService = downloadService;
|
||||
} catch (UnknownHostException e) { // impossible
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "IOException initializing server", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDownloadFile(DownloadFile downloadFile) {
|
||||
this.downloadFile = downloadFile;
|
||||
}
|
||||
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
|
@ -73,38 +78,41 @@ public class StreamProxy implements Runnable {
|
|||
public void run() {
|
||||
Looper.prepare();
|
||||
isRunning = true;
|
||||
|
||||
while (isRunning) {
|
||||
try {
|
||||
Socket client = socket.accept();
|
||||
|
||||
if (client == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.d(TAG, "client connected");
|
||||
|
||||
StreamToMediaPlayerTask task = new StreamToMediaPlayerTask(client);
|
||||
|
||||
if (task.processRequest()) {
|
||||
task.execute();
|
||||
}
|
||||
|
||||
} catch (SocketTimeoutException e) {
|
||||
// Do nothing
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error connecting to client", e);
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "Proxy interrupted. Shutting down.");
|
||||
}
|
||||
|
||||
private class StreamToMediaPlayerTask extends AsyncTask<String, Void, Integer> {
|
||||
|
||||
String localPath;
|
||||
File thisFile;
|
||||
Socket client;
|
||||
int cbSkip;
|
||||
|
||||
public StreamToMediaPlayerTask(Socket client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
|
||||
private HttpRequest readRequest() {
|
||||
HttpRequest request = null;
|
||||
InputStream is;
|
||||
|
@ -135,107 +143,114 @@ public class StreamProxy implements Runnable {
|
|||
|
||||
public boolean processRequest() {
|
||||
HttpRequest request = readRequest();
|
||||
|
||||
if (request == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read HTTP headers
|
||||
|
||||
Log.d(TAG, "Processing request");
|
||||
|
||||
try {
|
||||
localPath = URLDecoder.decode(request.getRequestLine().getUri(), Constants.UTF_8);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.e(TAG, "Unsupported encoding", e);
|
||||
thisFile = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile();
|
||||
|
||||
if (!thisFile.exists()) {
|
||||
Log.e(TAG, "File " + thisFile.getPath() + " does not exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
File file = new File(localPath);
|
||||
if (!file.exists()) {
|
||||
Log.e(TAG, "File " + localPath + " does not exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(String... params) {
|
||||
long fileSize = downloadService.getCurrentPlaying().getSong().getSize();
|
||||
protected Integer doInBackground(String... params) {
|
||||
long fileSize = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile().length() : downloadFile.getSong().getSize();
|
||||
|
||||
// Create HTTP header
|
||||
String headers = "HTTP/1.0 200 OK\r\n";
|
||||
headers += "Content-Type: " + "application/octet-stream" + "\r\n";
|
||||
|
||||
if (fileSize > 0) {
|
||||
headers += "Content-Length: " + fileSize + "\r\n";
|
||||
}
|
||||
|
||||
headers += "Connection: close\r\n";
|
||||
headers += "\r\n";
|
||||
// Create HTTP header
|
||||
String headers = "HTTP/1.1 200 OK\r\n";
|
||||
|
||||
long cbToSend = fileSize - cbSkip;
|
||||
OutputStream output = null;
|
||||
byte[] buff = new byte[64 * 1024];
|
||||
try {
|
||||
output = new BufferedOutputStream(client.getOutputStream(), 32*1024);
|
||||
output.write(headers.getBytes());
|
||||
if (fileSize > 0) {
|
||||
headers += "Content-Length: " + fileSize + "\r\n";
|
||||
}
|
||||
|
||||
headers += "Accept-Ranges: bytes\r\n";
|
||||
headers += "Content-Type: " + "application/octet-stream" + "\r\n";
|
||||
headers += "Connection: close\r\n";
|
||||
headers += "\r\n";
|
||||
|
||||
// Loop as long as there's stuff to send
|
||||
while (isRunning && cbToSend>0 && !client.isClosed()) {
|
||||
long cbToSend = fileSize - cbSkip;
|
||||
long totalBytesSent = 0;
|
||||
OutputStream output = null;
|
||||
byte[] buff = new byte[64 * 1024];
|
||||
|
||||
try {
|
||||
output = new BufferedOutputStream(client.getOutputStream(), 32 * 1024);
|
||||
output.write(headers.getBytes());
|
||||
|
||||
// Loop as long as there's stuff to send
|
||||
while (isRunning && cbToSend > 0 && !client.isClosed()) {
|
||||
// See if there's more to send
|
||||
int cbSentThisBatch = 0;
|
||||
|
||||
// See if there's more to send
|
||||
File file = new File(localPath);
|
||||
int cbSentThisBatch = 0;
|
||||
if (file.exists()) {
|
||||
FileInputStream input = new FileInputStream(file);
|
||||
input.skip(cbSkip);
|
||||
int cbToSendThisBatch = input.available();
|
||||
while (cbToSendThisBatch > 0) {
|
||||
int cbToRead = Math.min(cbToSendThisBatch, buff.length);
|
||||
int cbRead = input.read(buff, 0, cbToRead);
|
||||
if (cbRead == -1) {
|
||||
break;
|
||||
}
|
||||
cbToSendThisBatch -= cbRead;
|
||||
cbToSend -= cbRead;
|
||||
output.write(buff, 0, cbRead);
|
||||
output.flush();
|
||||
cbSkip += cbRead;
|
||||
cbSentThisBatch += cbRead;
|
||||
}
|
||||
input.close();
|
||||
}
|
||||
FileInputStream input = new FileInputStream(thisFile);
|
||||
input.skip(cbSkip);
|
||||
int cbToSendThisBatch = input.available();
|
||||
|
||||
// If we did nothing this batch, block for a second
|
||||
if (cbSentThisBatch == 0) {
|
||||
Log.d(TAG, "Blocking until more data appears");
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SocketException socketException) {
|
||||
Log.e(TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly");
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.e(TAG, "Exception thrown from streaming task:");
|
||||
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
while (cbToSendThisBatch > 0) {
|
||||
int cbToRead = Math.min(cbToSendThisBatch, buff.length);
|
||||
int cbRead = input.read(buff, 0, cbToRead);
|
||||
|
||||
// Cleanup
|
||||
try {
|
||||
if (output != null) {
|
||||
output.close();
|
||||
}
|
||||
client.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
Log.e(TAG, "IOException while cleaning up streaming task:");
|
||||
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (cbRead == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
cbToSendThisBatch -= cbRead;
|
||||
cbToSend -= cbRead;
|
||||
|
||||
output.write(buff, 0, cbRead);
|
||||
output.flush();
|
||||
|
||||
cbSkip += cbRead;
|
||||
cbSentThisBatch += cbRead;
|
||||
totalBytesSent += cbRead;
|
||||
}
|
||||
|
||||
input.close();
|
||||
|
||||
if (!downloadFile.isDownloading()) {
|
||||
if (downloadFile.isCompleteFileAvailable()) {
|
||||
if (downloadFile.getCompleteFile().length() == totalBytesSent) {
|
||||
Log.d(TAG, "Track is no longer being downloaded, sent " + totalBytesSent + " / " + fileSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we did nothing this batch, block for a second
|
||||
if (cbSentThisBatch == 0) {
|
||||
Log.d(TAG, "Blocking until more data appears");
|
||||
Thread.sleep(500);
|
||||
}
|
||||
}
|
||||
} catch (SocketException socketException) {
|
||||
Log.e(TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly");
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Exception thrown from streaming task:");
|
||||
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
try {
|
||||
if (output != null) {
|
||||
output.close();
|
||||
}
|
||||
client.close();
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "IOException while cleaning up streaming task:");
|
||||
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -146,6 +146,11 @@ public class Util extends DownloadActivity {
|
|||
SharedPreferences prefs = getPreferences(context);
|
||||
return prefs.getBoolean(Constants.PREFERENCES_KEY_SHOW_LOCK_SCREEN_CONTROLS, false);
|
||||
}
|
||||
|
||||
public static boolean isStreamProxyEnabled(Context context) {
|
||||
SharedPreferences prefs = getPreferences(context);
|
||||
return prefs.getBoolean(Constants.PREFERENCES_KEY_USE_STREAM_PROXY, false);
|
||||
}
|
||||
|
||||
public static void setActiveServer(Context context, int instance) {
|
||||
SharedPreferences prefs = getPreferences(context);
|
||||
|
|
Loading…
Reference in New Issue