From 93b62c79b12cf569c396dd3d863845060949108f Mon Sep 17 00:00:00 2001 From: Joshua Bahnsen Date: Sun, 19 May 2013 23:33:40 -0700 Subject: [PATCH] Try to limit memory usage on images, fix Play Next --- AndroidManifest.xml | 4 +- gen/com/handmark/pulltorefresh/library/R.java | 14 +- .../thejoshwa/ultrasonic/androidapp/R.java | 216 ++++---- res/layout-land/download.xml | 3 +- res/layout-port/download.xml | 3 +- res/layout/notification.xml | 190 ++++--- res/layout/notification_large.xml | 113 +++++ res/values-hu/strings.xml | 77 +-- .../androidapp/activity/DownloadActivity.java | 6 +- .../activity/SelectAlbumActivity.java | 11 +- .../activity/SelectPlaylistActivity.java | 1 - .../activity/SubsonicTabActivity.java | 464 +++++++++++++----- .../UltraSonicAppWidgetProvider4x1.java | 2 +- .../service/CachedMusicService.java | 4 +- .../androidapp/service/DownloadFile.java | 5 +- .../service/DownloadServiceImpl.java | 104 ++-- .../androidapp/service/MusicService.java | 3 +- .../service/OfflineMusicService.java | 4 +- .../androidapp/service/RESTMusicService.java | 4 +- .../ultrasonic/androidapp/util/Constants.java | 1 + .../ultrasonic/androidapp/util/FileUtil.java | 38 +- .../androidapp/util/ImageLoader.java | 107 ++-- .../ultrasonic/androidapp/util/Util.java | 304 ++++++------ .../ultrasonic/androidapp/view/AlbumView.java | 2 +- 24 files changed, 986 insertions(+), 694 deletions(-) create mode 100644 res/layout/notification_large.xml diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 7953e77f..012bf27e 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2,8 +2,8 @@ + a:versionCode="22" + a:versionName="1.1.0.18" > diff --git a/gen/com/handmark/pulltorefresh/library/R.java b/gen/com/handmark/pulltorefresh/library/R.java index 6d6250b4..370f1f7c 100644 --- a/gen/com/handmark/pulltorefresh/library/R.java +++ b/gen/com/handmark/pulltorefresh/library/R.java @@ -51,7 +51,7 @@ public final class R { public static final class id { public static final int both = 0x7f060003; public static final int disabled = 0x7f060000; - public static final int fl_inner = 0x7f06007f; + public static final int fl_inner = 0x7f06007e; public static final int flip = 0x7f060008; public static final int gridview = 0x7f060009; public static final int manualOnly = 0x7f060004; @@ -59,17 +59,17 @@ public final class R { public static final int pullFromEnd = 0x7f060002; public static final int pullFromStart = 0x7f060001; public static final int pullUpFromBottom = 0x7f060006; - public static final int pull_to_refresh_image = 0x7f060080; - public static final int pull_to_refresh_progress = 0x7f060081; - public static final int pull_to_refresh_sub_text = 0x7f060083; - public static final int pull_to_refresh_text = 0x7f060082; + public static final int pull_to_refresh_image = 0x7f06007f; + public static final int pull_to_refresh_progress = 0x7f060080; + public static final int pull_to_refresh_sub_text = 0x7f060082; + public static final int pull_to_refresh_text = 0x7f060081; public static final int rotate = 0x7f060007; public static final int scrollview = 0x7f06000b; public static final int webview = 0x7f06000a; } public static final class layout { - public static final int pull_to_refresh_header_horizontal = 0x7f030018; - public static final int pull_to_refresh_header_vertical = 0x7f030019; + public static final int pull_to_refresh_header_horizontal = 0x7f030019; + public static final int pull_to_refresh_header_vertical = 0x7f03001a; } public static final class string { public static final int pull_to_refresh_from_bottom_pull_label = 0x7f080003; diff --git a/gen/com/thejoshwa/ultrasonic/androidapp/R.java b/gen/com/thejoshwa/ultrasonic/androidapp/R.java index c1845fee..e543635f 100644 --- a/gen/com/thejoshwa/ultrasonic/androidapp/R.java +++ b/gen/com/thejoshwa/ultrasonic/androidapp/R.java @@ -584,27 +584,27 @@ or to a theme attribute in the form "?[package:][type:]na public static final int unknown_album_large=0x7f02008e; } public static final class id { - public static final int album=0x7f060074; + public static final int album=0x7f060073; public static final int album_artist=0x7f06001d; public static final int album_coverart=0x7f06001b; - public static final int album_menu_pin=0x7f0600bc; - public static final int album_menu_play_last=0x7f0600bb; - public static final int album_menu_play_next=0x7f0600ba; - public static final int album_menu_play_now=0x7f0600b9; + public static final int album_menu_pin=0x7f0600bb; + public static final int album_menu_play_last=0x7f0600ba; + public static final int album_menu_play_next=0x7f0600b9; + public static final int album_menu_play_now=0x7f0600b8; public static final int album_star=0x7f06001e; public static final int album_title=0x7f06001c; public static final int appwidget_coverart=0x7f06001f; public static final int appwidget_top=0x7f060021; public static final int artist=0x7f060023; - public static final int artist_menu_pin=0x7f0600c0; - public static final int artist_menu_play_last=0x7f0600bf; - public static final int artist_menu_play_next=0x7f0600be; - public static final int artist_menu_play_now=0x7f0600bd; + public static final int artist_menu_pin=0x7f0600bf; + public static final int artist_menu_play_last=0x7f0600be; + public static final int artist_menu_play_next=0x7f0600bd; + public static final int artist_menu_play_now=0x7f0600bc; public static final int both=0x7f060003; public static final int control_next=0x7f060026; public static final int control_play=0x7f060025; public static final int control_previous=0x7f060024; - public static final int control_stop=0x7f060075; + public static final int control_stop=0x7f060074; public static final int disabled=0x7f060000; public static final int download_album=0x7f060032; public static final int download_album_art_image=0x7f06002c; @@ -614,8 +614,8 @@ or to a theme attribute in the form "?[package:][type:]na public static final int download_control_layout=0x7f060027; public static final int download_duration=0x7f060030; public static final int download_empty=0x7f060033; - public static final int download_equalizer=0x7f0600ae; - public static final int download_jukebox=0x7f0600b0; + public static final int download_equalizer=0x7f0600ad; + public static final int download_jukebox=0x7f0600af; public static final int download_list=0x7f060034; public static final int download_next=0x7f060062; public static final int download_pause=0x7f060060; @@ -631,7 +631,7 @@ or to a theme attribute in the form "?[package:][type:]na public static final int download_status=0x7f060028; public static final int download_stop=0x7f060061; public static final int download_toggle_list=0x7f06005c; - public static final int download_visualizer=0x7f0600af; + public static final int download_visualizer=0x7f0600ae; public static final int download_visualizer_view_layout=0x7f06002d; public static final int equalizer_bar=0x7f06003b; public static final int equalizer_frequency=0x7f060039; @@ -639,14 +639,14 @@ or to a theme attribute in the form "?[package:][type:]na public static final int equalizer_enabled=0x7f060036; public static final int equalizer_layout=0x7f060037; public static final int equalizer_preset=0x7f060038; - public static final int fl_inner=0x7f06007f; + public static final int fl_inner=0x7f06007e; public static final int flip=0x7f060008; - public static final int get_playlist_comment=0x7f0600aa; - public static final int get_playlist_comment_label=0x7f0600a9; - public static final int get_playlist_name=0x7f0600a8; - public static final int get_playlist_name_label=0x7f0600a7; - public static final int get_playlist_public=0x7f0600ac; - public static final int get_playlist_public_label=0x7f0600ab; + public static final int get_playlist_comment=0x7f0600a9; + public static final int get_playlist_comment_label=0x7f0600a8; + public static final int get_playlist_name=0x7f0600a7; + public static final int get_playlist_name_label=0x7f0600a6; + public static final int get_playlist_public=0x7f0600ab; + public static final int get_playlist_public_label=0x7f0600aa; public static final int gridview=0x7f060009; public static final int help_back=0x7f06003d; public static final int help_buttons=0x7f06003c; @@ -677,7 +677,7 @@ or to a theme attribute in the form "?[package:][type:]na public static final int main_list=0x7f060047; public static final int main_music=0x7f06004c; public static final int main_select_server=0x7f060049; - public static final int main_shuffle=0x7f0600ad; + public static final int main_shuffle=0x7f0600ac; public static final int main_songs=0x7f060050; public static final int main_songs_button=0x7f060051; public static final int main_songs_starred=0x7f060052; @@ -706,99 +706,98 @@ or to a theme attribute in the form "?[package:][type:]na public static final int menu_common=0x7f06006c; public static final int menu_exit=0x7f06006f; public static final int menu_home=0x7f060067; - public static final int menu_lyrics=0x7f0600b5; + public static final int menu_lyrics=0x7f0600b4; public static final int menu_main=0x7f060065; public static final int menu_navigation=0x7f060066; public static final int menu_now_playing=0x7f06006b; public static final int menu_playlists=0x7f06006a; - public static final int menu_remove=0x7f0600b6; - public static final int menu_remove_all=0x7f0600b2; - public static final int menu_save_playlist=0x7f0600b1; - public static final int menu_screen_on_off=0x7f0600b3; + public static final int menu_remove=0x7f0600b5; + public static final int menu_remove_all=0x7f0600b1; + public static final int menu_save_playlist=0x7f0600b0; + public static final int menu_screen_on_off=0x7f0600b2; public static final int menu_search=0x7f060069; public static final int menu_settings=0x7f06006d; - public static final int menu_show_album=0x7f0600b4; - public static final int menu_shuffle=0x7f0600b7; + public static final int menu_show_album=0x7f0600b3; + public static final int menu_shuffle=0x7f0600b6; public static final int notification_image=0x7f060071; - public static final int now_playing=0x7f060076; - public static final int now_playing_artist=0x7f06007a; - public static final int now_playing_control_play=0x7f06007b; - public static final int now_playing_image=0x7f060078; - public static final int now_playing_trackname=0x7f060079; - public static final int now_playing_view=0x7f060077; - public static final int play_video_contents=0x7f06007c; - public static final int playlist_info=0x7f0600c1; - public static final int playlist_menu_delete=0x7f0600c6; - public static final int playlist_menu_pin=0x7f0600c4; - public static final int playlist_menu_play_now=0x7f0600c2; - public static final int playlist_menu_play_shuffled=0x7f0600c3; - public static final int playlist_name=0x7f06007d; - public static final int playlist_update_info=0x7f0600c5; - public static final int progress_message=0x7f06007e; + public static final int now_playing=0x7f060075; + public static final int now_playing_artist=0x7f060079; + public static final int now_playing_control_play=0x7f06007a; + public static final int now_playing_image=0x7f060077; + public static final int now_playing_trackname=0x7f060078; + public static final int now_playing_view=0x7f060076; + public static final int play_video_contents=0x7f06007b; + public static final int playlist_info=0x7f0600c0; + public static final int playlist_menu_delete=0x7f0600c5; + public static final int playlist_menu_pin=0x7f0600c3; + public static final int playlist_menu_play_now=0x7f0600c1; + public static final int playlist_menu_play_shuffled=0x7f0600c2; + public static final int playlist_name=0x7f06007c; + public static final int playlist_update_info=0x7f0600c4; + public static final int progress_message=0x7f06007d; public static final int pullDownFromTop=0x7f060005; public static final int pullFromEnd=0x7f060002; public static final int pullFromStart=0x7f060001; public static final int pullUpFromBottom=0x7f060006; - public static final int pull_to_refresh_image=0x7f060080; - public static final int pull_to_refresh_progress=0x7f060081; - public static final int pull_to_refresh_sub_text=0x7f060083; - public static final int pull_to_refresh_text=0x7f060082; + public static final int pull_to_refresh_image=0x7f06007f; + public static final int pull_to_refresh_progress=0x7f060080; + public static final int pull_to_refresh_sub_text=0x7f060082; + public static final int pull_to_refresh_text=0x7f060081; public static final int rotate=0x7f060007; - public static final int save_playlist_name=0x7f060085; - public static final int save_playlist_root=0x7f060084; + public static final int save_playlist_name=0x7f060084; + public static final int save_playlist_root=0x7f060083; public static final int scrollview=0x7f06000b; - public static final int search_albums=0x7f060089; - public static final int search_artists=0x7f060088; - public static final int search_list=0x7f060086; - public static final int search_more_albums=0x7f06008c; - public static final int search_more_artists=0x7f06008b; - public static final int search_more_songs=0x7f06008d; - public static final int search_search=0x7f060087; - public static final int search_songs=0x7f06008a; - public static final int select_album_art=0x7f060090; - public static final int select_album_artist=0x7f060092; + public static final int search_albums=0x7f060088; + public static final int search_artists=0x7f060087; + public static final int search_list=0x7f060085; + public static final int search_more_albums=0x7f06008b; + public static final int search_more_artists=0x7f06008a; + public static final int search_more_songs=0x7f06008c; + public static final int search_search=0x7f060086; + public static final int search_songs=0x7f060089; + public static final int select_album_art=0x7f06008f; + public static final int select_album_artist=0x7f060091; public static final int select_album_delete=0x7f060019; - public static final int select_album_duration=0x7f060095; - public static final int select_album_empty=0x7f06008e; - public static final int select_album_entries=0x7f06008f; - public static final int select_album_genre=0x7f060093; + public static final int select_album_duration=0x7f060094; + public static final int select_album_empty=0x7f06008d; + public static final int select_album_entries=0x7f06008e; + public static final int select_album_genre=0x7f060092; public static final int select_album_more=0x7f06001a; public static final int select_album_pin=0x7f060017; - public static final int select_album_play_all=0x7f0600b8; + public static final int select_album_play_all=0x7f0600b7; public static final int select_album_play_last=0x7f060016; public static final int select_album_play_next=0x7f060015; public static final int select_album_play_now=0x7f060014; public static final int select_album_select=0x7f060013; - public static final int select_album_song_count=0x7f060094; - public static final int select_album_title=0x7f060091; + public static final int select_album_song_count=0x7f060093; + public static final int select_album_title=0x7f060090; public static final int select_album_unpin=0x7f060018; - public static final int select_artist_folder=0x7f060097; - public static final int select_artist_folder_1=0x7f060098; - public static final int select_artist_folder_2=0x7f060099; - public static final int select_artist_list=0x7f060096; - public static final int select_genre_empty=0x7f06009a; - public static final int select_genre_list=0x7f06009b; - public static final int select_playlist_empty=0x7f06009c; - public static final int select_playlist_list=0x7f06009d; - public static final int song_artist=0x7f0600a2; - public static final int song_check=0x7f06009e; - public static final int song_duration=0x7f0600a3; - public static final int song_menu_pin=0x7f0600ca; - public static final int song_menu_play_last=0x7f0600c9; - public static final int song_menu_play_next=0x7f0600c8; - public static final int song_menu_play_now=0x7f0600c7; - public static final int song_menu_unpin=0x7f0600cb; - public static final int song_star=0x7f0600a4; - public static final int song_status=0x7f0600a1; - public static final int song_title=0x7f0600a0; - public static final int song_track=0x7f06009f; - public static final int status_icon=0x7f060072; + public static final int select_artist_folder=0x7f060096; + public static final int select_artist_folder_1=0x7f060097; + public static final int select_artist_folder_2=0x7f060098; + public static final int select_artist_list=0x7f060095; + public static final int select_genre_empty=0x7f060099; + public static final int select_genre_list=0x7f06009a; + public static final int select_playlist_empty=0x7f06009b; + public static final int select_playlist_list=0x7f06009c; + public static final int song_artist=0x7f0600a1; + public static final int song_check=0x7f06009d; + public static final int song_duration=0x7f0600a2; + public static final int song_menu_pin=0x7f0600c9; + public static final int song_menu_play_last=0x7f0600c8; + public static final int song_menu_play_next=0x7f0600c7; + public static final int song_menu_play_now=0x7f0600c6; + public static final int song_menu_unpin=0x7f0600ca; + public static final int song_star=0x7f0600a3; + public static final int song_status=0x7f0600a0; + public static final int song_title=0x7f06009f; + public static final int song_track=0x7f06009e; public static final int statusbar=0x7f060070; - public static final int tab_progress=0x7f0600a5; - public static final int tab_progress_message=0x7f0600a6; + public static final int tab_progress=0x7f0600a4; + public static final int tab_progress_message=0x7f0600a5; public static final int title=0x7f060022; public static final int toast_layout_root=0x7f060041; - public static final int trackname=0x7f060073; + public static final int trackname=0x7f060072; public static final int webview=0x7f06000a; } public static final class integer { @@ -826,24 +825,25 @@ or to a theme attribute in the form "?[package:][type:]na public static final int menu_row_category=0x7f030011; public static final int menu_row_item=0x7f030012; public static final int notification=0x7f030013; - public static final int now_playing=0x7f030014; - public static final int play_video=0x7f030015; - public static final int playlist_list_item=0x7f030016; - public static final int progress=0x7f030017; - public static final int pull_to_refresh_header_horizontal=0x7f030018; - public static final int pull_to_refresh_header_vertical=0x7f030019; - public static final int save_playlist=0x7f03001a; - public static final int search=0x7f03001b; - public static final int search_buttons=0x7f03001c; - public static final int select_album=0x7f03001d; - public static final int select_album_header=0x7f03001e; - public static final int select_artist=0x7f03001f; - public static final int select_artist_header=0x7f030020; - public static final int select_genre=0x7f030021; - public static final int select_playlist=0x7f030022; - public static final int song_list_item=0x7f030023; - public static final int tab_progress=0x7f030024; - public static final int update_playlist=0x7f030025; + public static final int notification_large=0x7f030014; + public static final int now_playing=0x7f030015; + public static final int play_video=0x7f030016; + public static final int playlist_list_item=0x7f030017; + public static final int progress=0x7f030018; + public static final int pull_to_refresh_header_horizontal=0x7f030019; + public static final int pull_to_refresh_header_vertical=0x7f03001a; + public static final int save_playlist=0x7f03001b; + public static final int search=0x7f03001c; + public static final int search_buttons=0x7f03001d; + public static final int select_album=0x7f03001e; + public static final int select_album_header=0x7f03001f; + public static final int select_artist=0x7f030020; + public static final int select_artist_header=0x7f030021; + public static final int select_genre=0x7f030022; + public static final int select_playlist=0x7f030023; + public static final int song_list_item=0x7f030024; + public static final int tab_progress=0x7f030025; + public static final int update_playlist=0x7f030026; } public static final class menu { public static final int main=0x7f0e0000; diff --git a/res/layout-land/download.xml b/res/layout-land/download.xml index 0c9d5cae..ae382f0f 100644 --- a/res/layout-land/download.xml +++ b/res/layout-land/download.xml @@ -81,7 +81,8 @@ a:layout_height="60dip" a:layout_gravity="bottom|center_horizontal" a:layout_marginLeft="60dip" - a:layout_marginRight="60dip" /> + a:layout_marginRight="60dip" + a:orientation="vertical" /> diff --git a/res/layout-port/download.xml b/res/layout-port/download.xml index ccc0dd9a..88da3109 100644 --- a/res/layout-port/download.xml +++ b/res/layout-port/download.xml @@ -58,7 +58,8 @@ a:layout_above="@+id/download_song_title" a:layout_gravity="center_horizontal" a:layout_marginLeft="80dip" - a:layout_marginRight="80dip" /> + a:layout_marginRight="80dip" + a:orientation="vertical" /> diff --git a/res/layout/notification.xml b/res/layout/notification.xml index efd7f8b4..df3a59dc 100644 --- a/res/layout/notification.xml +++ b/res/layout/notification.xml @@ -1,112 +1,102 @@ - + - + - + - + - + - + + - + - - + - + - + - + + - - - - + \ No newline at end of file diff --git a/res/layout/notification_large.xml b/res/layout/notification_large.xml new file mode 100644 index 00000000..1132c53e --- /dev/null +++ b/res/layout/notification_large.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index 2e6a6099..776c303c 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -7,17 +7,18 @@ Lejátszás Lejátszás (Következőként) Lejátszás (Utolsóként) - Megjelöl - Megjelölés visszavonása + Kijelöl + Visszavon Törlés Különféle előadók Többféle műfaj Részletek Véletlen sorrendű lejátszás - Jóváhagy + Jóváhagyás Név Megjegyzés - Nyilvános + Nyilvános + Előadó megjelenítése UltraSonic főoldal Médiakönyvtár Keresés @@ -40,8 +41,8 @@ Legjobbra értékelt Véletlenszerű Csillagozott - Név szerint - Előadó szerint + Albumnév szerint + Előadónév szerint Dalok Csillagozott Véletlenszerű @@ -59,17 +60,17 @@ Törölt lejátszási lista %s Lejátszási lista törlése sikertelen %s Lejátszási listák - Információk frissítése - Frissített lejátszási lista információ %s - Lejátszási lista információinak frissítése sikertelen %s + Módosítás + Módosított lejátszási lista %s + Lejátszási lista módosítása sikertelen %s Súgó Üdvözli az UltraSonic! Vissza Bezár file:///android_asset/html/en/index.html Betöltés… - Video betöltése… - Kérjük, telepítse az Adobe Flash Player-t a Play Áruházból. + Videó betöltése… + Kérjük, telepítse az Adobe Flash Player-t a Play Áruházból! Keresés Keresés Érintse meg a kereséshez @@ -78,13 +79,13 @@ Albumok Dalok Továbbiak - Kérem várjon… + Kérem várjon!… Mediakönyvtár Kapcsolat nélküli médiák Nem található média! Összes kijelölése - %d műsorszám kijelölve. - %d műsorszám visszavonva. + %d dal kijelölve. + %d dal visszavonva. Egyéb Kapcsolat nélküli Keresés… @@ -107,8 +108,8 @@ Dalszövegek Dal eltávolítása Összes eltávolítása - Kijelző Be - Kijelző Ki + Kijelző be + Kijelző ki Véletlen sorrendű Lejátszási lista mentése Equalizer @@ -123,8 +124,8 @@ Ismétlés ki Összes ismétlése Dal ismétlése - Visualizer Be - Visualizer Ki + Visualizer be + Visualizer ki Távvezérlés bekapcsolása. A zenelejátszás a kiszolgálón történik. Távvezérlés kikapcsolása. A zenelejátszás a telefonon történik. Távoli hangerő @@ -135,7 +136,7 @@ %1$s dal hozzáadva: \"%2$s\" Frissítés sikertelen: \"%s\", próbálja később! %1$s eltávolítva: \"%2$s\" - Biztos, hogy törölni akarja: %1$s + Biztos, hogy törölni akarja? %1$s %1$s%2$s %d kbps Dalszöveg nem található! @@ -160,8 +161,8 @@ Gyorsítótár helye Hibás gyorsítótár hely! Az alapértelmezett használata. Kapcsolat tesztelése… - Kapcsolat OK - Kapcsolat OK. A kiszolgálónak nincs licence! + Kapcsolat OK! + Kapcsolat OK! A kiszolgálónak nincs licence! Csatlakozási hiba! Adjon meg egy érvényes URL-t! Adjon meg egy érvényes felhasználónevet (szóközt nem tartalmazhat)! @@ -185,12 +186,12 @@ Korlátlan Csak Wi-Fi streaming Streaming, csak ha rendelkezésre áll Wi-Fi kapcsolat. - Bitráta és fájl-utótag megjelenítése - Bitráta és fájl-utótag hozzáfűzése az előadó nevéhez. + Bitráta és fájlkiterjesztés megjelenítése + Bitráta és fájlkiterjesztés megjelenítése az előadónév mellett. Mappanevek használata az előadók neveként Feltételezi, hogy a legfelső szintű mappa az elődó neve. Sorszám megjelenítése - A dal sorszámának megjelenítése. + Dalok sorszámának megjelenítése. 1 dal 2 dal 3 dal @@ -207,14 +208,14 @@ 20 GB Korlátlan Keresési előzmények törlése - Keresési előzmények törölve + Keresési előzmények törölve. Egyéb beállítások Keresés beállításai Lejátszás-vezérlés beállításai Továbbítás Last.fm-re (Scrobbling) A Last.fm felhasználónevet és jelszót be kell állítani a Subsonic kiszolgálón! Albumborító átméretezés (Kiszolgáló-oldali) - A teljes méretű helyett átméretezett képek letöltése a kiszolgálóról (sávszélesség-takarékos). + Teljes méretű helyett átméretezett képek letöltése a kiszolgálóról (sávszélesség-takarékos). Elrejtés Zenefájlok elrejtése egyéb alkalmazások elől. A következő alkalomtól lép életbe, amikor az Android zenefájlokat keres a telefonon. @@ -275,27 +276,27 @@ Alapértelmezett előadók Alapértelmezett albumok Alapértelmezett dalok - Ugrás időtartama - Böngésszen ID3 tag - Használja ID3 tag módszerek helyett a fájlrendszer alapú módszerek + Ugrás időintervalluma + Böngészés ID3 Tag használatával + ID3 Tag módszer használata a fájlredszer alapú mód helyett. Első év: Utolsó év: Műfaj: Hálózati hiba történt! Újrapróbálkozás %1$d - %2$d. - Kérem várjon… - Betöltés. + Kérem várjon!… + Betöltés... Az alkalmazás hálózati hozzáférést igényel. Kérjük, kapcsolja be a Wi-Fi-t vagy a mobilhálózatot! Hálózati hiba történt! Kérjük, ellenőrizze a kiszolgáló címét vagy próbálja később! Az erőforrás nem található! Kérjük, ellenőrizze a kiszolgáló címét! Értelmezhetetlen válasz! Kérjük, ellenőrizze a kiszolgáló címét! Csatlakozás a kiszolgálóhoz, kérem várjon! - Olvasás a kiszolgálóról. - Olvasás a kiszolgálóról. Kész! + Olvasás a kiszolgálóról... + Olvasás a kiszolgálóról... Kész! Nem kompatibilis verzió. Kérjük, frissítse az UltraSonic Android alkalmazást! Nem kompatibilis verzió. Kérjük, frissítse a Subsonic kiszolgálót! Hibás felhasználónév vagy jelszó! Nem engedélyezett! Ellenőrizze a felhasználó jogosultságait a Subsonic kiszolgálón! - %d előadót talált. + %d előadó található a médiakönyvtárban. Frissítés Mappa kiválasztása Összes mappa @@ -318,12 +319,12 @@ %d dal - 1 dal megjelölve. - %d dal megjelölve. + 1 dal kijelölve. + %d dal kijelölve. - 1 dal megjelölése visszavonva. - %d dal megjelölése visszavonva. + 1 dal visszavonva. + %d dal visszavonva. 1 dal hozzáadva a lejátszási sorhoz. diff --git a/src/com/thejoshwa/ultrasonic/androidapp/activity/DownloadActivity.java b/src/com/thejoshwa/ultrasonic/androidapp/activity/DownloadActivity.java index 6e3bb2e4..203db5af 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/activity/DownloadActivity.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/activity/DownloadActivity.java @@ -443,6 +443,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi onCurrentChanged(); onSliderProgressChanged(); scrollToCurrent(); + if (downloadService != null && downloadService.getKeepScreenOn()) { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } else { @@ -790,6 +791,7 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi } currentPlaying = getDownloadService().getCurrentPlaying(); + if (currentPlaying != null) { currentSong = currentPlaying.getSong(); final Drawable starDrawable = currentSong.getStarred() ? Util.getDrawableFromAttribute(SubsonicTabActivity.getInstance(), R.attr.star_full) : Util.getDrawableFromAttribute(SubsonicTabActivity.getInstance(), R.attr.star_hollow); @@ -797,13 +799,13 @@ public class DownloadActivity extends SubsonicTabActivity implements OnGestureLi songTitleTextView.setText(currentSong.getTitle()); albumTextView.setText(currentSong.getAlbum()); artistTextView.setText(currentSong.getArtist()); - getImageLoader().loadImage(albumArtImageView, currentSong, true, true); + getImageLoader().loadImage(albumArtImageView, currentSong, true, 0, false, true); } else { currentSong = null; songTitleTextView.setText(null); albumTextView.setText(null); artistTextView.setText(null); - getImageLoader().loadImage(albumArtImageView, null, true, false); + getImageLoader().loadImage(albumArtImageView, null, true, 0, false, false); } } diff --git a/src/com/thejoshwa/ultrasonic/androidapp/activity/SelectAlbumActivity.java b/src/com/thejoshwa/ultrasonic/androidapp/activity/SelectAlbumActivity.java index 1b14308b..78145c57 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/activity/SelectAlbumActivity.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/activity/SelectAlbumActivity.java @@ -18,13 +18,11 @@ */ package com.thejoshwa.ultrasonic.androidapp.activity; -import android.app.AlertDialog; -import android.content.DialogInterface; import android.content.Intent; +import android.graphics.Bitmap; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; @@ -37,7 +35,6 @@ import android.widget.ListView; import android.widget.TextView; import com.thejoshwa.ultrasonic.androidapp.R; -import com.thejoshwa.ultrasonic.androidapp.domain.Artist; import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory; import com.thejoshwa.ultrasonic.androidapp.service.DownloadFile; import com.thejoshwa.ultrasonic.androidapp.service.MusicService; @@ -325,7 +322,7 @@ public class SelectAlbumActivity extends SubsonicTabActivity { downloadRecursively(entry.getId(), false, false, true, false, false, false); break; case R.id.album_menu_play_next: - downloadRecursively(entry.getId(), false, false, true, false, false, true); + downloadRecursively(entry.getId(), false, false, false, false, false, true); break; case R.id.album_menu_play_last: downloadRecursively(entry.getId(), false, true, false, false, false, false); @@ -753,9 +750,9 @@ public class SelectAlbumActivity extends SubsonicTabActivity { } private View createHeader(List entries, String name, int songCount) { - View coverArtView = header.findViewById(R.id.select_album_art); + ImageView coverArtView = (ImageView) header.findViewById(R.id.select_album_art); int artworkSelection = random.nextInt(entries.size()); - getImageLoader().loadImage(coverArtView, entries.get(artworkSelection), true, true); + getImageLoader().loadImage(coverArtView, entries.get(artworkSelection), true, Util.getAlbumImageSize(SelectAlbumActivity.this), false, true); TextView titleView = (TextView) header.findViewById(R.id.select_album_title); titleView.setText(name != null ? name : getActionBar().getSubtitle()); diff --git a/src/com/thejoshwa/ultrasonic/androidapp/activity/SelectPlaylistActivity.java b/src/com/thejoshwa/ultrasonic/androidapp/activity/SelectPlaylistActivity.java index c5d6fc79..e3a81330 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/activity/SelectPlaylistActivity.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/activity/SelectPlaylistActivity.java @@ -30,7 +30,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.EditText; import android.widget.ListView; diff --git a/src/com/thejoshwa/ultrasonic/androidapp/activity/SubsonicTabActivity.java b/src/com/thejoshwa/ultrasonic/androidapp/activity/SubsonicTabActivity.java index 785587f7..02efac71 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/activity/SubsonicTabActivity.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/activity/SubsonicTabActivity.java @@ -24,20 +24,23 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; +import android.app.Notification; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.graphics.Bitmap; -import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.net.Uri; +import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Environment; -import android.util.DisplayMetrics; +import android.os.Handler; import android.util.Log; import android.view.KeyEvent; import android.view.MenuItem; @@ -45,9 +48,8 @@ import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; -import android.view.Window; import android.widget.ImageView; -import android.widget.ListView; +import android.widget.RemoteViews; import android.widget.TextView; import com.thejoshwa.ultrasonic.androidapp.R; import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory; @@ -62,7 +64,6 @@ import com.thejoshwa.ultrasonic.androidapp.service.MusicServiceFactory; import com.thejoshwa.ultrasonic.androidapp.service.OfflineException; import com.thejoshwa.ultrasonic.androidapp.service.ServerTooOldException; import com.thejoshwa.ultrasonic.androidapp.util.Constants; -import com.thejoshwa.ultrasonic.androidapp.util.FileUtil; import com.thejoshwa.ultrasonic.androidapp.util.ImageLoader; import com.thejoshwa.ultrasonic.androidapp.util.LoadingTask; import com.thejoshwa.ultrasonic.androidapp.util.ModalBackgroundTask; @@ -95,6 +96,8 @@ public class SubsonicTabActivity extends Activity implements OnClickListener{ View playlistsMenuItem = null; View menuMain = null; public static boolean nowPlayingHidden = false; + private static Entry currentSong; + public Bitmap nowPlayingImage; boolean licenseValid; @Override @@ -102,7 +105,7 @@ public class SubsonicTabActivity extends Activity implements OnClickListener{ setUncaughtExceptionHandler(); applyTheme(); super.onCreate(bundle); - + startService(new Intent(this, DownloadServiceImpl.class)); setVolumeControlStream(AudioManager.STREAM_MUSIC); @@ -178,6 +181,7 @@ public class SubsonicTabActivity extends Activity implements OnClickListener{ Util.unregisterMediaButtonEventReceiver(this); super.onDestroy(); destroyed = true; + nowPlayingView = null; getImageLoader().clear(); } @@ -213,54 +217,50 @@ public class SubsonicTabActivity extends Activity implements OnClickListener{ return destroyed; } - public void showNowPlaying() - { - nowPlayingView = findViewById(R.id.now_playing); - - if (!Util.getShowNowPlayingPreference(this)) { - if (nowPlayingView != null) { - nowPlayingView.setVisibility(View.GONE); - } - return; - } - - if (nowPlayingView != null) { - final DownloadService downloadService = DownloadServiceImpl.getInstance(); - - if (downloadService != null) { - PlayerState playerState = downloadService.getPlayerState(); - - if (playerState.equals(PlayerState.PAUSED) || playerState.equals(PlayerState.STARTED)) { - DownloadFile file = downloadService.getCurrentPlaying(); - - if (file != null) { - final Entry song = file.getSong(); - showNowPlaying(this, (DownloadServiceImpl)downloadService, song, playerState); - } - } else { - hideNowPlaying(); - } - - ImageView nowPlayingControlPlay = (ImageView) nowPlayingView.findViewById(R.id.now_playing_control_play); - - SwipeDetector swipeDetector = SwipeDetector.Create(SubsonicTabActivity.this, downloadService); - nowPlayingView.setOnTouchListener(swipeDetector); - - nowPlayingView.setOnClickListener(new View.OnClickListener() { + public void showNowPlaying() { + this.runOnUiThread(new Runnable() { + @Override + public void run() { + new SilentBackgroundTask(SubsonicTabActivity.this) { @Override - public void onClick(View v) { + protected Void doInBackground() throws Throwable { + if (!Util.getShowNowPlayingPreference(SubsonicTabActivity.this)) { + hideNowPlaying(); + return null; + } + + nowPlayingView = findViewById(R.id.now_playing); + + if (nowPlayingView != null) { + final DownloadService downloadService = DownloadServiceImpl .getInstance(); + + if (downloadService != null) { + PlayerState playerState = downloadService.getPlayerState(); + + if (playerState.equals(PlayerState.PAUSED) || playerState.equals(PlayerState.STARTED)) { + DownloadFile file = downloadService.getCurrentPlaying(); + + if (file != null) { + final Entry song = file.getSong(); + showNowPlaying(SubsonicTabActivity.this, (DownloadServiceImpl) downloadService, song, playerState); + } + } else { + hideNowPlaying(); + } + } + } + + return null; } - }); - - nowPlayingControlPlay.setOnClickListener(new View.OnClickListener() { + @Override - public void onClick(View view) { - downloadService.togglePlayPause(); + protected void done(Void result) { + return; } - }); + }.execute(); } - } - } + }); + } private void applyTheme() { String theme = Util.getTheme(this); @@ -272,104 +272,302 @@ public class SubsonicTabActivity extends Activity implements OnClickListener{ } } - private void showNowPlaying(final Context context, final DownloadServiceImpl downloadService, final MusicDirectory.Entry song, final PlayerState playerState) { - this.runOnUiThread( new Runnable() { - @Override - public void run() { - nowPlayingView = findViewById(R.id.now_playing); - - if (!Util.getShowNowPlayingPreference(SubsonicTabActivity.this)) { - if (nowPlayingView != null) { - nowPlayingView.setVisibility(View.GONE); - } - return; - } - - if (nowPlayingView != null) { - nowPlayingView.setVisibility(View.VISIBLE); - nowPlayingHidden = false; - - String title = song.getTitle(); - String artist = song.getArtist(); - - try { - ImageView nowPlayingImage = (ImageView) nowPlayingView.findViewById(R.id.now_playing_image); - TextView nowPlayingTrack = (TextView) nowPlayingView.findViewById(R.id.now_playing_trackname); - TextView nowPlayingArtist = (TextView) nowPlayingView.findViewById(R.id.now_playing_artist); + public void showNotification(final Handler handler, final MusicDirectory.Entry song, final DownloadServiceImpl downloadService, final Notification notification, final PlayerState playerState) { + + if (Util.isNotificationEnabled(this)) { + new AsyncTask() { + @Override + protected void onPostExecute(String[] result) { + super.onPostExecute(result); + } - DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - int imageSizeLarge = (int) Math.round(Math.min(metrics.widthPixels, metrics.heightPixels)); + @SuppressLint("NewApi") + @Override + protected String[] doInBackground(Void... params) { + RemoteViews notificationView = notification.contentView; + RemoteViews bigNotificationView = null; + + if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN){ + bigNotificationView = notification.bigContentView; + } + + if (playerState == PlayerState.PAUSED) { + setImageViewResourceOnUiThread(notificationView, R.id.control_play, R.drawable.media_start_normal_dark); + + if (bigNotificationView != null) { + setImageViewResourceOnUiThread(bigNotificationView, R.id.control_play, R.drawable.media_start_normal_dark); + } + } else if (playerState == PlayerState.STARTED) { + setImageViewResourceOnUiThread(notificationView, R.id.control_play, R.drawable.media_pause_normal_dark); + + if (bigNotificationView != null) { + setImageViewResourceOnUiThread(bigNotificationView, R.id.control_play, R.drawable.media_pause_normal_dark); + } + } + + if (currentSong != song) { + currentSong = song; + + String title = song.getTitle(); + String text = song.getArtist(); + String album = song.getAlbum(); + + try { + if (nowPlayingImage == null) { + setImageViewResourceOnUiThread(notificationView, R.id.notification_image, R.drawable.unknown_album); + + if (bigNotificationView != null) { + setImageViewResourceOnUiThread(bigNotificationView, R.id.notification_image, R.drawable.unknown_album); + } + } else { + setImageViewBitmapOnUiThread(notificationView, R.id.notification_image, nowPlayingImage); + + if (bigNotificationView != null) { + setImageViewBitmapOnUiThread(bigNotificationView, R.id.notification_image, nowPlayingImage); + } + } + } catch (Exception x) { + Log.w(TAG, "Failed to get notification cover art", x); + setImageViewResourceOnUiThread(notificationView, R.id.notification_image, R.drawable.unknown_album); + + if (bigNotificationView != null) { + setImageViewResourceOnUiThread(bigNotificationView, R.id.notification_image, R.drawable.unknown_album); + } + } + + setTextViewTextOnUiThread(notificationView, R.id.trackname, title); + setTextViewTextOnUiThread(notificationView, R.id.artist, text); + setTextViewTextOnUiThread(notificationView, R.id.album, album); - int size = 64; - - if (imageSizeLarge <= 480) { - size = 64; - } else if (imageSizeLarge <= 768) { - size = 128; - } else if (imageSizeLarge <= 1024) { - size = 256; - } else if (imageSizeLarge <= 1080) { - size = imageSizeLarge; - } - - Bitmap bitmap = FileUtil.getAlbumArtBitmap(context, song, size); - - if (bitmap == null) { - // set default album art - nowPlayingImage.setImageResource(R.drawable.unknown_album); - } else { - nowPlayingImage.setImageBitmap(bitmap); + if (bigNotificationView != null) { + setTextViewTextOnUiThread(bigNotificationView, R.id.trackname, title); + setTextViewTextOnUiThread(bigNotificationView, R.id.artist, text); + setTextViewTextOnUiThread(bigNotificationView, R.id.album, album); } - - nowPlayingImage.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(SubsonicTabActivity.this, SelectAlbumActivity.class); - - if (Util.getShouldUseId3Tags(SubsonicTabActivity.this)) { - intent.putExtra(Constants.INTENT_EXTRA_NAME_IS_ALBUM, true); - intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, song.getAlbumId()); - } else { - intent.putExtra(Constants.INTENT_EXTRA_NAME_IS_ALBUM, false); - intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, song.getParent()); - } - - intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, song.getAlbum()); - Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent); - } - }); - - nowPlayingTrack.setText(title); - nowPlayingArtist.setText(artist); + } - } catch (Exception x) { - Log.w(TAG, "Failed to get notification cover art", x); - } + // Send the notification and put the service in the foreground. + handler.post(new Runnable() { + @Override + public void run() { + downloadService.startForeground(Constants.NOTIFICATION_ID_PLAYING, notification); + } + }); + + return null; + } + }.execute(); + } + } - ImageView playButton = (ImageView) nowPlayingView.findViewById(R.id.now_playing_control_play); + public void hidePlayingNotification(final Handler handler, final DownloadServiceImpl downloadService) { - if (playerState == PlayerState.PAUSED) { - playButton.setImageDrawable(Util.getDrawableFromAttribute(SubsonicTabActivity.this, R.attr.media_play)); - } else if (playerState == PlayerState.STARTED) { - playButton.setImageDrawable(Util.getDrawableFromAttribute(SubsonicTabActivity.this, R.attr.media_pause)); - } - } - } - }); + currentSong = null; + + // Remove notification and remove the service from the foreground + handler.post(new Runnable(){ + @Override + public void run() { + downloadService.stopForeground(true); + } + }); + } + + private void showNowPlaying(final Context context, final DownloadServiceImpl downloadService, final MusicDirectory.Entry song, final PlayerState playerState) { + nowPlayingView = findViewById(R.id.now_playing); + + if (!Util.getShowNowPlayingPreference(SubsonicTabActivity.this)) { + hideNowPlaying(); + return; + } + + if (nowPlayingView != null) { + try { + setVisibilityOnUiThread(nowPlayingView, View.VISIBLE); + nowPlayingHidden = false; + + ImageView playButton = (ImageView) nowPlayingView.findViewById(R.id.now_playing_control_play); + + if (playerState == PlayerState.PAUSED) { + setImageDrawableOnUiThread(playButton, Util.getDrawableFromAttribute(SubsonicTabActivity.this, R.attr.media_play)); + } else if (playerState == PlayerState.STARTED) { + setImageDrawableOnUiThread(playButton, Util.getDrawableFromAttribute(SubsonicTabActivity.this, R.attr.media_pause)); + } + + String title = song.getTitle(); + String artist = song.getArtist(); + + final ImageView nowPlayingAlbumArtImage = (ImageView) nowPlayingView.findViewById(R.id.now_playing_image); + TextView nowPlayingTrack = (TextView) nowPlayingView.findViewById(R.id.now_playing_trackname); + TextView nowPlayingArtist = (TextView) nowPlayingView.findViewById(R.id.now_playing_artist); + + this.runOnUiThread( new Runnable() { + @Override + public void run() { + getImageLoader().loadImage(nowPlayingAlbumArtImage, song, true, Util.getNotificationImageSize(SubsonicTabActivity.this), false, true); + } + }); + + final Intent intent = new Intent(SubsonicTabActivity.this, SelectAlbumActivity.class); + + if (Util.getShouldUseId3Tags(SubsonicTabActivity.this)) { + intent.putExtra(Constants.INTENT_EXTRA_NAME_IS_ALBUM, true); + intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, song.getAlbumId()); + } else { + intent.putExtra(Constants.INTENT_EXTRA_NAME_IS_ALBUM, false); + intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, song.getParent()); + } + + intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, song.getAlbum()); + + setOnClickListenerOnUiThread(nowPlayingAlbumArtImage, new View.OnClickListener() { + @Override + public void onClick(View view) { + Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent); + } + }); + + setTextOnUiThread(nowPlayingTrack, title); + setTextOnUiThread(nowPlayingArtist, artist); + + ImageView nowPlayingControlPlay = (ImageView) nowPlayingView.findViewById(R.id.now_playing_control_play); + + SwipeDetector swipeDetector = SwipeDetector.Create(SubsonicTabActivity.this, downloadService); + setOnTouchListenerOnUiThread(nowPlayingView, swipeDetector); + + setOnClickListenerOnUiThread(nowPlayingView, new View.OnClickListener() { + @Override + public void onClick(View v) { + } + }); + + setOnClickListenerOnUiThread(nowPlayingControlPlay, new View.OnClickListener() { + @Override + public void onClick(View view) { + downloadService.togglePlayPause(); + } + }); + + } catch (Exception x) { + Log.w(TAG, "Failed to get notification cover art", x); + } + } } public void hideNowPlaying() { + nowPlayingView = findViewById(R.id.now_playing); + setVisibilityOnUiThread(nowPlayingView, View.GONE); + } + + public void setTextViewTextOnUiThread(final RemoteViews view, final int id, final String text) { this.runOnUiThread( new Runnable() { @Override public void run() { - nowPlayingView = findViewById(R.id.now_playing); - - if (nowPlayingView != null) { - nowPlayingView.setVisibility(View.GONE); + if (view != null) { + view.setTextViewText(id, text); } } }); - } + } + + public void setImageViewBitmapOnUiThread(final RemoteViews view, final int id, final Bitmap bitmap) { + this.runOnUiThread( new Runnable() { + @Override + public void run() { + if (view != null) { + view.setImageViewBitmap(id, bitmap); + } + } + }); + } + + public void setImageViewResourceOnUiThread(final RemoteViews view, final int id, final int resouce) { + this.runOnUiThread( new Runnable() { + @Override + public void run() { + if (view != null) { + view.setImageViewResource(id, resouce); + } + } + }); + } + + public void setOnTouchListenerOnUiThread(final View view, final View.OnTouchListener listener) { + this.runOnUiThread( new Runnable() { + @Override + public void run() { + if (view != null && view.getVisibility() != View.GONE) { + view.setOnTouchListener(listener); + } + } + }); + } + + public void setOnClickListenerOnUiThread(final View view, final View.OnClickListener listener) { + this.runOnUiThread( new Runnable() { + @Override + public void run() { + if (view != null && view.getVisibility() != View.GONE) { + view.setOnClickListener(listener); + } + } + }); + } + + public void setTextOnUiThread(final TextView view, final String text) { + this.runOnUiThread( new Runnable() { + @Override + public void run() { + if (view != null && view.getVisibility() != View.GONE) { + view.setText(text); + } + } + }); + } + + public void setImageResourceOnUiThread(final ImageView view, final int resource) { + this.runOnUiThread( new Runnable() { + @Override + public void run() { + if (view != null && view.getVisibility() != View.GONE) { + view.setImageResource(resource); + } + } + }); + } + + public void setImageDrawableOnUiThread(final ImageView view, final Drawable drawable) { + this.runOnUiThread( new Runnable() { + @Override + public void run() { + if (view != null && view.getVisibility() != View.GONE) { + view.setImageDrawable(drawable); + } + } + }); + } + + public void setImageBitmapOnUiThread(final ImageView view, final Bitmap bitmap) { + this.runOnUiThread( new Runnable() { + @Override + public void run() { + if (view != null && view.getVisibility() != View.GONE) { + view.setImageBitmap(bitmap); + } + } + }); + } + + public void setVisibilityOnUiThread(final View view, final int visibility) { + this.runOnUiThread( new Runnable() { + @Override + public void run() { + if (view != null && view.getVisibility() != visibility) { + view.setVisibility(visibility); + } + } + }); + } public static SubsonicTabActivity getInstance() { return instance; @@ -842,7 +1040,7 @@ public class SubsonicTabActivity extends Activity implements OnClickListener{ } } else if (Math.abs(deltaY) > MIN_DISTANCE) { if (deltaY < 0) { - activity.nowPlayingHidden = true; + SubsonicTabActivity.nowPlayingHidden = true; activity.hideNowPlaying(); return false; } diff --git a/src/com/thejoshwa/ultrasonic/androidapp/provider/UltraSonicAppWidgetProvider4x1.java b/src/com/thejoshwa/ultrasonic/androidapp/provider/UltraSonicAppWidgetProvider4x1.java index 917848d6..7bef460b 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/provider/UltraSonicAppWidgetProvider4x1.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/provider/UltraSonicAppWidgetProvider4x1.java @@ -156,7 +156,7 @@ public class UltraSonicAppWidgetProvider4x1 extends AppWidgetProvider { // Set the cover art try { int size = context.getResources().getDrawable(R.drawable.appwidget_art_default).getIntrinsicHeight(); - Bitmap bitmap = currentPlaying == null ? null : FileUtil.getAlbumArtBitmap(context, currentPlaying, size); + Bitmap bitmap = currentPlaying == null ? null : FileUtil.getAlbumArtBitmap(context, currentPlaying, size, true); if (bitmap == null) { // Set default cover art diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/CachedMusicService.java b/src/com/thejoshwa/ultrasonic/androidapp/service/CachedMusicService.java index 02a453a5..a748953f 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/service/CachedMusicService.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/service/CachedMusicService.java @@ -255,8 +255,8 @@ public class CachedMusicService implements MusicService { } @Override - public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, ProgressListener progressListener) throws Exception { - return musicService.getCoverArt(context, entry, size, saveToFile, progressListener); + public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception { + return musicService.getCoverArt(context, entry, size, saveToFile, highQuality, progressListener); } @Override diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadFile.java b/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadFile.java index 9b57af2c..b62e8408 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadFile.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadFile.java @@ -335,9 +335,8 @@ public class DownloadFile { private void downloadAndSaveCoverArt(MusicService musicService) throws Exception { try { if (song.getCoverArt() != null) { - DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - int size = Math.min(metrics.widthPixels, metrics.heightPixels); - musicService.getCoverArt(context, song, size, true, null); + int size = Util.getMinDisplayMetric(context); + musicService.getCoverArt(context, song, size, true, true, null); } } catch (Exception x) { Log.e(TAG, "Failed to get cover art.", x); diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceImpl.java b/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceImpl.java index 849182bf..49282ea3 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceImpl.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/service/DownloadServiceImpl.java @@ -27,7 +27,6 @@ import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.media.AudioManager; -import android.media.AudioManager.OnAudioFocusChangeListener; import android.media.MediaMetadataRetriever; import android.media.MediaPlayer; import android.media.RemoteControlClient; @@ -37,7 +36,6 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.PowerManager; -import android.util.DisplayMetrics; import android.util.Log; import android.widget.RemoteViews; import android.widget.SeekBar; @@ -84,6 +82,8 @@ public class DownloadServiceImpl extends Service implements DownloadService { public static final String PLAYSTATUS_REQUEST = "com.android.music.playstatusrequest"; public static final String PLAYSTATUS_RESPONSE = "com.android.music.playstatusresponse"; + + public static final int lockScreenAlbumArtSize = 500; private final IBinder binder = new SimpleServiceBinder(this); private Looper mediaPlayerLooper; @@ -151,21 +151,8 @@ public class DownloadServiceImpl extends Service implements DownloadService { } } - private OnAudioFocusChangeListener _afChangeListener = new OnAudioFocusChangeListener() { - public void onAudioFocusChange(int focusChange) { - if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) { - pause(); - } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { - if (playerState == PlayerState.STARTED) { - start(); - } - } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { - stop(); - } - } - }; - - @Override + @SuppressLint("NewApi") + @Override public void onCreate() { super.onCreate(); @@ -213,10 +200,16 @@ public class DownloadServiceImpl extends Service implements DownloadService { notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; notification.contentView = new RemoteViews(this.getPackageName(), R.layout.notification); + Util.linkButtons(this, notification.contentView, false); + + if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN){ + notification.bigContentView = new RemoteViews(this.getPackageName(), R.layout.notification_large); + Util.linkButtons(this, notification.bigContentView, false); + } + Intent notificationIntent = new Intent(this, DownloadActivity.class); notification.contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); - Util.linkButtons(this, notification.contentView, false); - + if (equalizerAvailable) { equalizerController = new EqualizerController(this, mediaPlayer); if (!equalizerController.isAvailable()) { @@ -366,7 +359,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { autoPlayStart = false; } } - + @Override public synchronized void setShufflePlayEnabled(boolean enabled) { shufflePlay = enabled; @@ -560,24 +553,20 @@ public class DownloadServiceImpl extends Service implements DownloadService { // Update widget UltraSonicAppWidgetProvider4x1.getInstance().notifyChange(this, this, playerState == PlayerState.STARTED); - + SubsonicTabActivity tabInstance = SubsonicTabActivity.getInstance(); + if (currentPlaying != null) { - if (showNotification) { - Util.showPlayingNotification(this, this, handler, currentPlaying.getSong(), this.notification, this.playerState); - } - - SubsonicTabActivity tabInstance = SubsonicTabActivity.getInstance(); - if (tabInstance != null) { - //tabInstance.showNowPlaying(this, this, currentPlaying.getSong(), this.playerState); + int size = Util.getNotificationImageSize(this); + + tabInstance.nowPlayingImage = FileUtil.getAlbumArtBitmap(this, currentPlaying.getSong(), size, true); + tabInstance.showNotification(handler, currentPlaying.getSong(), this, this.notification, this.playerState); tabInstance.showNowPlaying(); } } else { - Util.hidePlayingNotification(this, this, handler); - - SubsonicTabActivity tabInstance = SubsonicTabActivity.getInstance(); - if (tabInstance != null) { + tabInstance.nowPlayingImage = null; + tabInstance.hidePlayingNotification(handler, this); tabInstance.hideNowPlaying(); } } @@ -891,7 +880,7 @@ public class DownloadServiceImpl extends Service implements DownloadService { } if (this.playerState == PlayerState.STARTED) { - audioManager.requestAudioFocus(_afChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); + Util.requestAudioFocus(this); } boolean showWhenPaused = (this.playerState == PlayerState.PAUSED && Util.isNotificationAlwaysEnabled(this)); @@ -906,22 +895,23 @@ public class DownloadServiceImpl extends Service implements DownloadService { // Update widget UltraSonicAppWidgetProvider4x1.getInstance().notifyChange(this, this, this.playerState == PlayerState.STARTED); + SubsonicTabActivity tabInstance = SubsonicTabActivity.getInstance(); if (show) { + int size = Util.getNotificationImageSize(this); + Bitmap bitmap = FileUtil.getAlbumArtBitmap(this, currentPlaying.getSong(), size, true); + if (currentPlaying != null) { - Util.showPlayingNotification(this, this, handler, currentPlaying.getSong(), this.notification, this.playerState); - - SubsonicTabActivity tabInstance = SubsonicTabActivity.getInstance(); if (tabInstance != null) { + tabInstance.nowPlayingImage = bitmap; + tabInstance.showNotification(handler, currentPlaying.getSong(), this, this.notification, this.playerState); tabInstance.showNowPlaying(); - //tabInstance.showNowPlaying(this, this, currentPlaying.getSong(), this.playerState); } } } else if (hide) { - Util.hidePlayingNotification(this, this, handler); - - SubsonicTabActivity tabInstance = SubsonicTabActivity.getInstance(); if (tabInstance != null) { + tabInstance.nowPlayingImage = null; + tabInstance.hidePlayingNotification(handler, this); tabInstance.hideNowPlaying(); } } @@ -1031,18 +1021,18 @@ public class DownloadServiceImpl extends Service implements DownloadService { Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON); intent.setComponent(new ComponentName(this.getPackageName(), MediaButtonIntentReceiver.class.getName())); remoteControlClient = new RemoteControlClient(PendingIntent.getBroadcast(this, 0, intent, 0)); + + remoteControlClient.setTransportControlFlags( + RemoteControlClient.FLAG_KEY_MEDIA_PLAY | + RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | + RemoteControlClient.FLAG_KEY_MEDIA_NEXT | + RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | + RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE | + RemoteControlClient.FLAG_KEY_MEDIA_STOP); } audioManager.registerRemoteControlClient(remoteControlClient); - remoteControlClient.setTransportControlFlags( - RemoteControlClient.FLAG_KEY_MEDIA_PLAY | - RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | - RemoteControlClient.FLAG_KEY_MEDIA_NEXT | - RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | - RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE | - RemoteControlClient.FLAG_KEY_MEDIA_STOP); - switch (playerState) { case STARTED: @@ -1052,15 +1042,23 @@ public class DownloadServiceImpl extends Service implements DownloadService { remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_PAUSED); break; case IDLE: + case COMPLETED: case STOPPED: remoteControlClient.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED); break; + case DOWNLOADING: + case PREPARED: + case PREPARING: + default: + break; } try { if (currentPlaying != null) { if (currentSong != currentPlaying.getSong()) { currentSong = currentPlaying.getSong(); + } else { + return; } String artist = currentSong.getArtist(); @@ -1068,10 +1066,10 @@ public class DownloadServiceImpl extends Service implements DownloadService { String title = artist + " - " + currentSong.getTitle(); Integer duration = currentSong.getDuration(); - DisplayMetrics metrics = this.getResources().getDisplayMetrics(); - int size = Math.min(metrics.widthPixels, metrics.heightPixels); // Always get the album art from disk - Bitmap bitmap = FileUtil.getAlbumArtBitmap(this, currentSong, size); + if (Util.bluetoothBitmap == null) { + Util.bluetoothBitmap = FileUtil.getAlbumArtBitmap(this, currentSong, Util.bluetoothImagesize, true); + } // Update the remote controls remoteControlClient @@ -1088,10 +1086,10 @@ public class DownloadServiceImpl extends Service implements DownloadService { .apply(); } - if (bitmap != null) { + if (Util.bluetoothBitmap != null) { remoteControlClient .editMetadata(false) - .putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, bitmap) + .putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, Util.bluetoothBitmap) .apply(); } } diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/MusicService.java b/src/com/thejoshwa/ultrasonic/androidapp/service/MusicService.java index 6576a48e..79c1c575 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/service/MusicService.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/service/MusicService.java @@ -30,6 +30,7 @@ import com.thejoshwa.ultrasonic.androidapp.domain.Indexes; import com.thejoshwa.ultrasonic.androidapp.domain.JukeboxStatus; import com.thejoshwa.ultrasonic.androidapp.domain.Lyrics; import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory; +import com.thejoshwa.ultrasonic.androidapp.domain.MusicDirectory.Entry; import com.thejoshwa.ultrasonic.androidapp.domain.MusicFolder; import com.thejoshwa.ultrasonic.androidapp.domain.Playlist; import com.thejoshwa.ultrasonic.androidapp.domain.SearchCritera; @@ -97,7 +98,7 @@ public interface MusicService { SearchResult getStarred2(Context context, ProgressListener progressListener) throws Exception; - Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, ProgressListener progressListener) throws Exception; + Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception; HttpResponse getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, CancellableTask task) throws Exception; diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java b/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java index b9592c99..ed2b5519 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/service/OfflineMusicService.java @@ -257,9 +257,9 @@ public class OfflineMusicService extends RESTMusicService { } @Override - public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, ProgressListener progressListener) throws Exception { + public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception { try { - return FileUtil.getAlbumArtBitmap(context, entry, size); + return FileUtil.getAlbumArtBitmap(context, entry, size, highQuality); } catch(Exception e) { return null; } diff --git a/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java b/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java index 3f11c0d8..ae22175e 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/service/RESTMusicService.java @@ -727,12 +727,12 @@ public class RESTMusicService implements MusicService { } @Override - public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, ProgressListener progressListener) throws Exception { + public Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality, ProgressListener progressListener) throws Exception { // Synchronize on the entry so that we don't download concurrently for // the same song. synchronized (entry) { // Use cached file, if existing. - Bitmap bitmap = FileUtil.getAlbumArtBitmap(context, entry, size); + Bitmap bitmap = FileUtil.getAlbumArtBitmap(context, entry, size, highQuality); boolean serverScaling = Util.isServerScalingEnabled(context); if (bitmap == null) { diff --git a/src/com/thejoshwa/ultrasonic/androidapp/util/Constants.java b/src/com/thejoshwa/ultrasonic/androidapp/util/Constants.java index 1ff8d4ec..e4faeda5 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/util/Constants.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/util/Constants.java @@ -115,6 +115,7 @@ public final class Constants { public static final String PREFERENCES_KEY_DOWNLOAD_TRANSITION = "transitionToDownloadOnPlay"; public static final String PREFERENCES_KEY_INCREMENT_TIME = "incrementTime"; public static final String PREFERENCES_KEY_ID3_TAGS = "useId3Tags"; + public static final String PREFERENCES_KEY_TEMP_LOSS = "tempLoss"; // Name of the preferences file. public static final String PREFERENCES_FILE_NAME = "com.thejoshwa.ultrasonic.androidapp_preferences"; diff --git a/src/com/thejoshwa/ultrasonic/androidapp/util/FileUtil.java b/src/com/thejoshwa/ultrasonic/androidapp/util/FileUtil.java index 6db83932..551e3062 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/util/FileUtil.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/util/FileUtil.java @@ -121,20 +121,34 @@ public class FileUtil { return new File(albumArtDir, Util.md5Hex(albumDir.getPath()) + ".jpeg"); } - public static Bitmap getAlbumArtBitmap(Context context, MusicDirectory.Entry entry, int size) { + public static Bitmap getAlbumArtBitmap(Context context, MusicDirectory.Entry entry, int size, boolean highQuality) { File albumArtFile = getAlbumArtFile(context, entry); if (albumArtFile.exists()) { - Bitmap bitmap = BitmapFactory.decodeFile(albumArtFile.getPath()); + final BitmapFactory.Options opt = new BitmapFactory.Options(); + + + if (size > 0) { + opt.inJustDecodeBounds = true; + BitmapFactory.decodeFile(albumArtFile.getPath(), opt); + + if (highQuality) { + opt.inDither = true; + opt.inPreferQualityOverSpeed = true; + } + + opt.inPurgeable = true; + opt.inSampleSize = Util.calculateInSampleSize(opt, size, Util.getScaledHeight(opt.outHeight, opt.outWidth, size)); + opt.inJustDecodeBounds = false; + } + + Bitmap bitmap = BitmapFactory.decodeFile(albumArtFile.getPath(), opt); Log.i("getAlbumArtBitmap", String.valueOf(size)); + if (bitmap == null) { return null; } else { - if (size > 0) { - return Util.scaleBitmap(bitmap, size); - } - return bitmap; } } @@ -142,6 +156,18 @@ public class FileUtil { return null; } + public static Bitmap scaleDownBitmap(Bitmap photo, int newHeight, Context context) { + + final float densityMultiplier = context.getResources().getDisplayMetrics().density; + + int h= (int) (newHeight*densityMultiplier); + int w= (int) (h * photo.getWidth()/((double) photo.getHeight())); + + photo=Bitmap.createScaledBitmap(photo, w, h, true); + + return photo; + } + public static File getArtistDirectory(Context context, Artist artist) { File dir = new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(artist.getName())); return dir; diff --git a/src/com/thejoshwa/ultrasonic/androidapp/util/ImageLoader.java b/src/com/thejoshwa/ultrasonic/androidapp/util/ImageLoader.java index 1e5b8bfe..b59c00e7 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/util/ImageLoader.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/util/ImageLoader.java @@ -18,14 +18,12 @@ */ package com.thejoshwa.ultrasonic.androidapp.util; -import android.app.ActionBar; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; import android.os.Handler; -import android.os.Message; import android.util.DisplayMetrics; import android.util.Log; import android.view.View; @@ -51,15 +49,16 @@ public class ImageLoader implements Runnable { private static final String TAG = ImageLoader.class.getSimpleName(); private static final int CONCURRENCY = 5; - private final LRUCache cache = new LRUCache(100); + private final LRUCache cache = new LRUCache(100); private final BlockingQueue queue; private final int imageSizeDefault; private final int imageSizeLarge; - private Drawable largeUnknownImage; - private Drawable drawable; - + private Bitmap largeUnknownImage; + private Context context; + public ImageLoader(Context context) { - queue = new LinkedBlockingQueue(500); + this.context = context; + queue = new LinkedBlockingQueue(500); // Determine the density-dependent image sizes. imageSizeDefault = context.getResources().getDrawable(R.drawable.unknown_album).getIntrinsicHeight(); @@ -76,13 +75,10 @@ public class ImageLoader implements Runnable { private void createLargeUnknownImage(Context context) { BitmapDrawable drawable = (BitmapDrawable) context.getResources().getDrawable(R.drawable.unknown_album_large); Log.i(TAG, "createLargeUnknownImage"); - Bitmap bitmap = Util.scaleBitmap(drawable.getBitmap(), imageSizeLarge); - - //bitmap = createReflection(bitmap); - largeUnknownImage = Util.createDrawableFromBitmap(context, bitmap); + largeUnknownImage = Util.scaleBitmap(drawable.getBitmap(), imageSizeLarge); } - public void loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) { + public void loadImage(View view, MusicDirectory.Entry entry, boolean large, int size, boolean crossfade, boolean highQuality) { if (entry == null) { setUnknownImage(view, large); return; @@ -95,11 +91,14 @@ public class ImageLoader implements Runnable { return; } - int size = large ? imageSizeLarge : imageSizeDefault; - Drawable drawable = cache.get(getKey(coverArt, size)); + if (size <= 0) { + size = large ? imageSizeLarge : imageSizeDefault; + } - if (drawable != null) { - setImage(view, drawable, large); + Bitmap bitmap = cache.get(getKey(coverArt, size)); + + if (bitmap != null) { + setImageBitmap(view, bitmap, false); return; } @@ -107,81 +106,40 @@ public class ImageLoader implements Runnable { setUnknownImage(view, large); } - queue.offer(new Task(view, entry, size, large, large, crossfade)); - } - - public void setActionBarArtwork(final View view, final MusicDirectory.Entry entry, final ActionBar ab) { - if (entry == null || entry.getCoverArt() == null) { - ab.setLogo(largeUnknownImage); - } - - final int size = imageSizeLarge; - drawable = cache.get(getKey(entry.getCoverArt(), size)); - - if (drawable != null) { - ab.setLogo(drawable); - } - - final Handler handler = new Handler(){ - @Override - public void handleMessage(Message msg) { - drawable = (Drawable) msg.obj; - ab.setLogo(drawable); - } - }; - - new Thread(new Runnable() { - public void run() { - MusicService musicService = MusicServiceFactory.getMusicService(view.getContext()); - - try - { - Bitmap bitmap = musicService.getCoverArt(view.getContext(), entry, size, true, null); - drawable = Util.createDrawableFromBitmap(view.getContext(), bitmap); - Message msg = Message.obtain(); - msg.obj = drawable; - handler.sendMessage(msg); - cache.put(getKey(entry.getCoverArt(), size), drawable); - } catch (Throwable x) { - Log.e(TAG, "Failed to download album art.", x); - } - } - }).start(); + queue.offer(new Task(view, entry, size, large, large, crossfade, highQuality)); } private String getKey(String coverArtId, int size) { return coverArtId + size; } - private void setImage(View view, Drawable drawable, boolean crossfade) { - if (view instanceof TextView) { - // Cross-fading is not implemented for TextView since it's not in use. It would be easy to add it, though. - TextView textView = (TextView) view; - textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null); - } else if (view instanceof ImageView) { + private void setImageBitmap(View view, Bitmap bitmap, boolean crossfade) { + if (view instanceof ImageView) { ImageView imageView = (ImageView) view; if (crossfade) { Drawable existingDrawable = imageView.getDrawable(); + Drawable newDrawable = Util.createDrawableFromBitmap(this.context, bitmap); + if (existingDrawable == null) { - Bitmap emptyImage = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + Bitmap emptyImage = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); existingDrawable = new BitmapDrawable(emptyImage); } - Drawable[] layers = new Drawable[]{existingDrawable, drawable}; + Drawable[] layers = new Drawable[]{existingDrawable, newDrawable}; TransitionDrawable transitionDrawable = new TransitionDrawable(layers); imageView.setImageDrawable(transitionDrawable); transitionDrawable.startTransition(250); } else { - imageView.setImageDrawable(drawable); + imageView.setImageBitmap(bitmap); } } } private void setUnknownImage(View view, boolean large) { if (large) { - setImage(view, largeUnknownImage, false); + setImageBitmap(view, largeUnknownImage, false); } else { if (view instanceof TextView) { ((TextView) view).setCompoundDrawablesWithIntrinsicBounds(R.drawable.unknown_album, 0, 0, 0); @@ -212,36 +170,31 @@ public class ImageLoader implements Runnable { private final MusicDirectory.Entry entry; private final Handler handler; private final int size; - private final boolean reflection; private final boolean saveToFile; private final boolean crossfade; + private final boolean highQuality; - public Task(View view, MusicDirectory.Entry entry, int size, boolean reflection, boolean saveToFile, boolean crossfade) { + public Task(View view, MusicDirectory.Entry entry, int size, boolean reflection, boolean saveToFile, boolean crossfade, boolean highQuality) { this.view = view; this.entry = entry; this.size = size; - this.reflection = reflection; this.saveToFile = saveToFile; this.crossfade = crossfade; + this.highQuality = highQuality; handler = new Handler(); } public void execute() { try { MusicService musicService = MusicServiceFactory.getMusicService(view.getContext()); - Bitmap bitmap = musicService.getCoverArt(view.getContext(), entry, size, saveToFile, null); + final Bitmap bitmap = musicService.getCoverArt(view.getContext(), entry, size, saveToFile, highQuality, null); - if (reflection) { - //bitmap = createReflection(bitmap); - } - - final Drawable drawable = Util.createDrawableFromBitmap(view.getContext(), bitmap); - cache.put(getKey(entry.getCoverArt(), size), drawable); + cache.put(getKey(entry.getCoverArt(), size), bitmap); handler.post(new Runnable() { @Override public void run() { - setImage(view, drawable, crossfade); + setImageBitmap(view, bitmap, crossfade); } }); } catch (Throwable x) { diff --git a/src/com/thejoshwa/ultrasonic/androidapp/util/Util.java b/src/com/thejoshwa/ultrasonic/androidapp/util/Util.java index 62a827a4..aa2273e7 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/util/Util.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/util/Util.java @@ -20,10 +20,7 @@ package com.thejoshwa.ultrasonic.androidapp.util; import android.app.Activity; import android.app.AlertDialog; -import android.app.Notification; -import android.app.NotificationManager; import android.app.PendingIntent; -import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -31,15 +28,15 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.media.AudioManager; +import android.media.AudioManager.OnAudioFocusChangeListener; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiManager; -import android.os.Build; import android.os.Environment; -import android.os.Handler; import android.os.Parcelable; import android.preference.PreferenceManager; import android.util.DisplayMetrics; @@ -102,6 +99,12 @@ public class Util extends DownloadActivity { public static final String CM_AVRCP_PLAYSTATE_CHANGED = "com.android.music.playstatechanged"; public static final String CM_AVRCP_METADATA_CHANGED = "com.android.music.metachanged"; + + public final static int bluetoothImagesize = 500; + + private static boolean hasFocus = false; + private static boolean pauseFocus = false; + private static boolean lowerFocus = false; private static final Map SERVER_REST_VERSIONS = new ConcurrentHashMap(); @@ -109,7 +112,8 @@ public class Util extends DownloadActivity { private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; private static Toast toast; - private static MusicDirectory.Entry currentSong; + public static Bitmap bluetoothBitmap; + private static Entry currentSong; private Util() { } @@ -710,83 +714,7 @@ public class Util extends DownloadActivity { .show(); } - public static void showPlayingNotification(final Context context, final DownloadServiceImpl downloadService, Handler handler, MusicDirectory.Entry song, final Notification notification, PlayerState playerState) { - - if (Util.isNotificationEnabled(context)) { - if (currentSong != song) { - currentSong = song; - - // Use the same text for the ticker and the expanded - // notification - String title = song.getTitle(); - String text = song.getArtist(); - String album = song.getAlbum(); - - // Set the album art. - try { - DisplayMetrics metrics = context.getResources().getDisplayMetrics(); - int imageSizeLarge = (int) Math.round(Math.min(metrics.widthPixels, metrics.heightPixels)); - - int size = 64; - - if (imageSizeLarge <= 480) { - size = 64; - } else if (imageSizeLarge <= 768) { - size = 128; - } else if (imageSizeLarge <= 1024) { - size = 256; - } else if (imageSizeLarge <= 1080) { - size = imageSizeLarge; - } - - Bitmap bitmap = FileUtil.getAlbumArtBitmap(context, song, size); - - if (bitmap == null) { - // set default album art - notification.contentView.setImageViewResource(R.id.notification_image, R.drawable.unknown_album); - } else { - notification.contentView.setImageViewBitmap(R.id.notification_image, bitmap); - } - } catch (Exception x) { - Log.w(TAG, "Failed to get notification cover art", x); - notification.contentView.setImageViewResource(R.id.notification_image, R.drawable.unknown_album); - } - - // set the text for the notifications - notification.contentView.setTextViewText(R.id.trackname, title); - notification.contentView.setTextViewText(R.id.artist, text); - notification.contentView.setTextViewText(R.id.album, album); - } - - if (playerState == PlayerState.PAUSED) { - notification.contentView.setImageViewResource(R.id.control_play, R.drawable.media_start_normal_dark); - } else if (playerState == PlayerState.STARTED) { - notification.contentView.setImageViewResource(R.id.control_play, R.drawable.media_pause_normal_dark); - } - - // Send the notification and put the service in the foreground. - handler.post(new Runnable() { - @Override - public void run() { - startForeground(downloadService, Constants.NOTIFICATION_ID_PLAYING, notification); - } - }); - } - } - - public static void hidePlayingNotification(final Context context, final DownloadServiceImpl downloadService, Handler handler) { - - currentSong = null; - - // Remove notification and remove the service from the foreground - handler.post(new Runnable(){ - @Override - public void run() { - stopForeground(downloadService, true); - } - }); - } - + public static void sleepQuietly(long millis) { try { Thread.sleep(millis); @@ -841,72 +769,34 @@ public class Util extends DownloadActivity { return wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, tag); } - public static Bitmap scaleBitmap(Bitmap bitmap, int size) { + public static int getScaledHeight(double height, double width, int newWidth) { // Try to keep correct aspect ratio of the original image, do not force a square - double aspectRatio = (double)bitmap.getHeight() / (double)bitmap.getWidth(); + double aspectRatio = height / width; // Assume the size given refers to the width of the image, so calculate the new height using // the previously determined aspect ratio - int newHeight = (int) Math.round(size * aspectRatio); - - return Bitmap.createScaledBitmap(bitmap, size, newHeight, true); + return (int) Math.round(newWidth * aspectRatio); + } + + public static int getScaledHeight(Bitmap bitmap, int width) { + return getScaledHeight((double)bitmap.getHeight(), (double)bitmap.getWidth(), width); + } + + public static Bitmap scaleBitmap(Bitmap bitmap, int size) { + return Bitmap.createScaledBitmap(bitmap, size, getScaledHeight(bitmap, size), true); } public static void registerMediaButtonEventReceiver(Context context) { - if (getMediaButtonsPreference(context)) { - // AudioManager.registerMediaButtonEventReceiver() was introduced in Android 2.2. - // Use reflection to maintain compatibility with 1.5. - try { - AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - ComponentName componentName = new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName()); - Method method = AudioManager.class.getMethod("registerMediaButtonEventReceiver", ComponentName.class); - method.invoke(audioManager, componentName); - } catch (Throwable x) { - // Ignored. - } + AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + audioManager.registerMediaButtonEventReceiver(new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName())); + } } public static void unregisterMediaButtonEventReceiver(Context context) { - // AudioManager.unregisterMediaButtonEventReceiver() was introduced in Android 2.2. - // Use reflection to maintain compatibility with 1.5. - try { - AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - ComponentName componentName = new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName()); - Method method = AudioManager.class.getMethod("unregisterMediaButtonEventReceiver", ComponentName.class); - method.invoke(audioManager, componentName); - } catch (Throwable x) { - // Ignored. - } - } - - private static void startForeground(Service service, int notificationId, Notification notification) { - // Service.startForeground() was introduced in Android 2.0. - // Use reflection to maintain compatibility with 1.5. - try { - Method method = Service.class.getMethod("startForeground", int.class, Notification.class); - method.invoke(service, notificationId, notification); - Log.i(TAG, "Successfully invoked Service.startForeground()"); - } catch (Throwable x) { - NotificationManager notificationManager = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.notify(Constants.NOTIFICATION_ID_PLAYING, notification); - Log.i(TAG, "Service.startForeground() not available. Using work-around."); - } - } - - private static void stopForeground(Service service, boolean removeNotification) { - // Service.stopForeground() was introduced in Android 2.0. - // Use reflection to maintain compatibility with 1.5. - try { - Method method = Service.class.getMethod("stopForeground", boolean.class); - method.invoke(service, removeNotification); - Log.i(TAG, "Successfully invoked Service.stopForeground()"); - } catch (Throwable x) { - NotificationManager notificationManager = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.cancel(Constants.NOTIFICATION_ID_PLAYING); - Log.i(TAG, "Service.stopForeground() not available. Using work-around."); - } + AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + audioManager.unregisterMediaButtonEventReceiver(new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName())); } public static MusicDirectory getSongsFromSearchResult(SearchResult searchResult) { @@ -943,7 +833,7 @@ public class Util extends DownloadActivity { } public static void broadcastA2dpMetaDataChange(Context context, DownloadService downloadService) { - MusicDirectory.Entry song = null; + Entry song = null; Intent avrcpIntent = new Intent(CM_AVRCP_METADATA_CHANGED); if (downloadService != null) { @@ -967,9 +857,13 @@ public class Util extends DownloadActivity { avrcpIntent.putExtra("id", (long) 0); avrcpIntent.putExtra("duration", (long) 0); avrcpIntent.putExtra("position", (long) 0); + bluetoothBitmap = null; } else { - Bitmap bitmap = FileUtil.getAlbumArtBitmap(context, song, 0); - + if (song != currentSong) { + currentSong = song; + bluetoothBitmap = FileUtil.getAlbumArtBitmap(context, song, bluetoothImagesize, true); + } + String title = song.getTitle(); String artist = song.getArtist(); String album = song.getAlbum(); @@ -984,8 +878,8 @@ public class Util extends DownloadActivity { avrcpIntent.putExtra("artist_name", artist); avrcpIntent.putExtra("album", album); avrcpIntent.putExtra("album_name", album); - avrcpIntent.putExtra("cover", (Parcelable) bitmap); - avrcpIntent.putExtra("coverart", (Parcelable) bitmap); + avrcpIntent.putExtra("cover", (Parcelable) bluetoothBitmap); + avrcpIntent.putExtra("coverart", (Parcelable) bluetoothBitmap); if (playerPosition != null) { avrcpIntent.putExtra("position", (long) playerPosition); @@ -1012,13 +906,16 @@ public class Util extends DownloadActivity { if (downloadService.getCurrentPlaying() != null) { Intent avrcpIntent = new Intent(CM_AVRCP_PLAYSTATE_CHANGED); - MusicDirectory.Entry song = downloadService.getCurrentPlaying().getSong(); + Entry song = downloadService.getCurrentPlaying().getSong(); if (song == null) { return; } - Bitmap bitmap = FileUtil.getAlbumArtBitmap(context, song, 0); + if (song != currentSong) { + currentSong = song; + bluetoothBitmap = FileUtil.getAlbumArtBitmap(context, song, bluetoothImagesize, true); + } String title = song.getTitle(); String artist = song.getArtist(); @@ -1034,8 +931,8 @@ public class Util extends DownloadActivity { avrcpIntent.putExtra("artist_name", artist); avrcpIntent.putExtra("album", album); avrcpIntent.putExtra("album_name", album); - avrcpIntent.putExtra("cover", (Parcelable) bitmap); - avrcpIntent.putExtra("coverart", (Parcelable) bitmap); + avrcpIntent.putExtra("cover", (Parcelable) bluetoothBitmap); + avrcpIntent.putExtra("coverart", (Parcelable) bluetoothBitmap); if (playerPosition != null) { avrcpIntent.putExtra("position", (long) playerPosition); @@ -1100,6 +997,121 @@ public class Util extends DownloadActivity { context.sendBroadcast(intent); } + public static int getNotificationImageSize(Context context) { + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + int imageSizeLarge = (int) Math.round(Math.min(metrics.widthPixels, metrics.heightPixels)); + + int size = 64; + + if (imageSizeLarge <= 480) { + size = 64; + } else if (imageSizeLarge <= 768) { + size = 128; + } else { + size = 256; + } + + return size; + } + + public static int getAlbumImageSize(Context context) { + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + int imageSizeLarge = (int) Math.round(Math.min(metrics.widthPixels, metrics.heightPixels)); + + int size = 128; + + if (imageSizeLarge <= 480) { + size = 128; + } else if (imageSizeLarge <= 768) { + size = 256; + } else { + size = 512; + } + + return size; + } + + public static void requestAudioFocus(final Context context) { + if (!hasFocus) { + final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + hasFocus = true; + audioManager.requestAudioFocus(new OnAudioFocusChangeListener() { + public void onAudioFocusChange(int focusChange) { + DownloadServiceImpl downloadService = (DownloadServiceImpl)context; + if((focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) && !downloadService.isJukeboxEnabled()) { + if(downloadService.getPlayerState() == PlayerState.STARTED) { + SharedPreferences prefs = getPreferences(context); + int lossPref = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_TEMP_LOSS, "1")); + if(lossPref == 2 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK)) { + lowerFocus = true; + downloadService.setVolume(0.1f); + } else if(lossPref == 0 || (lossPref == 1 && focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT)) { + pauseFocus = true; + downloadService.pause(); + } + } + } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { + if(pauseFocus) { + pauseFocus = false; + downloadService.start(); + } else if(lowerFocus) { + lowerFocus = false; + downloadService.setVolume(1.0f); + } + } else if(focusChange == AudioManager.AUDIOFOCUS_LOSS && !downloadService.isJukeboxEnabled()) { + hasFocus = false; + downloadService.pause(); + audioManager.abandonAudioFocus(this); + } + } + }, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); + } + } + + public static int getMinDisplayMetric(Context context) + { + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + return Math.min(metrics.widthPixels, metrics.heightPixels); + } + + public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { + // Raw height and width of image + final int height = options.outHeight; + final int width = options.outWidth; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + + // Calculate ratios of height and width to requested height and + // width + final int heightRatio = Math.round((float) height / (float) reqHeight); + final int widthRatio = Math.round((float) width / (float) reqWidth); + + // Choose the smallest ratio as inSampleSize value, this will + // guarantee + // a final image with both dimensions larger than or equal to the + // requested height and width. + inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; + } + + return inSampleSize; + } + + public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth, int reqHeight) { + + // First decode with inJustDecodeBounds=true to check dimensions + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; + BitmapFactory.decodeFile(path, options); + + // Calculate inSampleSize + options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); + + // Decode bitmap with inSampleSize set + options.inJustDecodeBounds = false; + return BitmapFactory.decodeFile(path, options); + } + public static void linkButtons(Context context, RemoteViews views, boolean playerActive) { Intent intent = new Intent(context, playerActive ? DownloadActivity.class : MainActivity.class); diff --git a/src/com/thejoshwa/ultrasonic/androidapp/view/AlbumView.java b/src/com/thejoshwa/ultrasonic/androidapp/view/AlbumView.java index e5823b2b..08fe9051 100644 --- a/src/com/thejoshwa/ultrasonic/androidapp/view/AlbumView.java +++ b/src/com/thejoshwa/ultrasonic/androidapp/view/AlbumView.java @@ -59,7 +59,7 @@ public class AlbumView extends UpdateView { artistView.setText(album.getArtist()); artistView.setVisibility(album.getArtist() == null ? View.GONE : View.VISIBLE); starImageView.setImageDrawable(album.getStarred() ? Util.getDrawableFromAttribute(getContext(), R.attr.star_full) : Util.getDrawableFromAttribute(getContext(), R.attr.star_hollow)); - imageLoader.loadImage(coverArtView, album, false, true); + imageLoader.loadImage(coverArtView, album, false, 0, false, true); if (Util.isOffline(getContext())) { starImageView.setVisibility(View.GONE);