Make StreamProxy optional, prepareAsync for MediaPlayer, code fixups in StreamProxy

This commit is contained in:
Joshua Bahnsen 2013-02-10 21:30:46 -07:00
parent d8418254ef
commit 793f5b4464
10 changed files with 1971 additions and 1916 deletions

View File

@ -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

View File

@ -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&#8230;</string>
<string name="play_video.loading">Loading video&#8230;</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&#8230;</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&#8230;</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\"&#8230;</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 &gt; 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&#8230;</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&#8230;</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&#8230;</string>
<string name="play_video.loading">Loading video&#8230;</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&#8230;</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&#8230;</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\"&#8230;</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 &gt; 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&#8230;</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&#8230;</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>

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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());
}
}
}

View File

@ -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);
}

View File

@ -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";

View File

@ -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;
}
}
}

View File

@ -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);