diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 13b981da2..4678a1656 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -65,6 +65,27 @@ android:configChanges="orientation|screenSize" > + + + + + + + + diff --git a/bin/AndroidManifest.xml b/bin/AndroidManifest.xml index 13b981da2..4678a1656 100644 --- a/bin/AndroidManifest.xml +++ b/bin/AndroidManifest.xml @@ -65,6 +65,27 @@ android:configChanges="orientation|screenSize" > + + + + + + + + diff --git a/bin/EhViewer.apk b/bin/EhViewer.apk new file mode 100644 index 000000000..f903bf550 Binary files /dev/null and b/bin/EhViewer.apk differ diff --git a/bin/R.txt b/bin/R.txt index 77c3f303e..39a6d13eb 100644 --- a/bin/R.txt +++ b/bin/R.txt @@ -93,72 +93,77 @@ int drawable doujinshi 0x7f020006 int drawable front 0x7f020007 int drawable gamecg 0x7f020008 int drawable ic_action_action_search 0x7f020009 -int drawable ic_action_core_overflow 0x7f02000a -int drawable ic_action_favourite 0x7f02000b -int drawable ic_action_jump 0x7f02000c -int drawable ic_action_refresh 0x7f02000d -int drawable ic_action_search 0x7f02000e -int drawable ic_action_settings 0x7f02000f -int drawable ic_launcher 0x7f020010 -int drawable ic_navigation_drawer 0x7f020011 -int drawable imageset 0x7f020012 -int drawable indicator_arrow 0x7f020013 -int drawable indicator_bg_bottom 0x7f020014 -int drawable indicator_bg_top 0x7f020015 -int drawable manga 0x7f020016 -int drawable mask 0x7f020017 -int drawable misc 0x7f020018 -int drawable non_h 0x7f020019 -int drawable refresh 0x7f02001a -int drawable sadpanda 0x7f02001b -int drawable scrollbar_blue 0x7f02001c -int drawable scrollbar_white 0x7f02001d -int drawable star 0x7f02001e -int drawable star_empty 0x7f02001f -int drawable star_half 0x7f020020 -int drawable unknown 0x7f020021 -int drawable wait 0x7f020022 -int drawable western 0x7f020023 -int id action_favourite 0x7f070086 -int id action_jump 0x7f070089 -int id action_refresh 0x7f070088 -int id action_search 0x7f070087 -int id action_settings 0x7f07008a +int drawable ic_action_completed 0x7f02000a +int drawable ic_action_core_overflow 0x7f02000b +int drawable ic_action_download 0x7f02000c +int drawable ic_action_favourite 0x7f02000d +int drawable ic_action_jump 0x7f02000e +int drawable ic_action_pause 0x7f02000f +int drawable ic_action_refresh 0x7f020010 +int drawable ic_action_search 0x7f020011 +int drawable ic_action_settings 0x7f020012 +int drawable ic_action_start 0x7f020013 +int drawable ic_launcher 0x7f020014 +int drawable ic_navigation_drawer 0x7f020015 +int drawable imageset 0x7f020016 +int drawable indicator_arrow 0x7f020017 +int drawable indicator_bg_bottom 0x7f020018 +int drawable indicator_bg_top 0x7f020019 +int drawable manga 0x7f02001a +int drawable mask 0x7f02001b +int drawable misc 0x7f02001c +int drawable non_h 0x7f02001d +int drawable refresh 0x7f02001e +int drawable sadpanda 0x7f02001f +int drawable scrollbar_blue 0x7f020020 +int drawable scrollbar_white 0x7f020021 +int drawable star 0x7f020022 +int drawable star_empty 0x7f020023 +int drawable star_half 0x7f020024 +int drawable unknown 0x7f020025 +int drawable wait 0x7f020026 +int drawable western 0x7f020027 +int id action 0x7f07004c +int id action_favourite 0x7f07008b +int id action_jump 0x7f07008e +int id action_refresh 0x7f07008d +int id action_search 0x7f07008c +int id action_settings 0x7f07008f int id alignBounds 0x7f070013 int id alignMargins 0x7f070014 int id both 0x7f070008 int id bottom 0x7f070016 -int id bottom_panel 0x7f07007c -int id button_artistcg 0x7f07004b -int id button_asianporn 0x7f070051 -int id button_cosplay 0x7f070050 -int id button_doujinshi 0x7f070049 -int id button_gamecg 0x7f07004c -int id button_imageset 0x7f07004f -int id button_login 0x7f070075 -int id button_manga 0x7f07004a -int id button_misc 0x7f070052 -int id button_non_h 0x7f07004e +int id bottom_panel 0x7f070081 +int id button_artistcg 0x7f070050 +int id button_asianporn 0x7f070056 +int id button_cosplay 0x7f070055 +int id button_doujinshi 0x7f07004e +int id button_gamecg 0x7f070051 +int id button_imageset 0x7f070054 +int id button_login 0x7f07007a +int id button_manga 0x7f07004f +int id button_misc 0x7f070057 +int id button_non_h 0x7f070053 int id button_read 0x7f07003a -int id button_western 0x7f07004d +int id button_western 0x7f070052 int id center 0x7f07001b int id centerCrop 0x7f070026 int id centerInside 0x7f070027 int id center_horizontal 0x7f070019 int id center_vertical 0x7f070017 -int id checkbox_advance 0x7f070054 -int id checkbox_sdesc 0x7f070058 -int id checkbox_sdt1 0x7f07005b -int id checkbox_sdt2 0x7f07005c -int id checkbox_sh 0x7f07005d -int id checkbox_sname 0x7f070056 -int id checkbox_sr 0x7f07005e -int id checkbox_stags 0x7f070057 -int id checkbox_sto 0x7f07005a -int id checkbox_storr 0x7f070059 +int id checkbox_advance 0x7f070059 +int id checkbox_sdesc 0x7f07005d +int id checkbox_sdt1 0x7f070060 +int id checkbox_sdt2 0x7f070061 +int id checkbox_sh 0x7f070062 +int id checkbox_sname 0x7f07005b +int id checkbox_sr 0x7f070063 +int id checkbox_stags 0x7f07005c +int id checkbox_sto 0x7f07005f +int id checkbox_storr 0x7f07005e int id clip_horizontal 0x7f07001e int id clip_vertical 0x7f07001d -int id cover 0x7f070069 +int id cover 0x7f07006e int id custom 0x7f070043 int id detail_average 0x7f070038 int id detail_button_cancel 0x7f07003c @@ -178,38 +183,40 @@ int id detail_type 0x7f070031 int id detail_uploader 0x7f070032 int id detail_wait 0x7f07002f int id disabled 0x7f070005 -int id drawer_login 0x7f07006f -int id drawer_login_over 0x7f070070 +int id download 0x7f070048 +int id drawer_login 0x7f070074 +int id drawer_login_over 0x7f070075 int id end 0x7f070020 -int id favourite 0x7f070048 +int id favourite 0x7f07004d int id fill 0x7f07001c int id fill_horizontal 0x7f07001a int id fill_vertical 0x7f070018 -int id filter_advance 0x7f070055 +int id filter_advance 0x7f07005a int id fitCenter 0x7f070024 int id fitEnd 0x7f070025 int id fitStart 0x7f070023 int id fitXY 0x7f070022 -int id fl_inner 0x7f07007e +int id fl_inner 0x7f070083 int id flip 0x7f07000d int id fullscreen 0x7f070003 int id gridview 0x7f07000e int id horizontal 0x7f070011 -int id is_exhentai 0x7f070071 +int id info 0x7f07004b +int id is_exhentai 0x7f070076 int id left 0x7f070000 int id list 0x7f070044 -int id list_button_logout 0x7f070077 -int id list_jump_edit 0x7f070062 -int id list_jump_sum 0x7f070060 -int id list_jump_to 0x7f070061 -int id list_list 0x7f070064 -int id list_main 0x7f070063 -int id list_menu_list 0x7f07006d -int id list_menu_login 0x7f07006e -int id list_no_found 0x7f070068 -int id list_refresh 0x7f070066 -int id list_wait_first 0x7f070065 -int id list_wait_logout 0x7f070078 +int id list_button_logout 0x7f07007c +int id list_jump_edit 0x7f070067 +int id list_jump_sum 0x7f070065 +int id list_jump_to 0x7f070066 +int id list_list 0x7f070069 +int id list_main 0x7f070068 +int id list_menu_list 0x7f070072 +int id list_menu_login 0x7f070073 +int id list_no_found 0x7f07006d +int id list_refresh 0x7f07006b +int id list_wait_first 0x7f07006a +int id list_wait_logout 0x7f07007d int id manga_detail 0x7f070029 int id manga_detail_normal 0x7f07002c int id manga_detail_offensive 0x7f07002d @@ -219,85 +226,89 @@ int id manualOnly 0x7f070009 int id margin 0x7f070002 int id matrix 0x7f070021 int id message 0x7f070042 -int id name 0x7f07006a +int id name 0x7f07006f int id negative_button 0x7f070045 int id neutral_button 0x7f070046 int id page_list 0x7f07003b -int id pager 0x7f070074 -int id paper_list_gridLayout 0x7f070079 -int id paper_list_wait 0x7f07007a -int id password 0x7f070073 +int id pager 0x7f070079 +int id paper_list_gridLayout 0x7f07007e +int id paper_list_wait 0x7f07007f +int id password 0x7f070078 int id positive_button 0x7f070047 -int id preview_button_refresh 0x7f07007b -int id preview_num 0x7f07007d +int id preview_button_refresh 0x7f070080 +int id preview_num 0x7f070082 +int id progressBar 0x7f07004a int id pullDownFromTop 0x7f07000a int id pullFromEnd 0x7f070007 int id pullFromStart 0x7f070006 int id pullUpFromBottom 0x7f07000b -int id pull_to_refresh_image 0x7f07007f -int id pull_to_refresh_progress 0x7f070080 -int id pull_to_refresh_sub_text 0x7f070082 -int id pull_to_refresh_text 0x7f070081 -int id rate 0x7f07006c +int id pull_to_refresh_image 0x7f070084 +int id pull_to_refresh_progress 0x7f070085 +int id pull_to_refresh_sub_text 0x7f070087 +int id pull_to_refresh_text 0x7f070086 +int id rate 0x7f070071 int id right 0x7f070001 int id rotate 0x7f07000c -int id sadpanda 0x7f070067 +int id sadpanda 0x7f07006c int id scroll_view 0x7f070041 int id scrollview 0x7f070010 -int id search_text 0x7f070053 +int id search_text 0x7f070058 int id selected_view 0x7f070004 -int id set_name_edit 0x7f070083 -int id slidingmenumain 0x7f070084 -int id spinner_min_rating 0x7f07005f +int id set_name_edit 0x7f070088 +int id slidingmenumain 0x7f070089 +int id spinner_min_rating 0x7f070064 int id start 0x7f07001f -int id text_username 0x7f070076 +int id text_username 0x7f07007b +int id thumb 0x7f070049 int id title 0x7f070040 int id top 0x7f070015 -int id type 0x7f07006b -int id username 0x7f070072 +int id type 0x7f070070 +int id username 0x7f070077 int id vertical 0x7f070012 -int id wait_message 0x7f070085 +int id wait_message 0x7f07008a int id webview 0x7f07000f int layout detail 0x7f030000 int layout detail_normal 0x7f030001 int layout detail_offensive 0x7f030002 int layout detail_pining 0x7f030003 int layout dialog 0x7f030004 -int layout favourite 0x7f030005 -int layout filter 0x7f030006 -int layout jump 0x7f030007 -int layout list 0x7f030008 -int layout list_item 0x7f030009 -int layout list_item_text 0x7f03000a -int layout list_menu_list 0x7f03000b -int layout list_menu_login 0x7f03000c -int layout login 0x7f03000d -int layout manga 0x7f03000e -int layout menu_item 0x7f03000f -int layout menu_login 0x7f030010 -int layout menu_login_over 0x7f030011 -int layout page_list 0x7f030012 -int layout page_list_panel 0x7f030013 -int layout pull_to_refresh_header_horizontal 0x7f030014 -int layout pull_to_refresh_header_vertical 0x7f030015 -int layout set_name 0x7f030016 -int layout slidingmenumain 0x7f030017 -int layout wait 0x7f030018 +int layout download 0x7f030005 +int layout download_item 0x7f030006 +int layout favourite 0x7f030007 +int layout filter 0x7f030008 +int layout jump 0x7f030009 +int layout list 0x7f03000a +int layout list_item 0x7f03000b +int layout list_item_text 0x7f03000c +int layout list_menu_list 0x7f03000d +int layout list_menu_login 0x7f03000e +int layout login 0x7f03000f +int layout manga 0x7f030010 +int layout menu_item 0x7f030011 +int layout menu_login 0x7f030012 +int layout menu_login_over 0x7f030013 +int layout page_list 0x7f030014 +int layout page_list_panel 0x7f030015 +int layout pull_to_refresh_header_horizontal 0x7f030016 +int layout pull_to_refresh_header_vertical 0x7f030017 +int layout set_name 0x7f030018 +int layout slidingmenumain 0x7f030019 +int layout wait 0x7f03001a int menu detail 0x7f0d0000 int menu main 0x7f0d0001 int raw change_log 0x7f060000 int raw thanks 0x7f060001 -int string _default 0x7f090084 -int string action_refresh 0x7f090050 -int string action_settings 0x7f090051 -int string actual_size 0x7f09008b -int string add 0x7f090080 -int string add_tag 0x7f090068 -int string add_to_favourite 0x7f09008f -int string advance_search_left 0x7f090093 +int string _default 0x7f09008c +int string action_refresh 0x7f090051 +int string action_settings 0x7f090052 +int string actual_size 0x7f090094 +int string add 0x7f090088 +int string add_tag 0x7f090069 +int string add_to_favourite 0x7f090098 +int string advance_search_left 0x7f09009b int string app_name 0x7f090003 -int string cache_large 0x7f090065 -int string changelog 0x7f09007a +int string cache_large 0x7f090066 +int string changelog 0x7f090082 int string checkbox_advance 0x7f090015 int string checkbox_sdesc 0x7f090018 int string checkbox_sdt1 0x7f09001b @@ -308,7 +319,7 @@ int string checkbox_sr 0x7f09001e int string checkbox_stags 0x7f090017 int string checkbox_sto 0x7f09001a int string checkbox_storr 0x7f090019 -int string create_cache_error 0x7f090067 +int string create_cache_error 0x7f090068 int string dailog_check_login 0x7f09000c int string dailog_check_network 0x7f090008 int string dailog_network_error_no 0x7f09000a @@ -317,124 +328,132 @@ int string dailog_waring_no 0x7f090007 int string dailog_waring_plain 0x7f090005 int string dailog_waring_title 0x7f090004 int string dailog_waring_yes 0x7f090006 -int string detail_average 0x7f09002d -int string detail_button_cancel 0x7f090032 -int string detail_button_every 0x7f090034 -int string detail_button_known 0x7f090036 -int string detail_button_once 0x7f090033 -int string detail_button_read 0x7f090031 -int string detail_language 0x7f09002c -int string detail_not_rated 0x7f090038 -int string detail_offensive 0x7f090030 -int string detail_offensive_title 0x7f09002f -int string detail_pages 0x7f09002a -int string detail_people 0x7f09002e -int string detail_pining 0x7f090035 -int string detail_posted 0x7f090029 -int string detail_preview_error 0x7f090037 -int string detail_size 0x7f09002b -int string detail_uploader 0x7f090028 +int string detail_average 0x7f09002e +int string detail_button_cancel 0x7f090033 +int string detail_button_every 0x7f090035 +int string detail_button_known 0x7f090037 +int string detail_button_once 0x7f090034 +int string detail_button_read 0x7f090032 +int string detail_language 0x7f09002d +int string detail_not_rated 0x7f090039 +int string detail_offensive 0x7f090031 +int string detail_offensive_title 0x7f090030 +int string detail_pages 0x7f09002b +int string detail_people 0x7f09002f +int string detail_pining 0x7f090036 +int string detail_posted 0x7f09002a +int string detail_preview_error 0x7f090038 +int string detail_size 0x7f09002c +int string detail_uploader 0x7f090029 int string dialog_messgae_login_or_not 0x7f090010 int string dialog_send_crash_no 0x7f090025 int string dialog_send_crash_plain 0x7f090023 int string dialog_send_crash_title 0x7f090022 int string dialog_send_crash_yes 0x7f090024 int string dialog_title_login_or_not 0x7f09000f -int string download 0x7f090090 -int string em_can_not_reach 0x7f09004e -int string em_check_login_error 0x7f090047 -int string em_client_protocol 0x7f090044 -int string em_logout_error 0x7f090048 -int string em_network_error 0x7f09003e -int string em_no_network 0x7f09004d -int string em_no_network_2 0x7f09004f -int string em_open_input_stream_error 0x7f090042 -int string em_parser_error 0x7f090041 -int string em_put_cache_error 0x7f090045 -int string em_read_input_stream_error 0x7f090043 -int string em_response_code_error 0x7f090040 -int string em_retry 0x7f09004a -int string em_retry_times 0x7f09004b -int string em_timeout 0x7f09003f -int string em_unknown_error 0x7f09004c -int string em_url_error 0x7f090049 -int string em_url_format_error 0x7f090046 -int string error 0x7f090079 +int string download 0x7f09008f +int string download_successfully 0x7f090078 +int string download_task_finished 0x7f090076 +int string download_unsuccessfully 0x7f090079 +int string downloading 0x7f090077 +int string em_can_not_reach 0x7f09004f +int string em_check_login_error 0x7f090048 +int string em_client_protocol 0x7f090045 +int string em_logout_error 0x7f090049 +int string em_network_error 0x7f09003f +int string em_no_network 0x7f09004e +int string em_no_network_2 0x7f090050 +int string em_open_input_stream_error 0x7f090043 +int string em_parser_error 0x7f090042 +int string em_put_cache_error 0x7f090046 +int string em_read_input_stream_error 0x7f090044 +int string em_response_code_error 0x7f090041 +int string em_retry 0x7f09004b +int string em_retry_times 0x7f09004c +int string em_timeout 0x7f090040 +int string em_unknown_error 0x7f09004d +int string em_url_error 0x7f09004a +int string em_url_format_error 0x7f090047 +int string error 0x7f090081 int string exit_tip 0x7f09000b -int string favourite 0x7f090086 -int string first_page 0x7f09003a -int string fit_to_height 0x7f09008d -int string fit_to_screen 0x7f09008e -int string fit_to_width 0x7f09008c +int string favourite 0x7f09008e +int string first_page 0x7f09003b +int string fit_to_height 0x7f090096 +int string fit_to_screen 0x7f090097 +int string fit_to_width 0x7f090095 int string hint_no_keyword 0x7f090014 -int string homepage 0x7f090085 -int string input_error 0x7f090066 -int string jump 0x7f090082 +int string homepage 0x7f09008d +int string input_error 0x7f090067 +int string jump 0x7f09008a int string jump_sum 0x7f09001f int string jump_to 0x7f090020 -int string landscape 0x7f090055 -int string last_page 0x7f090074 -int string load_pre 0x7f090039 -int string login 0x7f09007b -int string logout 0x7f09007c -int string new_tag_name 0x7f09006d -int string no_found 0x7f090027 +int string landscape 0x7f090056 +int string last_page 0x7f09007c +int string load_pre 0x7f09003a +int string login 0x7f090083 +int string logout 0x7f090084 +int string new_tag_name 0x7f09006e +int string no_found 0x7f090028 int string not_login 0x7f090011 -int string password 0x7f09007f -int string period 0x7f090077 -int string portrait 0x7f090054 -int string preference_author 0x7f090063 -int string preference_author_summary 0x7f090064 -int string preference_auto_page_cache 0x7f09005f -int string preference_auto_page_cache_summary_off 0x7f090061 -int string preference_auto_page_cache_summary_on 0x7f090060 -int string preference_cache_summary 0x7f09005d -int string preference_cache_summary_no 0x7f09005e -int string preference_category_about 0x7f090062 -int string preference_category_cache 0x7f090058 -int string preference_category_display 0x7f090052 -int string preference_clear_cp_cache 0x7f09005a -int string preference_clear_page_cache 0x7f09005c -int string preference_cp_cache 0x7f090059 -int string preference_page_cache 0x7f09005b -int string preference_page_scaling 0x7f090056 -int string preference_screen_ori 0x7f090053 -int string preference_settings_title 0x7f090057 -int string pull_next_pull 0x7f090072 -int string pull_next_release 0x7f090073 -int string pull_pre_pull 0x7f090070 -int string pull_pre_release 0x7f090071 -int string pull_refresh_pull 0x7f09006e -int string pull_refresh_release 0x7f09006f +int string not_started 0x7f09007a +int string password 0x7f090087 +int string period 0x7f09007f +int string portrait 0x7f090055 +int string preference_author 0x7f090064 +int string preference_author_summary 0x7f090065 +int string preference_auto_page_cache 0x7f090060 +int string preference_auto_page_cache_summary_off 0x7f090062 +int string preference_auto_page_cache_summary_on 0x7f090061 +int string preference_cache_summary 0x7f09005e +int string preference_cache_summary_no 0x7f09005f +int string preference_category_about 0x7f090063 +int string preference_category_cache 0x7f090059 +int string preference_category_display 0x7f090053 +int string preference_clear_cp_cache 0x7f09005b +int string preference_clear_page_cache 0x7f09005d +int string preference_cp_cache 0x7f09005a +int string preference_page_cache 0x7f09005c +int string preference_page_scaling 0x7f090057 +int string preference_screen_ori 0x7f090054 +int string preference_settings_title 0x7f090058 +int string pull_next_pull 0x7f090073 +int string pull_next_release 0x7f090074 +int string pull_pre_pull 0x7f090071 +int string pull_pre_release 0x7f090072 +int string pull_refresh_pull 0x7f09006f +int string pull_refresh_release 0x7f090070 int string pull_to_refresh_pull_label 0x7f090000 int string pull_to_refresh_refreshing_label 0x7f090002 int string pull_to_refresh_release_label 0x7f090001 -int string refresh 0x7f090078 -int string remove 0x7f090091 -int string retry_max_next 0x7f09003d -int string retry_max_pre 0x7f09003c -int string sadpanda 0x7f090075 -int string some_page 0x7f090083 -int string star_2 0x7f090087 -int string star_3 0x7f090088 -int string star_4 0x7f090089 -int string star_5 0x7f09008a -int string start_reloading 0x7f09003b -int string tag_change_name 0x7f09006c -int string tag_name 0x7f090069 -int string tag_name_empty 0x7f09006a -int string tag_name_exist 0x7f09006b -int string thanks 0x7f090092 +int string refresh 0x7f090080 +int string remove 0x7f090099 +int string retry_max_next 0x7f09003e +int string retry_max_pre 0x7f09003d +int string sadpanda 0x7f09007d +int string some_page 0x7f09008b +int string star_2 0x7f090090 +int string star_3 0x7f090091 +int string star_4 0x7f090092 +int string star_5 0x7f090093 +int string start_download_task 0x7f090075 +int string start_reloading 0x7f09003c +int string tag_change_name 0x7f09006d +int string tag_name 0x7f09006a +int string tag_name_empty 0x7f09006b +int string tag_name_exist 0x7f09006c +int string thanks 0x7f09009a +int string toast_add_download 0x7f090027 int string toast_add_favourite 0x7f090026 int string toast_invalid_page 0x7f090021 int string toast_login_failed 0x7f09000e int string toast_login_succeeded 0x7f09000d int string toast_logout_failed 0x7f090013 int string toast_logout_succeeded 0x7f090012 -int string unfinished 0x7f090076 -int string username 0x7f09007e -int string wait 0x7f09007d -int string what_to_do 0x7f090081 +int string unfinished 0x7f09007e +int string username 0x7f090086 +int string wait 0x7f090085 +int string waiting 0x7f09007b +int string what_to_do 0x7f090089 int style ActionBar 0x7f0c0000 int style AppTheme 0x7f0c0006 int style Button 0x7f0c0003 diff --git a/bin/classes.dex b/bin/classes.dex new file mode 100644 index 000000000..bc2d5c568 Binary files /dev/null and b/bin/classes.dex differ diff --git a/bin/dexedLibs/android-support-v4-1c1a4a4d71c1c723e2137d4d967c3739.jar b/bin/dexedLibs/android-support-v4-1c1a4a4d71c1c723e2137d4d967c3739.jar new file mode 100644 index 000000000..e911d6a2c Binary files /dev/null and b/bin/dexedLibs/android-support-v4-1c1a4a4d71c1c723e2137d4d967c3739.jar differ diff --git a/bin/dexedLibs/android-support-v7-gridlayout-65f5994dd745e0ac459040dfde731386.jar b/bin/dexedLibs/android-support-v7-gridlayout-65f5994dd745e0ac459040dfde731386.jar new file mode 100644 index 000000000..aa01e5efa Binary files /dev/null and b/bin/dexedLibs/android-support-v7-gridlayout-65f5994dd745e0ac459040dfde731386.jar differ diff --git a/bin/dexedLibs/commons-lang3-3.2.1-8a36c15e1c40f2ad0206e5389bc96b5a.jar b/bin/dexedLibs/commons-lang3-3.2.1-8a36c15e1c40f2ad0206e5389bc96b5a.jar new file mode 100644 index 000000000..79ba9e369 Binary files /dev/null and b/bin/dexedLibs/commons-lang3-3.2.1-8a36c15e1c40f2ad0206e5389bc96b5a.jar differ diff --git a/bin/dexedLibs/gridlayout_v7-9aadecd3606a07a44286cb470164fa04.jar b/bin/dexedLibs/gridlayout_v7-9aadecd3606a07a44286cb470164fa04.jar new file mode 100644 index 000000000..efe1dc4af Binary files /dev/null and b/bin/dexedLibs/gridlayout_v7-9aadecd3606a07a44286cb470164fa04.jar differ diff --git a/bin/dexedLibs/library-8cd7abb8953cf577c4eead38fb2ed13b.jar b/bin/dexedLibs/library-8cd7abb8953cf577c4eead38fb2ed13b.jar new file mode 100644 index 000000000..efc222767 Binary files /dev/null and b/bin/dexedLibs/library-8cd7abb8953cf577c4eead38fb2ed13b.jar differ diff --git a/bin/dexedLibs/slidingmenu-f48f3a4eceb3b9455e8ae38a55377052.jar b/bin/dexedLibs/slidingmenu-f48f3a4eceb3b9455e8ae38a55377052.jar new file mode 100644 index 000000000..db309fbbc Binary files /dev/null and b/bin/dexedLibs/slidingmenu-f48f3a4eceb3b9455e8ae38a55377052.jar differ diff --git a/bin/res/crunch/drawable-hdpi/artistcg.png b/bin/res/crunch/drawable-hdpi/artistcg.png new file mode 100644 index 000000000..5fc1018b6 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/artistcg.png differ diff --git a/bin/res/crunch/drawable-hdpi/asianporn.png b/bin/res/crunch/drawable-hdpi/asianporn.png new file mode 100644 index 000000000..cbb4f6700 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/asianporn.png differ diff --git a/bin/res/crunch/drawable-hdpi/cosplay.png b/bin/res/crunch/drawable-hdpi/cosplay.png new file mode 100644 index 000000000..6f76b00b1 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/cosplay.png differ diff --git a/bin/res/crunch/drawable-hdpi/doujinshi.png b/bin/res/crunch/drawable-hdpi/doujinshi.png new file mode 100644 index 000000000..aa838023a Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/doujinshi.png differ diff --git a/bin/res/crunch/drawable-hdpi/gamecg.png b/bin/res/crunch/drawable-hdpi/gamecg.png new file mode 100644 index 000000000..a6fae72d7 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/gamecg.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_action_action_search.png b/bin/res/crunch/drawable-hdpi/ic_action_action_search.png new file mode 100644 index 000000000..ffb66bbe0 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_action_action_search.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_action_completed.png b/bin/res/crunch/drawable-hdpi/ic_action_completed.png new file mode 100644 index 000000000..b2d9bc6a9 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_action_completed.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_action_core_overflow.png b/bin/res/crunch/drawable-hdpi/ic_action_core_overflow.png new file mode 100644 index 000000000..4d3b90d60 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_action_core_overflow.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_action_download.png b/bin/res/crunch/drawable-hdpi/ic_action_download.png new file mode 100644 index 000000000..d5646a55b Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_action_download.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_action_favourite.png b/bin/res/crunch/drawable-hdpi/ic_action_favourite.png new file mode 100644 index 000000000..f57e87f1f Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_action_favourite.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_action_jump.png b/bin/res/crunch/drawable-hdpi/ic_action_jump.png new file mode 100644 index 000000000..857db0453 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_action_jump.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_action_pause.png b/bin/res/crunch/drawable-hdpi/ic_action_pause.png new file mode 100644 index 000000000..77759896d Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_action_pause.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_action_refresh.png b/bin/res/crunch/drawable-hdpi/ic_action_refresh.png new file mode 100644 index 000000000..fec24f27d Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_action_refresh.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_action_settings.png b/bin/res/crunch/drawable-hdpi/ic_action_settings.png new file mode 100644 index 000000000..509af13c9 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_action_settings.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_action_start.png b/bin/res/crunch/drawable-hdpi/ic_action_start.png new file mode 100644 index 000000000..34253492b Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_action_start.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_launcher.png b/bin/res/crunch/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..70cfbbf17 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_launcher.png differ diff --git a/bin/res/crunch/drawable-hdpi/ic_navigation_drawer.png b/bin/res/crunch/drawable-hdpi/ic_navigation_drawer.png new file mode 100644 index 000000000..ebcebc47a Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/ic_navigation_drawer.png differ diff --git a/bin/res/crunch/drawable-hdpi/imageset.png b/bin/res/crunch/drawable-hdpi/imageset.png new file mode 100644 index 000000000..e65093605 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/imageset.png differ diff --git a/bin/res/crunch/drawable-hdpi/manga.png b/bin/res/crunch/drawable-hdpi/manga.png new file mode 100644 index 000000000..f397b5636 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/manga.png differ diff --git a/bin/res/crunch/drawable-hdpi/mask.png b/bin/res/crunch/drawable-hdpi/mask.png new file mode 100644 index 000000000..7682ebd7d Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/mask.png differ diff --git a/bin/res/crunch/drawable-hdpi/misc.png b/bin/res/crunch/drawable-hdpi/misc.png new file mode 100644 index 000000000..165cafdb3 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/misc.png differ diff --git a/bin/res/crunch/drawable-hdpi/non_h.png b/bin/res/crunch/drawable-hdpi/non_h.png new file mode 100644 index 000000000..154b6a46d Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/non_h.png differ diff --git a/bin/res/crunch/drawable-hdpi/scrollbar_white.9.png b/bin/res/crunch/drawable-hdpi/scrollbar_white.9.png new file mode 100644 index 000000000..32e33ccd2 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/scrollbar_white.9.png differ diff --git a/bin/res/crunch/drawable-hdpi/star.png b/bin/res/crunch/drawable-hdpi/star.png new file mode 100644 index 000000000..44a45a5c4 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/star.png differ diff --git a/bin/res/crunch/drawable-hdpi/star_empty.png b/bin/res/crunch/drawable-hdpi/star_empty.png new file mode 100644 index 000000000..dc9a65cff Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/star_empty.png differ diff --git a/bin/res/crunch/drawable-hdpi/star_half.png b/bin/res/crunch/drawable-hdpi/star_half.png new file mode 100644 index 000000000..c81bd1bd2 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/star_half.png differ diff --git a/bin/res/crunch/drawable-hdpi/unknown.png b/bin/res/crunch/drawable-hdpi/unknown.png new file mode 100644 index 000000000..3f50c6e48 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/unknown.png differ diff --git a/bin/res/crunch/drawable-hdpi/western.png b/bin/res/crunch/drawable-hdpi/western.png new file mode 100644 index 000000000..6c61050c1 Binary files /dev/null and b/bin/res/crunch/drawable-hdpi/western.png differ diff --git a/bin/res/crunch/drawable-mdpi/artistcg.png b/bin/res/crunch/drawable-mdpi/artistcg.png new file mode 100644 index 000000000..ec3e32f0a Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/artistcg.png differ diff --git a/bin/res/crunch/drawable-mdpi/asianporn.png b/bin/res/crunch/drawable-mdpi/asianporn.png new file mode 100644 index 000000000..022466c11 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/asianporn.png differ diff --git a/bin/res/crunch/drawable-mdpi/cosplay.png b/bin/res/crunch/drawable-mdpi/cosplay.png new file mode 100644 index 000000000..2a4566531 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/cosplay.png differ diff --git a/bin/res/crunch/drawable-mdpi/doujinshi.png b/bin/res/crunch/drawable-mdpi/doujinshi.png new file mode 100644 index 000000000..2c152aa83 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/doujinshi.png differ diff --git a/bin/res/crunch/drawable-mdpi/gamecg.png b/bin/res/crunch/drawable-mdpi/gamecg.png new file mode 100644 index 000000000..af91cfaed Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/gamecg.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_action_action_search.png b/bin/res/crunch/drawable-mdpi/ic_action_action_search.png new file mode 100644 index 000000000..c74b0527a Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_action_action_search.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_action_completed.png b/bin/res/crunch/drawable-mdpi/ic_action_completed.png new file mode 100644 index 000000000..269be3cd5 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_action_completed.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_action_core_overflow.png b/bin/res/crunch/drawable-mdpi/ic_action_core_overflow.png new file mode 100644 index 000000000..9e44261b9 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_action_core_overflow.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_action_download.png b/bin/res/crunch/drawable-mdpi/ic_action_download.png new file mode 100644 index 000000000..856aa8dd9 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_action_download.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_action_favourite.png b/bin/res/crunch/drawable-mdpi/ic_action_favourite.png new file mode 100644 index 000000000..d559bd3c2 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_action_favourite.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_action_jump.png b/bin/res/crunch/drawable-mdpi/ic_action_jump.png new file mode 100644 index 000000000..fa79413aa Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_action_jump.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_action_pause.png b/bin/res/crunch/drawable-mdpi/ic_action_pause.png new file mode 100644 index 000000000..d8fedec72 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_action_pause.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_action_refresh.png b/bin/res/crunch/drawable-mdpi/ic_action_refresh.png new file mode 100644 index 000000000..cf473e3bd Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_action_refresh.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_action_settings.png b/bin/res/crunch/drawable-mdpi/ic_action_settings.png new file mode 100644 index 000000000..3173b19a1 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_action_settings.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_action_start.png b/bin/res/crunch/drawable-mdpi/ic_action_start.png new file mode 100644 index 000000000..83ffaf09c Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_action_start.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_launcher.png b/bin/res/crunch/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..02f609fec Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_launcher.png differ diff --git a/bin/res/crunch/drawable-mdpi/ic_navigation_drawer.png b/bin/res/crunch/drawable-mdpi/ic_navigation_drawer.png new file mode 100644 index 000000000..b4a600a24 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/ic_navigation_drawer.png differ diff --git a/bin/res/crunch/drawable-mdpi/imageset.png b/bin/res/crunch/drawable-mdpi/imageset.png new file mode 100644 index 000000000..1df00f6c3 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/imageset.png differ diff --git a/bin/res/crunch/drawable-mdpi/manga.png b/bin/res/crunch/drawable-mdpi/manga.png new file mode 100644 index 000000000..f3e53dfd6 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/manga.png differ diff --git a/bin/res/crunch/drawable-mdpi/mask.png b/bin/res/crunch/drawable-mdpi/mask.png new file mode 100644 index 000000000..8fb919a78 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/mask.png differ diff --git a/bin/res/crunch/drawable-mdpi/misc.png b/bin/res/crunch/drawable-mdpi/misc.png new file mode 100644 index 000000000..9eb145cfa Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/misc.png differ diff --git a/bin/res/crunch/drawable-mdpi/non_h.png b/bin/res/crunch/drawable-mdpi/non_h.png new file mode 100644 index 000000000..7ad513089 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/non_h.png differ diff --git a/bin/res/crunch/drawable-mdpi/scrollbar_blue.9.png b/bin/res/crunch/drawable-mdpi/scrollbar_blue.9.png new file mode 100644 index 000000000..836c804da Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/scrollbar_blue.9.png differ diff --git a/bin/res/crunch/drawable-mdpi/scrollbar_white.9.png b/bin/res/crunch/drawable-mdpi/scrollbar_white.9.png new file mode 100644 index 000000000..7de872c88 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/scrollbar_white.9.png differ diff --git a/bin/res/crunch/drawable-mdpi/star.png b/bin/res/crunch/drawable-mdpi/star.png new file mode 100644 index 000000000..f3811e1ce Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/star.png differ diff --git a/bin/res/crunch/drawable-mdpi/star_empty.png b/bin/res/crunch/drawable-mdpi/star_empty.png new file mode 100644 index 000000000..4e6755ffd Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/star_empty.png differ diff --git a/bin/res/crunch/drawable-mdpi/star_half.png b/bin/res/crunch/drawable-mdpi/star_half.png new file mode 100644 index 000000000..0b2a5a9bc Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/star_half.png differ diff --git a/bin/res/crunch/drawable-mdpi/unknown.png b/bin/res/crunch/drawable-mdpi/unknown.png new file mode 100644 index 000000000..8bb749e5b Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/unknown.png differ diff --git a/bin/res/crunch/drawable-mdpi/western.png b/bin/res/crunch/drawable-mdpi/western.png new file mode 100644 index 000000000..d4ddf4435 Binary files /dev/null and b/bin/res/crunch/drawable-mdpi/western.png differ diff --git a/bin/res/crunch/drawable-xhdpi/artistcg.png b/bin/res/crunch/drawable-xhdpi/artistcg.png new file mode 100644 index 000000000..6911d9615 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/artistcg.png differ diff --git a/bin/res/crunch/drawable-xhdpi/asianporn.png b/bin/res/crunch/drawable-xhdpi/asianporn.png new file mode 100644 index 000000000..68dd8c5bc Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/asianporn.png differ diff --git a/bin/res/crunch/drawable-xhdpi/cosplay.png b/bin/res/crunch/drawable-xhdpi/cosplay.png new file mode 100644 index 000000000..29e1b8526 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/cosplay.png differ diff --git a/bin/res/crunch/drawable-xhdpi/doujinshi.png b/bin/res/crunch/drawable-xhdpi/doujinshi.png new file mode 100644 index 000000000..6bf5b73f9 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/doujinshi.png differ diff --git a/bin/res/crunch/drawable-xhdpi/gamecg.png b/bin/res/crunch/drawable-xhdpi/gamecg.png new file mode 100644 index 000000000..43a76590f Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/gamecg.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_action_action_search.png b/bin/res/crunch/drawable-xhdpi/ic_action_action_search.png new file mode 100644 index 000000000..74b428c3c Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_action_action_search.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_action_completed.png b/bin/res/crunch/drawable-xhdpi/ic_action_completed.png new file mode 100644 index 000000000..f75c7f7a2 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_action_completed.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_action_core_overflow.png b/bin/res/crunch/drawable-xhdpi/ic_action_core_overflow.png new file mode 100644 index 000000000..d45e03853 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_action_core_overflow.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_action_download.png b/bin/res/crunch/drawable-xhdpi/ic_action_download.png new file mode 100644 index 000000000..738959600 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_action_download.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_action_favourite.png b/bin/res/crunch/drawable-xhdpi/ic_action_favourite.png new file mode 100644 index 000000000..d46a2a009 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_action_favourite.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_action_jump.png b/bin/res/crunch/drawable-xhdpi/ic_action_jump.png new file mode 100644 index 000000000..10fe11f9c Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_action_jump.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_action_pause.png b/bin/res/crunch/drawable-xhdpi/ic_action_pause.png new file mode 100644 index 000000000..244fdb8e9 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_action_pause.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_action_refresh.png b/bin/res/crunch/drawable-xhdpi/ic_action_refresh.png new file mode 100644 index 000000000..492101ce0 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_action_refresh.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_action_settings.png b/bin/res/crunch/drawable-xhdpi/ic_action_settings.png new file mode 100644 index 000000000..2587658a0 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_action_settings.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_action_start.png b/bin/res/crunch/drawable-xhdpi/ic_action_start.png new file mode 100644 index 000000000..4213d2398 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_action_start.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_launcher.png b/bin/res/crunch/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..ca5a1c0a5 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_launcher.png differ diff --git a/bin/res/crunch/drawable-xhdpi/ic_navigation_drawer.png b/bin/res/crunch/drawable-xhdpi/ic_navigation_drawer.png new file mode 100644 index 000000000..7f9bd18e1 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/ic_navigation_drawer.png differ diff --git a/bin/res/crunch/drawable-xhdpi/imageset.png b/bin/res/crunch/drawable-xhdpi/imageset.png new file mode 100644 index 000000000..06e425a45 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/imageset.png differ diff --git a/bin/res/crunch/drawable-xhdpi/manga.png b/bin/res/crunch/drawable-xhdpi/manga.png new file mode 100644 index 000000000..d9ac3a3a1 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/manga.png differ diff --git a/bin/res/crunch/drawable-xhdpi/mask.png b/bin/res/crunch/drawable-xhdpi/mask.png new file mode 100644 index 000000000..2280d690b Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/mask.png differ diff --git a/bin/res/crunch/drawable-xhdpi/misc.png b/bin/res/crunch/drawable-xhdpi/misc.png new file mode 100644 index 000000000..a1bf42725 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/misc.png differ diff --git a/bin/res/crunch/drawable-xhdpi/non_h.png b/bin/res/crunch/drawable-xhdpi/non_h.png new file mode 100644 index 000000000..b7f43e870 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/non_h.png differ diff --git a/bin/res/crunch/drawable-xhdpi/scrollbar_blue.9.png b/bin/res/crunch/drawable-xhdpi/scrollbar_blue.9.png new file mode 100644 index 000000000..bad663da2 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/scrollbar_blue.9.png differ diff --git a/bin/res/crunch/drawable-xhdpi/scrollbar_white.9.png b/bin/res/crunch/drawable-xhdpi/scrollbar_white.9.png new file mode 100644 index 000000000..335e87399 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/scrollbar_white.9.png differ diff --git a/bin/res/crunch/drawable-xhdpi/star.png b/bin/res/crunch/drawable-xhdpi/star.png new file mode 100644 index 000000000..b278cba1f Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/star.png differ diff --git a/bin/res/crunch/drawable-xhdpi/star_empty.png b/bin/res/crunch/drawable-xhdpi/star_empty.png new file mode 100644 index 000000000..964b1ab2c Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/star_empty.png differ diff --git a/bin/res/crunch/drawable-xhdpi/star_half.png b/bin/res/crunch/drawable-xhdpi/star_half.png new file mode 100644 index 000000000..f10e243a1 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/star_half.png differ diff --git a/bin/res/crunch/drawable-xhdpi/unknown.png b/bin/res/crunch/drawable-xhdpi/unknown.png new file mode 100644 index 000000000..27fe71ad5 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/unknown.png differ diff --git a/bin/res/crunch/drawable-xhdpi/western.png b/bin/res/crunch/drawable-xhdpi/western.png new file mode 100644 index 000000000..50afc39e1 Binary files /dev/null and b/bin/res/crunch/drawable-xhdpi/western.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/artistcg.png b/bin/res/crunch/drawable-xxhdpi/artistcg.png new file mode 100644 index 000000000..ddfd2b42c Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/artistcg.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/asianporn.png b/bin/res/crunch/drawable-xxhdpi/asianporn.png new file mode 100644 index 000000000..205714f7a Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/asianporn.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/back.png b/bin/res/crunch/drawable-xxhdpi/back.png new file mode 100644 index 000000000..05be3d0b4 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/back.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/cosplay.png b/bin/res/crunch/drawable-xxhdpi/cosplay.png new file mode 100644 index 000000000..a589c0826 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/cosplay.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/doujinshi.png b/bin/res/crunch/drawable-xxhdpi/doujinshi.png new file mode 100644 index 000000000..7cdbefaba Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/doujinshi.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/front.png b/bin/res/crunch/drawable-xxhdpi/front.png new file mode 100644 index 000000000..8a33b13b8 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/front.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/gamecg.png b/bin/res/crunch/drawable-xxhdpi/gamecg.png new file mode 100644 index 000000000..47838c882 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/gamecg.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_action_completed.png b/bin/res/crunch/drawable-xxhdpi/ic_action_completed.png new file mode 100644 index 000000000..1f37139ee Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_action_completed.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_action_core_overflow.png b/bin/res/crunch/drawable-xxhdpi/ic_action_core_overflow.png new file mode 100644 index 000000000..7f2d444fb Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_action_core_overflow.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_action_download.png b/bin/res/crunch/drawable-xxhdpi/ic_action_download.png new file mode 100644 index 000000000..35cd96cba Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_action_download.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_action_favourite.png b/bin/res/crunch/drawable-xxhdpi/ic_action_favourite.png new file mode 100644 index 000000000..b359e57ef Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_action_favourite.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_action_jump.png b/bin/res/crunch/drawable-xxhdpi/ic_action_jump.png new file mode 100644 index 000000000..7497865d4 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_action_jump.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_action_pause.png b/bin/res/crunch/drawable-xxhdpi/ic_action_pause.png new file mode 100644 index 000000000..b1b849ab1 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_action_pause.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_action_refresh.png b/bin/res/crunch/drawable-xxhdpi/ic_action_refresh.png new file mode 100644 index 000000000..b9097069f Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_action_refresh.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_action_search.png b/bin/res/crunch/drawable-xxhdpi/ic_action_search.png new file mode 100644 index 000000000..38cfd073f Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_action_search.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_action_settings.png b/bin/res/crunch/drawable-xxhdpi/ic_action_settings.png new file mode 100644 index 000000000..4bf08b90a Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_action_settings.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_action_start.png b/bin/res/crunch/drawable-xxhdpi/ic_action_start.png new file mode 100644 index 000000000..b5216a32d Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_action_start.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_launcher.png b/bin/res/crunch/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d7a36db9f Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_launcher.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/ic_navigation_drawer.png b/bin/res/crunch/drawable-xxhdpi/ic_navigation_drawer.png new file mode 100644 index 000000000..71a5bcffa Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/ic_navigation_drawer.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/imageset.png b/bin/res/crunch/drawable-xxhdpi/imageset.png new file mode 100644 index 000000000..bd4a31c71 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/imageset.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/manga.png b/bin/res/crunch/drawable-xxhdpi/manga.png new file mode 100644 index 000000000..4b1d9b093 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/manga.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/mask.png b/bin/res/crunch/drawable-xxhdpi/mask.png new file mode 100644 index 000000000..ce48a1acb Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/mask.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/misc.png b/bin/res/crunch/drawable-xxhdpi/misc.png new file mode 100644 index 000000000..bd2f9dbbd Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/misc.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/non_h.png b/bin/res/crunch/drawable-xxhdpi/non_h.png new file mode 100644 index 000000000..9c2644472 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/non_h.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/scrollbar_blue.9.png b/bin/res/crunch/drawable-xxhdpi/scrollbar_blue.9.png new file mode 100644 index 000000000..3855a84e7 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/scrollbar_blue.9.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/scrollbar_white.9.png b/bin/res/crunch/drawable-xxhdpi/scrollbar_white.9.png new file mode 100644 index 000000000..a7626b309 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/scrollbar_white.9.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/star.png b/bin/res/crunch/drawable-xxhdpi/star.png new file mode 100644 index 000000000..0506e58f9 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/star.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/star_empty.png b/bin/res/crunch/drawable-xxhdpi/star_empty.png new file mode 100644 index 000000000..c61edc57c Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/star_empty.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/star_half.png b/bin/res/crunch/drawable-xxhdpi/star_half.png new file mode 100644 index 000000000..7a00511a2 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/star_half.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/unknown.png b/bin/res/crunch/drawable-xxhdpi/unknown.png new file mode 100644 index 000000000..5380b9c17 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/unknown.png differ diff --git a/bin/res/crunch/drawable-xxhdpi/western.png b/bin/res/crunch/drawable-xxhdpi/western.png new file mode 100644 index 000000000..0d439f937 Binary files /dev/null and b/bin/res/crunch/drawable-xxhdpi/western.png differ diff --git a/bin/res/crunch/drawable-xxxhdpi/ic_launcher.png b/bin/res/crunch/drawable-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..3f1968806 Binary files /dev/null and b/bin/res/crunch/drawable-xxxhdpi/ic_launcher.png differ diff --git a/bin/res/crunch/drawable/refresh.png b/bin/res/crunch/drawable/refresh.png new file mode 100644 index 000000000..31f22571b Binary files /dev/null and b/bin/res/crunch/drawable/refresh.png differ diff --git a/bin/resources.ap_ b/bin/resources.ap_ new file mode 100644 index 000000000..65c158e40 Binary files /dev/null and b/bin/resources.ap_ differ diff --git a/res/drawable-hdpi/ic_action_completed.png b/res/drawable-hdpi/ic_action_completed.png new file mode 100644 index 000000000..38a24a11a Binary files /dev/null and b/res/drawable-hdpi/ic_action_completed.png differ diff --git a/res/drawable-hdpi/ic_action_download.png b/res/drawable-hdpi/ic_action_download.png new file mode 100644 index 000000000..2303b48df Binary files /dev/null and b/res/drawable-hdpi/ic_action_download.png differ diff --git a/res/drawable-hdpi/ic_action_pause.png b/res/drawable-hdpi/ic_action_pause.png new file mode 100644 index 000000000..c3bd3d730 Binary files /dev/null and b/res/drawable-hdpi/ic_action_pause.png differ diff --git a/res/drawable-hdpi/ic_action_start.png b/res/drawable-hdpi/ic_action_start.png new file mode 100644 index 000000000..b1fc0acac Binary files /dev/null and b/res/drawable-hdpi/ic_action_start.png differ diff --git a/res/drawable-mdpi/ic_action_completed.png b/res/drawable-mdpi/ic_action_completed.png new file mode 100644 index 000000000..a1ea4159c Binary files /dev/null and b/res/drawable-mdpi/ic_action_completed.png differ diff --git a/res/drawable-mdpi/ic_action_download.png b/res/drawable-mdpi/ic_action_download.png new file mode 100644 index 000000000..d4c2f27b7 Binary files /dev/null and b/res/drawable-mdpi/ic_action_download.png differ diff --git a/res/drawable-mdpi/ic_action_pause.png b/res/drawable-mdpi/ic_action_pause.png new file mode 100644 index 000000000..bd30e4560 Binary files /dev/null and b/res/drawable-mdpi/ic_action_pause.png differ diff --git a/res/drawable-mdpi/ic_action_start.png b/res/drawable-mdpi/ic_action_start.png new file mode 100644 index 000000000..01327a705 Binary files /dev/null and b/res/drawable-mdpi/ic_action_start.png differ diff --git a/res/drawable-xhdpi/ic_action_completed.png b/res/drawable-xhdpi/ic_action_completed.png new file mode 100644 index 000000000..67bc42785 Binary files /dev/null and b/res/drawable-xhdpi/ic_action_completed.png differ diff --git a/res/drawable-xhdpi/ic_action_download.png b/res/drawable-xhdpi/ic_action_download.png new file mode 100644 index 000000000..67df9c007 Binary files /dev/null and b/res/drawable-xhdpi/ic_action_download.png differ diff --git a/res/drawable-xhdpi/ic_action_pause.png b/res/drawable-xhdpi/ic_action_pause.png new file mode 100644 index 000000000..c216e3eed Binary files /dev/null and b/res/drawable-xhdpi/ic_action_pause.png differ diff --git a/res/drawable-xhdpi/ic_action_start.png b/res/drawable-xhdpi/ic_action_start.png new file mode 100644 index 000000000..a203bc1bd Binary files /dev/null and b/res/drawable-xhdpi/ic_action_start.png differ diff --git a/res/drawable-xxhdpi/ic_action_completed.png b/res/drawable-xxhdpi/ic_action_completed.png new file mode 100644 index 000000000..7fbfbfbd5 Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_completed.png differ diff --git a/res/drawable-xxhdpi/ic_action_download.png b/res/drawable-xxhdpi/ic_action_download.png new file mode 100644 index 000000000..56292e091 Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_download.png differ diff --git a/res/drawable-xxhdpi/ic_action_pause.png b/res/drawable-xxhdpi/ic_action_pause.png new file mode 100644 index 000000000..c8fd376cb Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_pause.png differ diff --git a/res/drawable-xxhdpi/ic_action_start.png b/res/drawable-xxhdpi/ic_action_start.png new file mode 100644 index 000000000..6f2d568af Binary files /dev/null and b/res/drawable-xxhdpi/ic_action_start.png differ diff --git a/res/layout/download.xml b/res/layout/download.xml new file mode 100644 index 000000000..14c93e4dd --- /dev/null +++ b/res/layout/download.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/res/layout/download_item.xml b/res/layout/download_item.xml new file mode 100644 index 000000000..2c4ca99c8 --- /dev/null +++ b/res/layout/download_item.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/raw/change_log b/res/raw/change_log index 81e83e974..ce991b04c 100644 --- a/res/raw/change_log +++ b/res/raw/change_log @@ -1,9 +1,11 @@ Version 0.3.0 (2014-??-??) * 完成搜索标签功能 +* 初步完成下载功能 * 修正由收藏进入漫画详情无封面显示 * 修正漫画详情无标题显示 * 修正匹配宽度 y 轴偏移错误 * 加强列表显示稳定性 +* 优化列表流畅度 * 微调界面 * 修正其他问题 diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 2bb8ad074..873864ecd 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -52,6 +52,7 @@ 已添加到收藏 + 已添加到下载列表 未找到 @@ -149,6 +150,15 @@ 上提载入下一页… 释放载入下一页… + + 开始下载任务 + 完成下载任务 + 正在下载 + 下载成功 + 下载失败 + 未启动 + 等待中 + 最后一页! 未完成的功能 @@ -169,6 +179,7 @@ 首页 收藏 + 下载 2 星 3 星 diff --git a/res/values/array.xml b/res/values/array.xml index 372cd0a83..409f70435 100644 --- a/res/values/array.xml +++ b/res/values/array.xml @@ -5,6 +5,7 @@ @string/homepage @string/favourite @android:string/search_go + @string/download diff --git a/res/values/strings.xml b/res/values/strings.xml index 6a6b4902b..b30b3fff2 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -54,6 +54,7 @@ Add to favourite + Add to download list No hits found @@ -155,6 +156,15 @@ Pull to load next page… Release to load next page… + + Start download task + Download task finished + Downloading + download successfully + download unsuccessfully + Not started + Waiting + Last page ! Sad Panda @@ -176,6 +186,7 @@ Homepage Favourite + Download 2 stars 3 stars diff --git a/src/com/hippo/ehviewer/CrashApplication.java b/src/com/hippo/ehviewer/CrashApplication.java index 430864351..b60f7877b 100644 --- a/src/com/hippo/ehviewer/CrashApplication.java +++ b/src/com/hippo/ehviewer/CrashApplication.java @@ -5,12 +5,14 @@ import java.lang.Thread.UncaughtExceptionHandler; import com.hippo.ehviewer.util.Cache; import com.hippo.ehviewer.util.Config; import com.hippo.ehviewer.util.Crash; +import com.hippo.ehviewer.util.Download; import com.hippo.ehviewer.util.EhClient; import com.hippo.ehviewer.util.Favourite; import com.hippo.ehviewer.util.Tag; import com.hippo.ehviewer.util.Ui; import android.app.Application; +import android.util.Log; public class CrashApplication extends Application implements UncaughtExceptionHandler { @@ -31,6 +33,7 @@ public class CrashApplication extends Application implements UncaughtExceptionHa Crash.init(this); BeautifyScreen.init(this); EhClient.init(this); + Download.init(this); mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); diff --git a/src/com/hippo/ehviewer/DownloadInfo.java b/src/com/hippo/ehviewer/DownloadInfo.java new file mode 100644 index 000000000..8cb40c36d --- /dev/null +++ b/src/com/hippo/ehviewer/DownloadInfo.java @@ -0,0 +1,27 @@ +package com.hippo.ehviewer; + +public class DownloadInfo { + public static final int STOP = 0x0; + public static final int DOWNLOADING = 0x1; + public static final int WAITING = 0x2; + public static final int COMPLETED = 0x3; + public static final int FAILED = 0x4; + + public static final boolean DETAIL_URL = false; + public static final boolean PAGE_URL = true; + + public String gid; + public String thumb; + public String title; + public int status = STOP; + public boolean type; + + public String detailUrlStr; + + public int pageSum = 0; + public int lastStartIndex = 1; + public String pageUrlStr; + + public float totalSize; + public float downloadSize; +} diff --git a/src/com/hippo/ehviewer/activity/DownloadActivity.java b/src/com/hippo/ehviewer/activity/DownloadActivity.java new file mode 100644 index 000000000..2efbfce71 --- /dev/null +++ b/src/com/hippo/ehviewer/activity/DownloadActivity.java @@ -0,0 +1,324 @@ +package com.hippo.ehviewer.activity; + +import java.util.List; + +import com.hippo.ehviewer.BeautifyScreen; +import com.hippo.ehviewer.DownloadInfo; +import com.hippo.ehviewer.R; +import com.hippo.ehviewer.service.DownloadService; +import com.hippo.ehviewer.service.DownloadServiceConnection; +import com.hippo.ehviewer.util.Cache; +import com.hippo.ehviewer.util.Config; +import com.hippo.ehviewer.util.Download; +import com.hippo.ehviewer.view.OlImageView; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.content.res.Configuration; +import android.os.Build; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; + +public class DownloadActivity extends Activity { + + private static final String TAG = "com.hippo.ehviewer.service.UPDATE"; + private static final String ACTION_UPDATE = "com.hippo.ehviewer.service.UPDATE"; + + private DownloadServiceConnection mServiceConn = new DownloadServiceConnection(); + + private List mDownloadInfos; + private DlAdapter mDlAdapter; + + private class DlAdapter extends BaseAdapter { + private LayoutInflater mInflater; + // TODO clean map sometimes + private SparseArray map; + + class Data { + public int status; + public boolean type; + public int lastStartIndex; + public float downloadSize; + + public Data(int status, boolean type, int lastStartIndex, float downloadSize) { + this.status = status; + this.type = type; + this.lastStartIndex = lastStartIndex; + this.downloadSize = downloadSize; + } + } + + public DlAdapter() { + mInflater = LayoutInflater.from(DownloadActivity.this); + map = new SparseArray(); + } + + @Override + public int getCount() { + return mDownloadInfos.size(); + } + + @Override + public Object getItem(int arg0) { + return mDownloadInfos.get(arg0); + } + + @Override + public long getItemId(int position) { + return 0; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + DownloadInfo di= mDownloadInfos.get(position); + Data data; + int oldId; + int newId; + if (convertView != null && (data = map.get((oldId = convertView.getId()))) != null) { + if (oldId != (newId = Integer.parseInt(di.gid))) { + convertView.setId(newId); + + OlImageView thumb = (OlImageView)convertView + .findViewById(R.id.thumb); + thumb.setUrl(di.thumb); + thumb.setKey(String.valueOf(di.gid)); + thumb.setCache(Cache.memoryCache, Cache.cpCache); + thumb.loadImage(true); + + TextView title = (TextView)convertView.findViewById(R.id.title); + title.setText(di.title); + } + if (data.status != di.status) { + data.status = di.status; + data.type = di.type; + data.lastStartIndex = di.lastStartIndex; + + setDownloadInfo(convertView, di, position); + } else if (di.status == DownloadInfo.DOWNLOADING && + (data.type != di.type + || data.lastStartIndex != di.lastStartIndex + || data.downloadSize != di.downloadSize)) { + data.type = di.type; + data.lastStartIndex = di.lastStartIndex; + + ProgressBar pb = (ProgressBar)convertView.findViewById(R.id.progressBar); + TextView info = (TextView)convertView.findViewById(R.id.info); + + if (di.type == DownloadInfo.DETAIL_URL) { + pb.setIndeterminate(true); + info.setText(R.string.downloading); + } else { + pb.setIndeterminate(false); + pb.setMax(di.pageSum); + pb.setProgress(di.lastStartIndex-1); + StringBuilder sb = new StringBuilder(getString(R.string.downloading)); + sb.append(" ").append(di.lastStartIndex-1).append(" / ").append(di.pageSum).append("\n"); + if (di.totalSize != 0) + sb.append(String.format("%.2f", di.downloadSize)) + .append(" / ").append(String.format("%.2f", di.totalSize)).append(" KB"); + info.setText(sb.toString()); + } + } + return convertView; + } + + convertView = mInflater.inflate(R.layout.download_item, null); + + OlImageView thumb = (OlImageView)convertView + .findViewById(R.id.thumb); + thumb.setUrl(di.thumb); + thumb.setKey(String.valueOf(di.gid)); + thumb.setCache(Cache.memoryCache, Cache.cpCache); + thumb.loadImage(true); + + TextView title = (TextView)convertView.findViewById(R.id.title); + title.setText(di.title); + + setDownloadInfo(convertView, di, position); + + convertView.setId(Integer.parseInt(di.gid)); + map.put(convertView.getId(), + new Data(di.status, di.type, di.lastStartIndex, di.downloadSize)); + return convertView; + } + + /** + * For clickable button, when click change message to "Please wait", then when action over change message + * + * @param view + * @param di + * @param position + */ + private void setDownloadInfo(View view, final DownloadInfo di, final int position) { + final ProgressBar pb = (ProgressBar)view.findViewById(R.id.progressBar); + final TextView info = (TextView)view.findViewById(R.id.info); + final ImageView action = (ImageView)view.findViewById(R.id.action); + + if (di.status == DownloadInfo.STOP) { + pb.setVisibility(View.GONE); + String meg = getString(R.string.not_started) + (di.type == DownloadInfo.DETAIL_URL ? "" + : (" " + (di.lastStartIndex-1) + " / " + di.pageSum)); + info.setText(meg); + action.setImageResource(R.drawable.ic_action_start); + action.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + pb.setVisibility(View.GONE); + info.setText(R.string.wait); + action.setClickable(false); + + Intent it = new Intent(DownloadActivity.this, DownloadService.class); + startService(it); + mServiceConn.getService().add(Download.get(position)); + } + }); + } else if (di.status == DownloadInfo.DOWNLOADING) { + pb.setVisibility(View.VISIBLE); + if (di.type == DownloadInfo.DETAIL_URL) { + pb.setIndeterminate(true); + info.setText(R.string.downloading); + } else { + pb.setIndeterminate(false); + pb.setMax(di.pageSum); + pb.setProgress(di.lastStartIndex-1); + StringBuilder sb = new StringBuilder(getString(R.string.downloading)); + sb.append(" ").append(di.lastStartIndex-1).append(" / ").append(di.pageSum).append("\n"); + if (di.totalSize != 0) + sb.append(String.format("%.2f", di.downloadSize)) + .append(" / ").append(String.format("%.2f", di.totalSize)).append(" KB"); + info.setText(sb.toString()); + } + action.setImageResource(R.drawable.ic_action_pause); + action.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + pb.setVisibility(View.GONE); + info.setText(R.string.wait); + action.setClickable(false); + + mServiceConn.getService().cancel(Download.get(position).gid); + } + }); + } else if (di.status == DownloadInfo.WAITING) { + pb.setVisibility(View.GONE); + info.setText(R.string.waiting); + action.setImageResource(R.drawable.ic_action_pause); + action.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + pb.setVisibility(View.GONE); + info.setText(R.string.wait); + action.setClickable(false); + + mServiceConn.getService().cancel(Download.get(position).gid); + } + }); + } else if (di.status == DownloadInfo.COMPLETED) { + pb.setVisibility(View.GONE); + info.setText(R.string.download_successfully); + action.setImageResource(R.drawable.ic_action_completed); + action.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(DownloadActivity.this, + MangaDownloadActivity.class); + intent.putExtra("title", di.title); + startActivity(intent); + } + }); + } else if (di.status == DownloadInfo.FAILED) { + pb.setVisibility(View.GONE); + String meg = getString(R.string.download_unsuccessfully) + (di.type == DownloadInfo.DETAIL_URL ? "" + : (" " + (di.lastStartIndex-1) + " / " + di.pageSum)); + info.setText(meg); + action.setImageResource(R.drawable.ic_action_start); + action.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + pb.setVisibility(View.GONE); + info.setText(R.string.wait); + action.setClickable(false); + + Intent it = new Intent(DownloadActivity.this, DownloadService.class); + startService(it); + mServiceConn.getService().add(Download.get(position)); + } + }); + } + } + } + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (Build.VERSION.SDK_INT >= 19) { + BeautifyScreen.fixColour(this); + } + } + + @Override + protected void onResume() { + super.onResume(); + int screenOri = Config.getScreenOriMode(); + if (screenOri != getRequestedOrientation()) + setRequestedOrientation(screenOri); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + unregisterReceiver(mReceiver); + unbindService(mServiceConn); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.download); + + int screenOri = Config.getScreenOriMode(); + if (screenOri != getRequestedOrientation()) + setRequestedOrientation(screenOri); + + // Download service + Intent it = new Intent(this, DownloadService.class); + bindService(it, mServiceConn, BIND_AUTO_CREATE); + + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_UPDATE); + registerReceiver(mReceiver, filter); + + // For colourfy the activity + if (Build.VERSION.SDK_INT >= 19) { + BeautifyScreen.ColourfyScreen(this); + } + + mDownloadInfos = Download.getDownloadInfoList(); + + ListView listView = (ListView)findViewById(R.id.download); + mDlAdapter = new DlAdapter(); + listView.setAdapter(mDlAdapter); + } + + private BroadcastReceiver mReceiver = new BroadcastReceiver(){ + @Override + public void onReceive(Context context, Intent intent) { + if(intent.getAction().equals(ACTION_UPDATE)) + mDlAdapter.notifyDataSetChanged(); + } + }; +} diff --git a/src/com/hippo/ehviewer/activity/FavouriteActivity.java b/src/com/hippo/ehviewer/activity/FavouriteActivity.java index ac7d7ea0b..808fca247 100644 --- a/src/com/hippo/ehviewer/activity/FavouriteActivity.java +++ b/src/com/hippo/ehviewer/activity/FavouriteActivity.java @@ -100,33 +100,29 @@ public class FavouriteActivity extends Activity{ @Override public View getView(int position, View convertView, ViewGroup parent) { ListMangaDetail lmd= mFavouriteLmd.get(position); + if (convertView == null) + convertView = mInflater.inflate(R.layout.list_item, null); - if (convertView != null) { - OlImageView cover = (OlImageView)convertView.findViewById(R.id.cover); - if (cover.getUrl().equals(lmd.thumb)) - return convertView; + OlImageView thumb = (OlImageView)convertView.findViewById(R.id.cover); + if (!lmd.gid.equals(thumb.getKey())) { + thumb.setUrl(lmd.thumb); + thumb.setKey(lmd.gid); + thumb.setCache(Cache.memoryCache, Cache.cpCache); + thumb.loadFromCache(); + + // Set manga name + TextView name = (TextView) convertView.findViewById(R.id.name); + name.setText(lmd.title); + + // Set Tpye + ImageView type = (ImageView) convertView.findViewById(R.id.type); + Ui.setType(type, lmd.category); + + // Add star + LinearLayout rate = (LinearLayout) convertView + .findViewById(R.id.rate); + Ui.addStar(rate, lmd.rating); } - - // View is different - convertView = mInflater.inflate(R.layout.list_item, null); - - OlImageView cover = (OlImageView) convertView - .findViewById(R.id.cover); - cover.setUrl(lmd.thumb); - cover.setKey(lmd.gid); - cover.setCache(Cache.memoryCache, Cache.cpCache); - cover.loadImage(false); - - TextView name = (TextView) convertView.findViewById(R.id.name); - name.setText(lmd.title); - - ImageView type = (ImageView) convertView.findViewById(R.id.type); - Ui.setType(type, lmd.category); - - LinearLayout rate = (LinearLayout) convertView - .findViewById(R.id.rate); - Ui.addStar(rate, lmd.rating); - return convertView; } } diff --git a/src/com/hippo/ehviewer/activity/MangaDownloadActivity.java b/src/com/hippo/ehviewer/activity/MangaDownloadActivity.java new file mode 100644 index 000000000..50e5913d2 --- /dev/null +++ b/src/com/hippo/ehviewer/activity/MangaDownloadActivity.java @@ -0,0 +1,152 @@ +package com.hippo.ehviewer.activity; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; + +import com.hippo.ehviewer.util.Config; +import com.hippo.ehviewer.util.Util; +import com.hippo.ehviewer.view.MangaImage; +import com.hippo.ehviewer.view.MangaViewPager; + +import android.R.color; +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.support.v4.view.PagerAdapter; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +public class MangaDownloadActivity extends Activity { + private static final String TAG = "MangaDownloadActivity"; + private MangaViewPager pageView; + private File dir; + private ArrayList fileList; + + class ImageLoadPackage { + public MangaImage mMangaImage; + public Bitmap mBitmap; + + public ImageLoadPackage(MangaImage mangaImage, Bitmap bitmap) { + mMangaImage = mangaImage; + mBitmap = bitmap; + } + } + + + + @SuppressLint("NewApi") + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + int screenOri = Config.getScreenOriMode(); + if (screenOri != getRequestedOrientation()) + setRequestedOrientation(screenOri); + + getActionBar().hide(); + // For API < 16 Fullscreen + if (Build.VERSION.SDK_INT < 19) { + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + Intent intent = getIntent(); + String title = intent.getStringExtra("title"); + if (title == null) { + finish(); + return; + } + dir = new File(Environment.getExternalStorageDirectory() + "/EhViewer/download/", title); + String[] files; + if (!dir.isDirectory() || (files = dir.list()) == null) { + finish(); + return; + } + fileList = new ArrayList(); + for (String fileName : files) { + String name = Util.getName(fileName); + if (Util.isNumber(name)) { + Log.d(TAG, fileName); + fileList.add(fileName); + } + } + // TODO do it you self + Collections.sort(fileList); + + pageView = new MangaViewPager(this); + pageView.setBackgroundColor(color.darker_gray); + // For fullscreen + if (Build.VERSION.SDK_INT >= 19) { + pageView.setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); + } + pageView.setAdapter(new PagerAdapter() { + @Override + public void destroyItem(ViewGroup container, int position, Object view) { + container.removeView((View)view); + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + final String imageName = fileList.get(position); + MangaImage oiv = new MangaImage(MangaDownloadActivity.this); + Bitmap bitmap = BitmapFactory.decodeFile(dir.toString() + "/" + imageName); + oiv.setImageBitmap(bitmap); + //oiv.enableZoomMove(true); + container.addView(oiv); + return oiv; + } + + @Override + public int getCount() { + return fileList.size(); + } + + @Override + public boolean isViewFromObject(View arg0, Object arg1) { + return arg0==arg1; + } + }); + + setContentView(pageView); + } + + @Override + protected void onResume() { + super.onResume(); + int screenOri = Config.getScreenOriMode(); + if (screenOri != getRequestedOrientation()) + setRequestedOrientation(screenOri); + } + + @SuppressLint("NewApi") + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (Build.VERSION.SDK_INT >= 19 && hasFocus && pageView != null) { + pageView.setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);} + } +} diff --git a/src/com/hippo/ehviewer/activity/MangaListActivity.java b/src/com/hippo/ehviewer/activity/MangaListActivity.java index dce4f3bb6..64eb542f6 100644 --- a/src/com/hippo/ehviewer/activity/MangaListActivity.java +++ b/src/com/hippo/ehviewer/activity/MangaListActivity.java @@ -14,6 +14,8 @@ import com.hippo.ehviewer.ListUrls; import com.hippo.ehviewer.R; import com.hippo.ehviewer.dialog.DialogBuilder; import com.hippo.ehviewer.dialog.SuperDialogUtil; +import com.hippo.ehviewer.service.DownloadService; +import com.hippo.ehviewer.service.DownloadServiceConnection; import com.hippo.ehviewer.util.Cache; import com.hippo.ehviewer.util.Config; import com.hippo.ehviewer.util.Crash; @@ -32,12 +34,15 @@ import com.jeremyfeinstein.slidingmenu.lib.app.SlidingActivity; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.IBinder; import android.R.color; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.SearchManager; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.ServiceConnection; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Color; @@ -134,6 +139,8 @@ public class MangaListActivity extends SlidingActivity { private int lastIndex = 1; private int visiblePage = 0; + private DownloadServiceConnection mServiceConn = new DownloadServiceConnection(); + private AlertDialog createCheckLoginDialog() { LayoutInflater inflater = this.getLayoutInflater(); View view = inflater.inflate(R.layout.wait, null); @@ -434,9 +441,10 @@ public class MangaListActivity extends SlidingActivity { @Override public void onItemClick(AdapterView arg0, View arg1, int position, long arg3) { + ListMangaDetail lmd; switch (position) { case 0: // Add favourite item - ListMangaDetail lmd = lmdArray.get(longClickItemIndex); + lmd = lmdArray.get(longClickItemIndex); Favourite.push(lmd); Toast.makeText(MangaListActivity.this, getString(R.string.toast_add_favourite), @@ -444,9 +452,14 @@ public class MangaListActivity extends SlidingActivity { break; case 1: // TODO + lmd = lmdArray.get(longClickItemIndex); + Intent it = new Intent(MangaListActivity.this, DownloadService.class); + startService(it); + mServiceConn.getService().add(lmd.gid, lmd.thumb, + EhClient.detailHeader + lmd.gid + "/" + lmd.token, lmd.title); Toast.makeText(MangaListActivity.this, - getString(R.string.unfinished), Toast.LENGTH_SHORT) - .show(); + getString(R.string.toast_add_download), + Toast.LENGTH_SHORT).show(); break; default: break; @@ -1099,37 +1112,30 @@ public class MangaListActivity extends SlidingActivity { @Override public View getView(int position, View convertView, ViewGroup parent) { - // Check is the item is the same ListMangaDetail lmd= lmdArray.get(position); - if (convertView != null) { - OlImageView cover = (OlImageView)convertView.findViewById(R.id.cover); - if (cover.getUrl().equals(lmd.thumb)) - return convertView; - } + if (convertView == null) + convertView = mInflater.inflate(R.layout.list_item, null); - convertView = mInflater.inflate(R.layout.list_item, null); + OlImageView thumb = (OlImageView)convertView.findViewById(R.id.cover); + if (!lmd.gid.equals(thumb.getKey())) { + thumb.setUrl(lmd.thumb); + thumb.setKey(lmd.gid); + thumb.setCache(Cache.memoryCache, Cache.cpCache); + thumb.loadFromCache(); - // Set cover url - OlImageView cover = (OlImageView) convertView - .findViewById(R.id.cover); - cover.setUrl(lmdArray.get(position).thumb); - cover.setKey(lmdArray.get(position).gid); - cover.setCache(Cache.memoryCache, Cache.cpCache); - cover.loadFromCache(); + // Set manga name + TextView name = (TextView) convertView.findViewById(R.id.name); + name.setText(lmd.title); - // Set manga name - TextView name = (TextView) convertView.findViewById(R.id.name); - name.setText(lmdArray.get(position).title); - - // Set Tpye - ImageView type = (ImageView) convertView.findViewById(R.id.type); - Ui.setType(type, lmdArray.get(position).category); - - // Add star - LinearLayout rate = (LinearLayout) convertView - .findViewById(R.id.rate); - Ui.addStar(rate, lmdArray.get(position).rating); + // Set Tpye + ImageView type = (ImageView) convertView.findViewById(R.id.type); + Ui.setType(type, lmd.category); + // Add star + LinearLayout rate = (LinearLayout) convertView + .findViewById(R.id.rate); + Ui.addStar(rate, lmd.rating); + } return convertView; } } @@ -1169,6 +1175,10 @@ public class MangaListActivity extends SlidingActivity { if (screenOri != getRequestedOrientation()) setRequestedOrientation(screenOri); + // Download service + Intent it = new Intent(MangaListActivity.this, DownloadService.class); + bindService(it, mServiceConn, BIND_AUTO_CREATE); + // Get url Intent intent = getIntent(); int type = intent.getIntExtra("type", ListUrls.ALL_TYPE); @@ -1246,7 +1256,12 @@ public class MangaListActivity extends SlidingActivity { showContent(); } else if (position == 2) { // filter filterDialog.show(); - } else { + } else if (position == 3) { // Download //TODO + Intent intent = new Intent(MangaListActivity.this, + DownloadActivity.class); + startActivity(intent); + showContent(); + } else if (position >= mStableItemCount){ ListUrls listUrls = Tag.get(listMenuTitle.get(position)); if (listUrls != null) { lus = listUrls; @@ -1500,10 +1515,11 @@ public class MangaListActivity extends SlidingActivity { @Override protected void onDestroy() { + super.onDestroy(); + unbindService(mServiceConn); if (Config.isAutoPageCache()) { Cache.pageCache.clear(); } - super.onDestroy(); } private void layout() { // First time diff --git a/src/com/hippo/ehviewer/network/Downloader.java b/src/com/hippo/ehviewer/network/Downloader.java new file mode 100644 index 000000000..497582372 --- /dev/null +++ b/src/com/hippo/ehviewer/network/Downloader.java @@ -0,0 +1,270 @@ +package com.hippo.ehviewer.network; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + +import android.util.Log; + +import com.hippo.ehviewer.DownloadInfo; +import com.hippo.ehviewer.util.Cache; +import com.hippo.ehviewer.util.Util; + +public class Downloader implements Runnable { + private static final String TAG = "Downloader"; + + public static final int HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; + public static final int HTTP_TEMP_REDIRECT = 307; + public static final int COMPLETED = 0; + public static final int STOP = -1; + public static final int NO_SDCARD = -2; + public static final int STATUS_HTTP_DATA_ERROR = -3; + public static final int STATUS_TOO_MANY_REDIRECTS = -4; + public static final int STATUS_FILE_ERROR = -5; + + private static final int BUFFER_SIZE = 4096; + + private static final int MAX_REDIRECTS = 5; + private static final int MAX_RETRY = 5; + private static final int DEFAULT_TIMEOUT = 20 * 1000; + + private String mPath; + private String mFileName; + private URL mUrl; + private DownloadInfo mDi; + + private int mTotalSize; + private int mDownloadSize = 0; + private int mRedirectionCount = 0; + + private int status; + private OnDownloadListener mListener; + + public interface OnDownloadListener { + public void onDownloadStart(int totalSize); + public void onDownloadStatusUpdate(int downloadSize, int totalSize); + } + + public void resetData(String path, String fileName, String urlStr, DownloadInfo di) throws MalformedURLException { + mPath = path; + mFileName = fileName; + mUrl = new URL(urlStr); + mDi = di; + + mDownloadSize = 0; + mRedirectionCount = 0; + status = COMPLETED; + } + + public void setOnDownloadListener(OnDownloadListener listener) { + mListener = listener; + } + + public Downloader(){} + + public Downloader(String path, String fileName, String urlStr, DownloadInfo di) throws MalformedURLException { + mPath = path; + mFileName = fileName; + mUrl = new URL(urlStr); + mDi = di; + } + + @Override + public void run() { + int retryTimes = 0; + if (Cache.hasSdCard()) + while(true) { + try { + mDownloadSize = 0; + mRedirectionCount = 0; + status = COMPLETED; + executeDownload(); + break; + } catch (StopRequestException e) { + e.printStackTrace(); + status = e.getFinalStatus(); + if (status == STOP || retryTimes > MAX_RETRY) + break; + retryTimes++; + } + } + else + status = NO_SDCARD; + } + + public int getStatus() { + return status; + } + + private void executeDownload() throws StopRequestException { + while (mRedirectionCount++ < MAX_REDIRECTS) { + HttpURLConnection conn = null; + try { + Log.d(TAG, "Get file " + mUrl.toString()); + conn = (HttpURLConnection)mUrl.openConnection(); + conn.setInstanceFollowRedirects(false); + conn.setConnectTimeout(DEFAULT_TIMEOUT); + conn.setReadTimeout(DEFAULT_TIMEOUT); + + final int responseCode = conn.getResponseCode(); + switch (responseCode) { + case HttpURLConnection.HTTP_OK: + processResponseHeaders(conn); + if (mListener != null) + mListener.onDownloadStart(mTotalSize); + transferData(conn); + return; + + case HttpURLConnection.HTTP_PARTIAL: + transferData(conn); + return; + + case HttpURLConnection.HTTP_MOVED_PERM: + case HttpURLConnection.HTTP_MOVED_TEMP: + case HttpURLConnection.HTTP_SEE_OTHER: + case HTTP_TEMP_REDIRECT: + final String location = conn.getHeaderField("Location"); + mUrl = new URL(mUrl, location); + continue; + + default: + StopRequestException.throwUnhandledHttpError( + responseCode, conn.getResponseMessage()); + } + } catch (IOException e) { + // Trouble with low-level sockets + throw new StopRequestException(STATUS_HTTP_DATA_ERROR, e); + + } finally { + if (conn != null) conn.disconnect(); + } + } + + throw new StopRequestException(STATUS_TOO_MANY_REDIRECTS, "Too many redirects"); + } + + /** + * Get Response Headers Info + * + * @param conn + */ + private void processResponseHeaders(HttpURLConnection conn) { + mTotalSize = conn.getContentLength(); + } + + /** + * Transfer data from the given connection to the destination file. + */ + private void transferData(HttpURLConnection conn) throws StopRequestException { + InputStream in = null; + OutputStream out = null; + File file = null; + try { + try { + in = conn.getInputStream(); + } catch (IOException e) { + throw new StopRequestException(STATUS_HTTP_DATA_ERROR, e); + } + + try { + file = new File(mPath, mFileName); + out = new FileOutputStream(file); + } catch (IOException e) { + throw new StopRequestException(STATUS_FILE_ERROR, e); + } + + // Start streaming data, periodically watch for pause/cancel + // commands and checking disk space as needed. + transferData(in, out); + } finally { + Util.closeStreamQuietly(in); + try { + if (out != null) out.flush(); + } catch (IOException e) { + } finally { + Util.closeStreamQuietly(out); + } + } + } + + /** + * Transfer as much data as possible from the HTTP response to the + * destination file. + */ + private void transferData(InputStream in, OutputStream out) + throws StopRequestException { + final byte data[] = new byte[BUFFER_SIZE]; + for (;;) { + int bytesRead = readFromResponse(data, in); + if (bytesRead == -1) { // success, end of stream already reached + handleEndOfStream(); + return; + } + + writeDataToDestination(data, bytesRead, out); + mDownloadSize += bytesRead; + if (mListener != null) + mListener.onDownloadStatusUpdate(mDownloadSize, mTotalSize); + + if (mDi.status == mDi.STOP) + throw new StopRequestException(STOP, + "Download is stopped"); + } + } + + /** + * Read some data from the HTTP response stream, handling I/O errors. + * @param data buffer to use to read data + * @param entityStream stream for reading the HTTP response entity + * @return the number of bytes actually read or -1 if the end of the stream has been reached + */ + private int readFromResponse(byte[] data, InputStream entityStream) + throws StopRequestException { + try { + return entityStream.read(data); + } catch (IOException ex) { + // TODO: handle stream errors the same as other retries + if ("unexpected end of stream".equals(ex.getMessage())) { + return -1; + } + throw new StopRequestException(STATUS_HTTP_DATA_ERROR, + "Failed reading response: " + ex, ex); + } + } + + /** + * Write a data buffer to the destination file. + * @param data buffer containing the data to write + * @param bytesRead how many bytes to write from the buffer + */ + private void writeDataToDestination(byte[] data, int bytesRead, OutputStream out) + throws StopRequestException { + try { + out.write(data, 0, bytesRead); + return; + } catch (IOException ex) { + // TODO: better differentiate between DRM and disk failures + // TODO: check disk is full + throw new StopRequestException(STATUS_FILE_ERROR, + "Failed to write data: " + ex); + } + } + + /** + * Called when we've reached the end of the HTTP response stream, to update the database and + * check for consistency. + */ + private void handleEndOfStream() throws StopRequestException { + final boolean lengthMismatched = (mTotalSize != -1) + && (mDownloadSize != mTotalSize); + if (lengthMismatched) { + throw new StopRequestException(STATUS_HTTP_DATA_ERROR, + "mismatched content length; unable to resume"); + } + } +} diff --git a/src/com/hippo/ehviewer/network/StopRequestException.java b/src/com/hippo/ehviewer/network/StopRequestException.java new file mode 100644 index 000000000..85299a64d --- /dev/null +++ b/src/com/hippo/ehviewer/network/StopRequestException.java @@ -0,0 +1,31 @@ +package com.hippo.ehviewer.network; + +class StopRequestException extends Exception { + + private final int mFinalStatus; + + public StopRequestException(int finalStatus, String message) { + super(message); + mFinalStatus = finalStatus; + } + + public StopRequestException(int finalStatus, Throwable t) { + super(t); + mFinalStatus = finalStatus; + } + + public StopRequestException(int finalStatus, String message, Throwable t) { + super(message, t); + mFinalStatus = finalStatus; + } + + public int getFinalStatus() { + return mFinalStatus; + } + + public static StopRequestException throwUnhandledHttpError(int code, String message) + throws StopRequestException { + final String error = "Unhandled HTTP response: " + code + " " + message; + throw new StopRequestException(code, error); + } +} diff --git a/src/com/hippo/ehviewer/service/DownloadService.java b/src/com/hippo/ehviewer/service/DownloadService.java new file mode 100644 index 000000000..99a27d670 --- /dev/null +++ b/src/com/hippo/ehviewer/service/DownloadService.java @@ -0,0 +1,207 @@ +package com.hippo.ehviewer.service; + +import java.util.HashMap; +import java.util.Map; + +import com.hippo.ehviewer.DownloadInfo; +import com.hippo.ehviewer.R; +import com.hippo.ehviewer.activity.DownloadActivity; +import com.hippo.ehviewer.util.Download; +import com.hippo.ehviewer.util.EhClient; + +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; +import android.support.v4.app.NotificationCompat; +import android.util.Log; + +public class DownloadService extends Service { + private static final int DOWNLOAD_NOTIFY_ID = -1; + private static final String TAG = "DownloadService"; + private static final String ACTION_UPDATE = "com.hippo.ehviewer.service.UPDATE"; + + private ServiceBinder mBinder = null; + + private NotificationManager mNotifyManager; + private NotificationCompat.Builder mBuilder; + + @Override + public void onCreate() { + super.onCreate(); + + Log.d(TAG, "Service onCreate"); + + mBinder = new ServiceBinder(); + mNotifyManager = (NotificationManager) + getSystemService(Context.NOTIFICATION_SERVICE); + mBuilder = new NotificationCompat.Builder(this); + Intent resultIntent = new Intent(this, DownloadActivity.class); + resultIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + PendingIntent resultPendingIntent = + PendingIntent.getActivity( + this, + 0, + resultIntent, + PendingIntent.FLAG_UPDATE_CURRENT + ); + mBuilder.setSmallIcon(R.drawable.ic_launcher).setContentIntent(resultPendingIntent); + + EhClient.DownloadMangaManager.setDownloadService(this); + EhClient.DownloadMangaManager.setOnDownloadMangaListener(new EhClient.OnDownloadMangaListener() { + @Override + public void onDownloadMangaAllStart() { + mBuilder.setContentTitle(getString(R.string.start_download_task)) + .setContentText(null) + .setProgress(0, 0, true).setOngoing(true); + mNotifyManager.notify(DOWNLOAD_NOTIFY_ID, mBuilder.build()); + } + + @Override + public void onDownloadMangaAllOver() { + mNotifyManager.cancel(DOWNLOAD_NOTIFY_ID); + stopSelf(); + } + + @Override + public void onDownloadMangaStart(String id) { + mBuilder.setContentTitle(getString(R.string.downloading) + + " " + Download.get(id).title) + .setContentText(null) + .setProgress(0, 0, true).setOngoing(true); + mNotifyManager.notify(DOWNLOAD_NOTIFY_ID, mBuilder.build()); + } + + @Override + public void onDownloadMangaStart(String id, int pageSum, int startIndex) { + mBuilder.setContentTitle(getString(R.string.downloading) + + " " + Download.get(id).title) + .setContentText(startIndex + " / " + pageSum) + .setProgress(pageSum, startIndex, false).setOngoing(true); + mNotifyManager.notify(DOWNLOAD_NOTIFY_ID, mBuilder.build()); + } + + @Override + public void onDownloadMangaStop(String id) { + // TODO Auto-generated method stub + + } + + @Override + public void onDownloadMangaOver(String id, boolean ok) { + if (ok) + mBuilder.setContentTitle(getString(R.string.download_successfully) + " " + Download.get(id).title); + else + mBuilder.setContentTitle(getString(R.string.download_unsuccessfully) + " " + Download.get(id).title); + mBuilder.setContentText(null).setProgress(0, 0, false).setOngoing(false); + mNotifyManager.notify(Integer.parseInt(id), mBuilder.build()); + } + + @Override + public void onDownloadPage(String id, int pageSum, int index) { + mBuilder.setContentTitle(getString(R.string.downloading) + + " " + Download.get(id).title) + .setContentText(index + " / " + pageSum) + .setProgress(pageSum, index, false).setOngoing(true); + mNotifyManager.notify(DOWNLOAD_NOTIFY_ID, mBuilder.build()); + } + + @Override + public void onDownloadPageProgress(String id, int pageSum, + int index, float totalSize, float downloadSize) { + // TODO Auto-generated method stub + + } + }); + + stopForeground(true); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.d(TAG, "Service onStartCommand"); + + return START_NOT_STICKY; + } + + @Override + public IBinder onBind(Intent intent) { + Log.d(TAG, "Service onBind"); + + return mBinder; + } + + @Override + public void onDestroy() { + super.onDestroy(); + + Log.d(TAG, "Service onDestroy"); + mNotifyManager.cancel(DOWNLOAD_NOTIFY_ID); + + mBinder = null; + mNotifyManager = null; + mBuilder = null; + } + + public void add(String gid, String thumb, String detailUrlStr, String title) { + DownloadInfo di = Download.get(gid); + if (di == null) { + di = new DownloadInfo(); + di.status = DownloadInfo.STOP; + di.gid = gid; + di.thumb = thumb; + di.title = title; + di.type = DownloadInfo.DETAIL_URL; + di.detailUrlStr = detailUrlStr; + Download.add(String.valueOf(gid), di); + notifyUpdate(); + } + add(di); + } + + public void add(String gid, String thumb, String detailUrlStr, + String pageUrlStr, int pageSum, int lastStartIndex, String title) { + DownloadInfo di = Download.get(gid); + if (di == null) { + di = new DownloadInfo(); + di.status = DownloadInfo.STOP; + di.gid = gid; + di.thumb = thumb; + di.title = title; + di.type = DownloadInfo.PAGE_URL; + di.detailUrlStr = detailUrlStr; + di.pageUrlStr = pageUrlStr; + di.pageSum = pageSum; + di.lastStartIndex = lastStartIndex; + Download.add(String.valueOf(gid), di); + notifyUpdate(); + } + add(di); + } + + public void add(DownloadInfo di) { + if (di.status == DownloadInfo.DOWNLOADING + || di.status == DownloadInfo.WAITING) + return; + di.status = DownloadInfo.WAITING; + EhClient.DownloadMangaManager.add(di); + } + + public void cancel(String id) { + EhClient.DownloadMangaManager.cancel(id); + } + + public void notifyUpdate(){ + Intent it = new Intent(ACTION_UPDATE); + sendBroadcast(it); + } + + public class ServiceBinder extends Binder{ + public DownloadService getService(){ + return DownloadService.this; + } + } +} diff --git a/src/com/hippo/ehviewer/service/DownloadServiceConnection.java b/src/com/hippo/ehviewer/service/DownloadServiceConnection.java new file mode 100644 index 000000000..bc4a059da --- /dev/null +++ b/src/com/hippo/ehviewer/service/DownloadServiceConnection.java @@ -0,0 +1,25 @@ +package com.hippo.ehviewer.service; + +import android.content.ComponentName; +import android.content.ServiceConnection; +import android.os.IBinder; + +public class DownloadServiceConnection implements ServiceConnection{ + + private DownloadService mService; + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + mService = ((DownloadService.ServiceBinder)service).getService(); + + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mService = null; + } + + public DownloadService getService() { + return mService; + } +} diff --git a/src/com/hippo/ehviewer/util/Cache.java b/src/com/hippo/ehviewer/util/Cache.java index 8c98f66bf..c1c383497 100644 --- a/src/com/hippo/ehviewer/util/Cache.java +++ b/src/com/hippo/ehviewer/util/Cache.java @@ -15,7 +15,6 @@ public class Cache { private static Context mContext; - private static boolean mSdCard = false; public static final String cpCachePath = "/EhViewer/cache/cover"; public static final String pageCachePath = "/EhViewer/cache/page"; public static DiskCache cpCache = null; @@ -38,10 +37,8 @@ public class Cache { mInit = true; mContext = context; - mSdCard = Environment.getExternalStorageState().equals( - Environment.MEDIA_MOUNTED); - if (mSdCard) { + if (hasSdCard()) { try { int cpCacheSize = Config.getCoverDiskCacheSize() * 1024 * 1024; if (cpCacheSize <= 0) @@ -98,9 +95,7 @@ public class Cache { * @return True if has sd card */ public static boolean hasSdCard() { - if (!mInit) { - throw new IllegalStateException("Please init Cache first."); - } - return mSdCard; + return Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED); } } diff --git a/src/com/hippo/ehviewer/util/Download.java b/src/com/hippo/ehviewer/util/Download.java new file mode 100644 index 000000000..3740f696e --- /dev/null +++ b/src/com/hippo/ehviewer/util/Download.java @@ -0,0 +1,260 @@ +package com.hippo.ehviewer.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; + +import android.content.Context; +import android.content.SharedPreferences; + +import com.hippo.ehviewer.DownloadInfo; +import com.hippo.ehviewer.ListUrls; + +public class Download { + private static final String SHA_PRE_NAME = "download_info"; + private static final String LIST_ORDER = "list_order"; + + private static Context mContext; + private static SharedPreferences mDownloadInfoPre; + private static ArrayList mListOrder = new ArrayList(); + private static ArrayList mDownloadInfos = new ArrayList(); + + private static boolean mInit = false; + + /** + * Init Tag + * + * @param context Application context + */ + public static void init(Context context) { + if (mInit) + return; + mInit = true; + + mContext = context; + mDownloadInfoPre = mContext.getSharedPreferences(SHA_PRE_NAME, 0); + + getDownloadInfo(); + } + + /** + * Is init + * @return True if init + */ + public static boolean isInit() { + return mInit; + } + + private static void getDownloadInfo() { + String[] allOrder = Util.getStrings(mDownloadInfoPre, LIST_ORDER); + + if (allOrder == null) + return; + + boolean errorFlag = false; + for (String item : allOrder) { + mListOrder.add(item); + String strDownloadInfo = mDownloadInfoPre.getString(item, null); + if (strDownloadInfo == null) { + mListOrder.remove(strDownloadInfo); + errorFlag = true; + continue; + } + DownloadInfo di = decode(strDownloadInfo); + if (di.status == DownloadInfo.DOWNLOADING + || di.status == DownloadInfo.WAITING) + di.status = DownloadInfo.STOP; + + mDownloadInfos.add(di); + } + if (errorFlag) + Util.putStrings(mDownloadInfoPre, LIST_ORDER, mListOrder); + } + + /** + * Add a new tag item to the end of tag list + * + * @param key + * @param tag + * @return + */ + public static boolean add(String key, DownloadInfo di) { + // Check contain this item or not + if (mListOrder.indexOf(key) == -1) { + mListOrder.add(key); + mDownloadInfos.add(di); + Util.putStrings(mDownloadInfoPre, LIST_ORDER, mListOrder); + mDownloadInfoPre.edit().putString(key, encode(di)).apply(); + return true; + } else + return false; + } + + /** + * Swap tag list order + * + * @param oldIndex + * @param newIndex + * @return + */ + public static boolean swap(int indexOne, int indexTwo) { + if (indexOne < 0 || indexOne > mListOrder.size() + || indexTwo < 0 || indexTwo > mListOrder.size()) + return false; + + if (indexOne == indexTwo) + return true; + + String temp1 = mListOrder.get(indexOne); + mListOrder.set(indexOne, mListOrder.get(indexTwo)); + mListOrder.set(indexTwo, temp1); + Util.putStrings(mDownloadInfoPre, LIST_ORDER, mListOrder); + + DownloadInfo temp2 = mDownloadInfos.get(indexOne); + mDownloadInfos.set(indexOne, mDownloadInfos.get(indexTwo)); + mDownloadInfos.set(indexTwo, temp2); + return true; + } + + public static boolean contains(String key) { + return mListOrder.contains(key); + } + + /** + * Remove Tag item + * + * @param index + * @return True if remove successfully + */ + public static boolean remove(String key) { + int index = mListOrder.indexOf(key); + if (index != -1) { + mListOrder.remove(index); + mDownloadInfos.remove(index); + mDownloadInfoPre.edit().remove(key).apply(); + Util.putStrings(mDownloadInfoPre, LIST_ORDER, mListOrder); + return true; + } else + return false; + } + + /** + * Remove Tag item + * + * @param index + * @return True if remove successfully + */ + public static boolean remove(int index) { + mDownloadInfos.remove(index); + String key = mListOrder.remove(index); + mDownloadInfoPre.edit().remove(key).apply(); + Util.putStrings(mDownloadInfoPre, LIST_ORDER, mListOrder); + return true; + } + + public static DownloadInfo get(String key) { + int index = mListOrder.indexOf(key); + if (index == -1) + return null; + return mDownloadInfos.get(index); + } + + /** + * You must not modify what you get + * + * @return + */ + public static ArrayList getDownloadInfoList() { + return mDownloadInfos; + } + + public static DownloadInfo get(int position) { + return mDownloadInfos.get(position); + } + + public static String getKey(int position) { + return mListOrder.get(position); + } + + public static ArrayList getKeys() { + return mListOrder; + } + + public static void notify(String key) { + int index = mListOrder.indexOf(key); + if (index != -1) { + mDownloadInfoPre.edit().putString(key, encode(mDownloadInfos.get(index))).apply(); + } + } + + protected static String encode(DownloadInfo di) { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + ObjectOutputStream outputStream = new ObjectOutputStream(os); + writeObject(di, outputStream); + } catch (Exception e) { + e.printStackTrace(); + return null; + } finally { + try { + os.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return Util.byteArrayToHexString(os.toByteArray()); + } + + protected static DownloadInfo decode(String strDi) { + byte[] bytes = Util.hexStringToByteArray(strDi); + ByteArrayInputStream is = new ByteArrayInputStream(bytes); + DownloadInfo di = null; + try { + ObjectInputStream ois = new ObjectInputStream(is); + di = readObject(ois); + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return di; + } + + public static void writeObject(DownloadInfo di, ObjectOutputStream out) throws IOException { + out.writeObject(di.gid); + out.writeObject(di.thumb); + out.writeObject(di.title); + out.writeObject((Integer)di.status); + out.writeObject((Boolean)di.type); + out.writeObject(di.detailUrlStr); + out.writeObject((Integer)di.pageSum); + out.writeObject((Integer)di.lastStartIndex); + out.writeObject(di.pageUrlStr); + } + + public static DownloadInfo readObject(ObjectInputStream in) { + DownloadInfo di = new DownloadInfo(); + try { + di.gid = (String)in.readObject(); + di.thumb = (String)in.readObject(); + di.title = (String)in.readObject(); + di.status = (Integer)in.readObject(); + di.type = (Boolean)in.readObject(); + di.detailUrlStr = (String)in.readObject(); + di.pageSum = (Integer)in.readObject(); + di.lastStartIndex = (Integer)in.readObject(); + di.pageUrlStr = (String)in.readObject(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + return di; + } +} diff --git a/src/com/hippo/ehviewer/util/EhClient.java b/src/com/hippo/ehviewer/util/EhClient.java index 46f29bb1c..853684605 100644 --- a/src/com/hippo/ehviewer/util/EhClient.java +++ b/src/com/hippo/ehviewer/util/EhClient.java @@ -5,9 +5,12 @@ import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.net.CookieHandler; import java.net.CookieManager; import java.net.CookiePolicy; @@ -33,12 +36,15 @@ import org.json.JSONException; import org.json.JSONObject; import com.hippo.ehviewer.DiskCache; +import com.hippo.ehviewer.DownloadInfo; import com.hippo.ehviewer.ListMangaDetail; import com.hippo.ehviewer.ListUrls; import com.hippo.ehviewer.MangaDetail; import com.hippo.ehviewer.PageList; import com.hippo.ehviewer.R; +import com.hippo.ehviewer.network.Downloader; import com.hippo.ehviewer.network.ShapreCookieStore; +import com.hippo.ehviewer.service.DownloadService; import android.app.NotificationManager; import android.content.Context; @@ -47,6 +53,7 @@ import android.graphics.BitmapFactory; import android.graphics.Movie; import android.net.ConnectivityManager; import android.net.NetworkInfo; +import android.os.Environment; import android.os.Handler; import android.os.Message; import android.support.v4.app.NotificationCompat; @@ -74,7 +81,7 @@ public class EhClient { private static String logoutUrl; private static final int TIMEOUT = 10 * 1000; - private static final int DOWNLOAD_RETRY_TIMES = 5; + private static final int RETRY_TIMES = 5; private static Context mContext; @@ -154,10 +161,9 @@ public class EhClient { listHeader = E_HENTAI_LIST_HEADER; detailHeader = E_HENTAI_DETAIL_HEADER; } - DownloadMangaManager.init(); } - + /** * Is init * @@ -1164,11 +1170,15 @@ public class EhClient { } - interface OnDownloadMangaListener { - public void onDownloadMangaStart(int id, int pageSum); - public void onDownloadMangaOver(int id); + public interface OnDownloadMangaListener { + public void onDownloadMangaStart(String id); + public void onDownloadMangaStart(String id, int pageSum, int startIndex); + public void onDownloadMangaStop(String id); + public void onDownloadMangaOver(String id, boolean ok); - public void onDownloadPage(int id, int index); + public void onDownloadPage(String id, int pageSum, int index); + public void onDownloadPageProgress(String id, int pageSum, + int index, float totalSize, float downloadSize); public void onDownloadMangaAllStart(); public void onDownloadMangaAllOver(); @@ -1176,30 +1186,30 @@ public class EhClient { /****** DownloadMangaManager ******/ public static class DownloadMangaManager { - private static final int INVALID_ID = -1; + public static final String DOWNLOAD_PATH = "/EhViewer/download/"; + private static final String ACTION_UPDATE = "com.hippo.ehviewer.service.DownloadService.UPDATE"; - private static int id = INVALID_ID; - private static int curDownloadId = INVALID_ID; - private static ArrayList mDownloadQueue = new ArrayList(); - - private static NotificationManager mNotifyManager; - private static NotificationCompat.Builder mBuilder; + private static DownloadInfo curDownloadInfo = null; + private static ArrayList mDownloadQueue = new ArrayList(); private static Object taskLock = new Object(); - private static OnDownloadMangaListener listener; + private static DownloadService mService; + + private static boolean mStop = false; public static void init() { - mNotifyManager = (NotificationManager)mContext - .getSystemService(Context.NOTIFICATION_SERVICE); - mBuilder = new NotificationCompat.Builder(mContext); - mBuilder.setSmallIcon(R.drawable.ic_launcher); + } public static void setOnDownloadMangaListener(OnDownloadMangaListener listener) { DownloadMangaManager.listener = listener; } + public static void setDownloadService(DownloadService service) { + DownloadMangaManager.mService = service; + } + /** * Add a download task to task queue * @@ -1207,90 +1217,283 @@ public class EhClient { * @param foldName * @return */ - public static int add(String detailUrlStr, String foldName) { - int newId = ++id; - if (newId < 0) - newId = id = 0; - mDownloadQueue.add(new DMTaskInfo(newId, detailUrlStr, foldName)); - + public static void add(DownloadInfo di) { synchronized (taskLock) { - if (curDownloadId == INVALID_ID && mDownloadQueue.size() != 0) + mDownloadQueue.add(di); + if (curDownloadInfo == null && mDownloadQueue.size() != 0) start(); } - return newId; + } + + public static void cancel(String id) { + synchronized (taskLock) { + DownloadInfo di = Download.get(id); + if (di != null) { + di.status = DownloadInfo.STOP; + mDownloadQueue.remove(di); + if (!id.equals(getCurDownloadId())) { + mService.notifyUpdate(); + Download.notify(id); + } + } + } + } + + public static String getCurDownloadId() { + synchronized (taskLock) { + if (curDownloadInfo == null) + return null; + else + return curDownloadInfo.gid; + } + } + + public static boolean isWaiting(String str) { + synchronized (taskLock) { + for (DownloadInfo di : mDownloadQueue) { + if (di.gid.equals(str)) + return true; + } + } + return false; } private static void start(){ - if(curDownloadId != INVALID_ID){ + if(curDownloadInfo != null){ return; } new Thread(new Runnable(){ @Override public void run() { - if (listener != null) - listener.onDownloadMangaAllStart(); + listener.onDownloadMangaAllStart(); + Parser parser = new Parser(); + Downloader imageDownloader = new Downloader(); + imageDownloader.setOnDownloadListener(new Downloader.OnDownloadListener() { + @Override + public void onDownloadStart(int totalSize) { + if (curDownloadInfo != null) { + curDownloadInfo.downloadSize = 0; + curDownloadInfo.totalSize = totalSize/1024.0f; + mService.notifyUpdate(); + } + } + + @Override + public void onDownloadStatusUpdate(int downloadSize, + int totalSize) { + curDownloadInfo.downloadSize = downloadSize/1024.0f; + curDownloadInfo.totalSize = totalSize/1024.0f; + mService.notifyUpdate(); + } + }); while(mDownloadQueue.size() > 0){ - DMTaskInfo ti = mDownloadQueue.get(0); - curDownloadId = ti.id; - mDownloadQueue.remove(0); - - StringBuffer sb = new StringBuffer(); - int pageSum = getFirstPageForDetail(ti.detailUrlStr, sb); - if (listener != null) - listener.onDownloadMangaStart(curDownloadId, pageSum); - + synchronized (taskLock) { + curDownloadInfo = mDownloadQueue.get(0); + curDownloadInfo.status = DownloadInfo.DOWNLOADING; + mDownloadQueue.remove(0); + } + Download.notify(String.valueOf(curDownloadInfo.gid)); + if (curDownloadInfo.type == DownloadInfo.DETAIL_URL) { + listener.onDownloadMangaStart(curDownloadInfo.gid); + mService.notifyUpdate(); + if (parser.getFirstPagePageSumForDetail(curDownloadInfo.detailUrlStr)) { // Get page info + curDownloadInfo.type = DownloadInfo.PAGE_URL; + curDownloadInfo.lastStartIndex = 1; + curDownloadInfo.pageSum = parser.getPageSum(); + curDownloadInfo.pageUrlStr = parser.getFirstPage(); + Download.notify(curDownloadInfo.gid); + + } else { // If get info error + listener.onDownloadMangaOver(curDownloadInfo.gid, false); + curDownloadInfo.status = DownloadInfo.FAILED; + mService.notifyUpdate(); + Download.notify(String.valueOf(curDownloadInfo.gid)); + continue; + } + } + //Create folder + File folder = new File(Environment.getExternalStorageDirectory() + DOWNLOAD_PATH + curDownloadInfo.title); // TODO + if (!folder.mkdirs() && !folder.isDirectory()) { + folder = new File(Environment.getExternalStorageDirectory() + DOWNLOAD_PATH + curDownloadInfo.gid); + if (!folder.mkdirs() && !folder.isDirectory()) { + listener.onDownloadMangaOver(curDownloadInfo.gid, false); + curDownloadInfo.status = DownloadInfo.FAILED; + mService.notifyUpdate(); + Download.notify(String.valueOf(curDownloadInfo.gid)); + continue; + } + } + String nextPage = curDownloadInfo.pageUrlStr; + curDownloadInfo.pageUrlStr = null; + String imageUrlStr = null; + boolean mComplete = true; + boolean mStop = false; + // Get page + curDownloadInfo.lastStartIndex--; + while (!nextPage.equals(curDownloadInfo.pageUrlStr)) { + curDownloadInfo.pageUrlStr = nextPage; + curDownloadInfo.lastStartIndex++; + Download.notify(String.valueOf(curDownloadInfo.gid)); + listener.onDownloadPage(curDownloadInfo.gid, curDownloadInfo.pageSum, curDownloadInfo.lastStartIndex-1); + mService.notifyUpdate(); + + if (parser.getPageInfoSumForPage(curDownloadInfo.pageUrlStr)) { + nextPage = parser.getNextPage(); + imageUrlStr = parser.getImageUrlStr(); + + // Check stop + if (curDownloadInfo.status == DownloadInfo.STOP) { + listener.onDownloadMangaStop(curDownloadInfo.gid); + mService.notifyUpdate(); + Download.notify(String.valueOf(curDownloadInfo.gid)); + mComplete = false; + mStop = true; + break; + } + + try { + imageDownloader.resetData(folder.toString(), + String.format("%05d", curDownloadInfo.lastStartIndex) + "." + Util.getExtension(imageUrlStr), + imageUrlStr, curDownloadInfo); + imageDownloader.run(); + + curDownloadInfo.downloadSize = 0; + curDownloadInfo.totalSize = 0; + + int downloadStatus = imageDownloader.getStatus(); + if (downloadStatus == Downloader.STOP) { // If stop by user + listener.onDownloadMangaStop(curDownloadInfo.gid); + mService.notifyUpdate(); + Download.notify(String.valueOf(curDownloadInfo.gid)); + mComplete = false; + mStop = true; + break; + } else if (downloadStatus != Downloader.COMPLETED) { // If get image error + Log.e(TAG, "Download image error, downloadStatus is " + downloadStatus); + mComplete = false; + break; + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } else { + mComplete = false; + break; + } + } + if (mComplete) { + listener.onDownloadMangaOver(curDownloadInfo.gid, true); + curDownloadInfo.status = DownloadInfo.COMPLETED; + mService.notifyUpdate(); + Download.notify(String.valueOf(curDownloadInfo.gid)); + } else if (!mStop) { + listener.onDownloadMangaOver(curDownloadInfo.gid, false); + curDownloadInfo.status = DownloadInfo.FAILED; + mService.notifyUpdate(); + Download.notify(String.valueOf(curDownloadInfo.gid)); + } } synchronized (taskLock) { - curDownloadId = INVALID_ID; - if (listener != null) - listener.onDownloadMangaAllOver(); + curDownloadInfo = null; + listener.onDownloadMangaAllOver(); } } }).start(); } + + public static boolean isEmpty() { + synchronized (taskLock) { + return curDownloadInfo == null; + } + } } - public static int getFirstPageForDetail(String detailUrlStr, StringBuffer firstPage) { - int retry_times = 0; - int errorMessageId; - String pageContent; - StringBuffer sb = new StringBuffer(); + private static class Parser { - // Get content - while (sb.length() == 0) { - errorMessageId = get(detailUrlStr, sb); - pageContent = sb.toString(); - - retry_times++; - if (retry_times > DOWNLOAD_RETRY_TIMES) - break; + private int errorMegId; + + private int pageSum; + private String firstPage; + + private String prePage; + private String nextPage; + private String imageUrlStr; + + + public int getPageSum() { + return pageSum; } - // If error - if (sb.length() == 0) - return 0; + public String getFirstPage() { + return firstPage; + } - // TODO + public String getPrePage() { + return prePage; + } + public String getNextPage() { + return nextPage; + } - return 0; - } - - - public static class DMTaskInfo { - public int id; - public String detailUrlStr; - public String foldName; + public String getImageUrlStr() { + return imageUrlStr; + } - public DMTaskInfo(int id, String detailUrlStr, String foldName) { - this.id = id; - this.detailUrlStr = detailUrlStr; - this.foldName = foldName; + public String getPageContent(String urlStr) { + int retry_times = 0; + StringBuffer sb = new StringBuffer(); + + // Get content + while (sb.length() == 0) { + errorMegId = get(urlStr, sb); + retry_times++; + if (retry_times > RETRY_TIMES) + break; + } + return sb.toString(); + } + + public boolean getFirstPagePageSumForDetail(String detailUrlStr) { + String pageContent = getPageContent(detailUrlStr); + if (pageContent.length() == 0) + return false; + + Pattern p = Pattern.compile("

Showing [\\d|,]+ - [\\d|,]+ of ([\\d|,]+) images

.+
]*>(?:]*>)?]*href=\"([^<>\"]+)\"[^<>]*>"); + Matcher m = p.matcher(pageContent); + if (m.find()) { + pageSum = Integer.parseInt(m.group(1).replace(",", "")); + firstPage = m.group(2); + return true; + } + return false; + } + + /** + * Get page info, previous page, next page, image url + * + * @param pageUrlStr + * @return True if get + */ + public boolean getPageInfoSumForPage(String pageUrlStr) { + String pageContent = getPageContent(pageUrlStr); + if (pageContent.length() == 0) + return false; + + Pattern p = Pattern.compile("]*id=\"prev\"[^<>]*href=\"([^<>\"]+)\">]*/>.+]id=\"next\"[^<>]*href=\"([^<>\"]+)\">]*/>.+]*src=\"([^<>\"]+?)\"[^<>]*style=\"[^<>\"]*\"[^<>]*/>"); + Matcher m = p.matcher(pageContent); + if (m.find()) { + prePage = m.group(1); + nextPage = m.group(2); + imageUrlStr = StringEscapeUtils.unescapeHtml4(m.group(3)); + return true; + } + return false; } } diff --git a/src/com/hippo/ehviewer/util/Favourite.java b/src/com/hippo/ehviewer/util/Favourite.java index 954ce59a8..6b91e497f 100644 --- a/src/com/hippo/ehviewer/util/Favourite.java +++ b/src/com/hippo/ehviewer/util/Favourite.java @@ -109,10 +109,6 @@ public class Favourite { * @return True if remove successfully */ public static boolean remove(int index) { - if (!mInit) { - throw new IllegalStateException("Please init Favourite first."); - } - mFavouriteLmd.remove(index); String key = mListOrder.remove(index); Util.putStrings(mFavouritePre, LIST_ORDER, mListOrder); @@ -126,9 +122,6 @@ public class Favourite { * @return */ public static ArrayList getFavouriteList() { - if (!mInit) { - throw new IllegalStateException("Please init Favourite first."); - } return mFavouriteLmd; } diff --git a/src/com/hippo/ehviewer/util/Tag.java b/src/com/hippo/ehviewer/util/Tag.java index 18b4053e7..0e7963705 100644 --- a/src/com/hippo/ehviewer/util/Tag.java +++ b/src/com/hippo/ehviewer/util/Tag.java @@ -25,9 +25,8 @@ public class Tag { private static ArrayList mTags = new ArrayList(); private static boolean mInit = false; - private static final String NOT_INIT_ERROR_INFO = "Please init Tag first."; /** - * Init Favourite + * Init Tag * * @param context Application context */ @@ -51,9 +50,6 @@ public class Tag { } private static void getTag() { - if (!mInit) - throw new IllegalStateException(NOT_INIT_ERROR_INFO); - String[] allOrder = Util.getStrings(mTagPre, LIST_ORDER); if (allOrder == null) @@ -82,9 +78,6 @@ public class Tag { * @return */ public static boolean add(String key, ListUrls tag) { - if (!mInit) - throw new IllegalStateException(NOT_INIT_ERROR_INFO); - // Check contain this item or not if (mListOrder.indexOf(key) == -1) { mListOrder.add(key); @@ -133,9 +126,6 @@ public class Tag { * @return True if remove successfully */ public static boolean remove(String key) { - if (!mInit) - throw new IllegalStateException(NOT_INIT_ERROR_INFO); - int index = mListOrder.indexOf(key); if (index != -1) { mListOrder.remove(index); @@ -154,9 +144,6 @@ public class Tag { * @return True if remove successfully */ public static boolean remove(int index) { - if (!mInit) - throw new IllegalStateException(NOT_INIT_ERROR_INFO); - mTags.remove(index); String key = mListOrder.remove(index); mTagPre.edit().remove(key).apply(); @@ -198,8 +185,6 @@ public class Tag { * @return */ public static ArrayList getTagList() { - if (!mInit) - throw new IllegalStateException(NOT_INIT_ERROR_INFO); return mTags; } @@ -209,8 +194,6 @@ public class Tag { * @return */ public static ArrayList getKeyList() { - if (!mInit) - throw new IllegalStateException(NOT_INIT_ERROR_INFO); return mListOrder; } diff --git a/src/com/hippo/ehviewer/util/Ui.java b/src/com/hippo/ehviewer/util/Ui.java index ccd825c4a..cc4d31b44 100644 --- a/src/com/hippo/ehviewer/util/Ui.java +++ b/src/com/hippo/ehviewer/util/Ui.java @@ -150,6 +150,7 @@ public class Ui { } if (viewGroup == null || rawRateString == null) return; + viewGroup.removeAllViews(); float num = 0; try{ num = Float.parseFloat(rawRateString); diff --git a/src/com/hippo/ehviewer/util/Util.java b/src/com/hippo/ehviewer/util/Util.java index a05ead698..fb59e1635 100644 --- a/src/com/hippo/ehviewer/util/Util.java +++ b/src/com/hippo/ehviewer/util/Util.java @@ -38,7 +38,7 @@ public class Util { private static String TAG = "Util"; /** - * Put InputStream to File, default bufferSize is 16 * 1024 + * Put InputStream to File, default bufferSize is 512 * 1024 * * @param is * @param file @@ -50,7 +50,7 @@ public class Util { } public static void copy(InputStream is, OutputStream os) throws IOException { - byte[] buffer = new byte[16 * 1024]; + byte[] buffer = new byte[512 * 1024]; int bytesRead; while((bytesRead = is.read(buffer)) !=-1) os.write(buffer, 0, bytesRead); @@ -65,11 +65,36 @@ public class Util { public static int getResourcesType(String url) { int type = BITMAP; int index = url.lastIndexOf('.'); - if (index != -1 && url.substring(index + 1).toLowerCase().equals("gif")) + if (index != -1 && getExtension(url).equals("gif")) type = MOVIE; return type; } + public static String getExtension(String url) { + int index = url.lastIndexOf('.'); + if (index != -1) + return url.substring(index + 1).toLowerCase(); + else + return "png"; + } + + public static String getName(String fileName) { + int index = fileName.lastIndexOf('.'); + if (index != -1) + return fileName.substring(0, index).toLowerCase(); + else + return "png"; + } + + public static boolean isNumber(String str) { + for (int i = 0; i < str.length(); i++) { + char ch = str.charAt(i); + if (ch < '0' || ch > '9') + return false; + } + return true; + } + public static String byteArrayToHexString(byte[] b) { StringBuilder sb = new StringBuilder(b.length * 2); for (byte element : b) { @@ -130,4 +155,20 @@ public class Util { sb.delete(length - 1, length); shaper.edit().putString(key, byteArrayToHexString(sb.toString().getBytes())).apply(); } + + public static void closeStreamQuietly (InputStream is) { + try { + if (is != null) + is.close(); + } catch (IOException e) { + } + } + + public static void closeStreamQuietly (OutputStream os) { + try { + if (os != null) + os.close(); + } catch (IOException e) { + } + } }