From 7e7e3f89ce606a88fc231872f441b75a9367e8e7 Mon Sep 17 00:00:00 2001 From: Eric Kok Date: Wed, 27 Feb 2013 12:48:24 +0100 Subject: [PATCH] Updated ActionBarSherlock to 4.2.0 --- android/AndroidManifest.xml | 3 +- android/project.properties | 2 +- android/res/values-v11/themes.xml | 19 + android/res/values-v14/themes.xml | 20 + android/res/values/themes.xml | 16 +- android/src/org/transdroid/gui/Details.java | 5 +- .../org/transdroid/gui/DetailsFragment.java | 33 +- android/src/org/transdroid/gui/Torrents.java | 7 +- .../org/transdroid/gui/TorrentsFragment.java | 50 +- .../src/org/transdroid/gui/rss/RssFeeds.java | 5 +- .../transdroid/gui/rss/RssFeedsFragment.java | 18 +- .../org/transdroid/gui/rss/RssListing.java | 6 +- .../gui/rss/RssListingFragment.java | 39 +- .../src/org/transdroid/gui/search/Search.java | 12 +- .../CHANGELOG.md | 192 +- .../CONTRIBUTING.md | 11 + .../JakeWharton-ActionBarSherlock/README.md | 37 +- .../{library => }/checkstyle.xml | 16 +- .../library/.classpath | 2 +- .../.settings/org.eclipse.jdt.core.prefs | 12 - .../library/AndroidManifest.xml | 11 +- .../library/README.md | 4 +- .../library/default.properties | 3 - .../library/libs/android-support-v4.jar | Bin 0 -> 271754 bytes .../library/pom.xml | 79 +- .../library/project.properties | 2 +- .../library/res/color/abs__item_bg.xml | 14 - ...s__primary_text_disable_only_holo_dark.xml | 20 + ...__primary_text_disable_only_holo_light.xml | 21 + .../res/color/abs__primary_text_holo_dark.xml | 24 + .../color/abs__primary_text_holo_light.xml | 26 + .../res/color/abs__tab_text_color_dark.xml | 8 - .../res/color/abs__tab_text_color_light.xml | 8 - .../abs__ab_bottom_solid_dark_holo.9.png | Bin 0 -> 144 bytes .../abs__ab_bottom_solid_inverse_holo.9.png | Bin 0 -> 138 bytes .../abs__ab_bottom_solid_light_holo.9.png | Bin 0 -> 144 bytes ...abs__ab_bottom_transparent_dark_holo.9.png | Bin 0 -> 135 bytes ...bs__ab_bottom_transparent_light_holo.9.png | Bin 0 -> 134 bytes .../abs__ab_share_pack_holo_dark.9.png | Bin 0 -> 2863 bytes .../abs__ab_share_pack_holo_light.9.png | Bin 0 -> 2859 bytes .../abs__ab_solid_dark_holo.9.png | Bin 0 -> 146 bytes .../abs__ab_solid_light_holo.9.png | Bin 0 -> 145 bytes .../abs__ab_solid_shadow_holo.9.png | Bin 0 -> 192 bytes .../abs__ab_stacked_solid_dark_holo.9.png | Bin 0 -> 146 bytes .../abs__ab_stacked_solid_light_holo.9.png | Bin 0 -> 146 bytes ...bs__ab_stacked_transparent_dark_holo.9.png | Bin 0 -> 139 bytes ...s__ab_stacked_transparent_light_holo.9.png | Bin 0 -> 133 bytes .../abs__ab_transparent_dark_holo.9.png | Bin 0 -> 155 bytes .../abs__ab_transparent_light_holo.9.png | Bin 0 -> 145 bytes .../abs__btn_cab_done_default_holo_dark.9.png | Bin 0 -> 104 bytes ...abs__btn_cab_done_default_holo_light.9.png | Bin 0 -> 102 bytes .../abs__btn_cab_done_focused_holo_dark.9.png | Bin 0 -> 112 bytes ...abs__btn_cab_done_focused_holo_light.9.png | Bin 0 -> 108 bytes .../abs__btn_cab_done_pressed_holo_dark.9.png | Bin 0 -> 110 bytes ...abs__btn_cab_done_pressed_holo_light.9.png | Bin 0 -> 108 bytes ...abs__cab_background_bottom_holo_dark.9.png | Bin 0 -> 149 bytes ...bs__cab_background_bottom_holo_light.9.png | Bin 0 -> 145 bytes .../abs__cab_background_holo_dark.9.png | Bin 3307 -> 0 bytes .../abs__cab_background_holo_light.9.png | Bin 3494 -> 0 bytes .../abs__cab_background_top_holo_dark.9.png | Bin 0 -> 147 bytes .../abs__cab_background_top_holo_light.9.png | Bin 0 -> 147 bytes .../abs__cab_ic_close_focused_holo.png | Bin 1292 -> 0 bytes .../abs__cab_ic_close_normal_holo.png | Bin 957 -> 0 bytes .../abs__cab_ic_close_pressed_holo.png | Bin 1749 -> 0 bytes .../abs__dialog_full_holo_dark.9.png | Bin 0 -> 1414 bytes .../abs__dialog_full_holo_light.9.png | Bin 0 -> 1537 bytes .../abs__ic_ab_back_holo_dark.png | Bin 938 -> 602 bytes .../abs__ic_ab_back_holo_light.png | Bin 975 -> 546 bytes .../abs__ic_cab_done_holo_dark.png | Bin 0 -> 713 bytes .../abs__ic_cab_done_holo_light.png | Bin 0 -> 737 bytes .../drawable-hdpi/abs__ic_clear_disabled.png | Bin 0 -> 1774 bytes .../drawable-hdpi/abs__ic_clear_normal.png | Bin 0 -> 1945 bytes ...c_clear_search_api_disabled_holo_light.png | Bin 0 -> 1504 bytes .../abs__ic_clear_search_api_holo_light.png | Bin 0 -> 1540 bytes .../library/res/drawable-hdpi/abs__ic_go.png | Bin 0 -> 1415 bytes .../abs__ic_go_search_api_holo_light.png | Bin 0 -> 1252 bytes ..._ic_menu_moreoverflow_normal_holo_dark.png | Bin 0 -> 144 bytes ...ic_menu_moreoverflow_normal_holo_light.png | Bin 0 -> 148 bytes .../abs__ic_menu_share_holo_dark.png | Bin 0 -> 467 bytes .../abs__ic_menu_share_holo_light.png | Bin 0 -> 505 bytes .../res/drawable-hdpi/abs__ic_search.png | Bin 0 -> 2280 bytes .../abs__ic_search_api_holo_light.png | Bin 0 -> 2271 bytes .../drawable-hdpi/abs__ic_voice_search.png | Bin 0 -> 2070 bytes .../abs__ic_voice_search_api_holo_light.png | Bin 0 -> 1833 bytes .../abs__list_activated_holo.9.png | Bin 0 -> 154 bytes .../abs__list_divider_holo_dark.9.png | Bin 0 -> 78 bytes .../abs__list_divider_holo_light.9.png | Bin 0 -> 76 bytes .../abs__list_focused_holo.9.png | Bin 1098 -> 159 bytes .../abs__list_longpressed_holo.9.png | Bin 1060 -> 154 bytes .../abs__list_pressed_holo_dark.9.png | Bin 1061 -> 159 bytes .../abs__list_pressed_holo_light.9.png | Bin 1060 -> 159 bytes .../abs__menu_dropdown_panel_holo_dark.9.png | Bin 0 -> 922 bytes .../abs__menu_dropdown_panel_holo_light.9.png | Bin 0 -> 1061 bytes .../abs__progress_bg_holo_dark.9.png | Bin 0 -> 178 bytes .../abs__progress_bg_holo_light.9.png | Bin 0 -> 174 bytes .../abs__progress_primary_holo_dark.9.png | Bin 0 -> 917 bytes .../abs__progress_primary_holo_light.9.png | Bin 0 -> 917 bytes .../abs__progress_secondary_holo_dark.9.png | Bin 0 -> 188 bytes .../abs__progress_secondary_holo_light.9.png | Bin 0 -> 188 bytes .../abs__spinner_48_inner_holo.png | Bin 0 -> 2081 bytes .../abs__spinner_48_outer_holo.png | Bin 0 -> 1811 bytes .../abs__spinner_ab_default_holo_dark.9.png | Bin 0 -> 311 bytes .../abs__spinner_ab_default_holo_light.9.png | Bin 0 -> 312 bytes .../abs__spinner_ab_disabled_holo_dark.9.png | Bin 0 -> 306 bytes .../abs__spinner_ab_disabled_holo_light.9.png | Bin 0 -> 306 bytes .../abs__spinner_ab_focused_holo_dark.9.png | Bin 0 -> 524 bytes .../abs__spinner_ab_focused_holo_light.9.png | Bin 0 -> 523 bytes .../abs__spinner_ab_pressed_holo_dark.9.png | Bin 0 -> 464 bytes .../abs__spinner_ab_pressed_holo_light.9.png | Bin 0 -> 458 bytes .../abs__spinner_default_holo_dark.9.png | Bin 378 -> 0 bytes .../abs__spinner_default_holo_light.9.png | Bin 378 -> 0 bytes .../abs__spinner_disabled_holo_dark.9.png | Bin 382 -> 0 bytes .../abs__spinner_disabled_holo_light.9.png | Bin 382 -> 0 bytes .../abs__spinner_focused_holo_dark.9.png | Bin 396 -> 0 bytes .../abs__spinner_focused_holo_light.9.png | Bin 532 -> 0 bytes .../abs__spinner_pressed_holo_dark.9.png | Bin 530 -> 0 bytes .../abs__spinner_pressed_holo_light.9.png | Bin 536 -> 0 bytes .../abs__tab_selected_focused_holo.9.png | Bin 218 -> 147 bytes .../abs__tab_selected_holo.9.png | Bin 159 -> 148 bytes ...s__tab_selected_pressed_focused_holo.9.png | Bin 522 -> 0 bytes .../abs__tab_selected_pressed_holo.9.png | Bin 271 -> 147 bytes .../abs__tab_unselected_focused_holo.9.png | Bin 216 -> 0 bytes .../abs__tab_unselected_holo.9.png | Bin 147 -> 0 bytes ..._tab_unselected_pressed_focused_holo.9.png | Bin 536 -> 0 bytes .../abs__tab_unselected_pressed_holo.9.png | Bin 265 -> 145 bytes ...__textfield_search_default_holo_dark.9.png | Bin 0 -> 110 bytes ..._textfield_search_default_holo_light.9.png | Bin 0 -> 105 bytes ...field_search_right_default_holo_dark.9.png | Bin 0 -> 108 bytes ...ield_search_right_default_holo_light.9.png | Bin 0 -> 103 bytes ...ield_search_right_selected_holo_dark.9.png | Bin 0 -> 114 bytes ...eld_search_right_selected_holo_light.9.png | Bin 0 -> 111 bytes ..._textfield_search_selected_holo_dark.9.png | Bin 0 -> 114 bytes ...textfield_search_selected_holo_light.9.png | Bin 0 -> 112 bytes .../abs__ab_bottom_solid_dark_holo.9.png | Bin 0 -> 134 bytes .../abs__ab_bottom_solid_inverse_holo.9.png | Bin 0 -> 129 bytes .../abs__ab_bottom_solid_light_holo.9.png | Bin 0 -> 134 bytes ...abs__ab_bottom_transparent_dark_holo.9.png | Bin 0 -> 123 bytes ...bs__ab_bottom_transparent_light_holo.9.png | Bin 0 -> 123 bytes .../abs__ab_share_pack_holo_dark.9.png | Bin 0 -> 2849 bytes .../abs__ab_share_pack_holo_light.9.png | Bin 0 -> 191 bytes .../abs__ab_solid_dark_holo.9.png | Bin 0 -> 133 bytes .../abs__ab_solid_light_holo.9.png | Bin 0 -> 133 bytes .../abs__ab_solid_shadow_holo.9.png | Bin 0 -> 168 bytes .../abs__ab_stacked_solid_dark_holo.9.png | Bin 0 -> 134 bytes .../abs__ab_stacked_solid_light_holo.9.png | Bin 0 -> 133 bytes ...bs__ab_stacked_transparent_dark_holo.9.png | Bin 0 -> 127 bytes ...s__ab_stacked_transparent_light_holo.9.png | Bin 0 -> 123 bytes .../abs__ab_transparent_dark_holo.9.png | Bin 0 -> 139 bytes .../abs__ab_transparent_light_holo.9.png | Bin 0 -> 133 bytes .../abs__btn_cab_done_default_holo_dark.9.png | Bin 0 -> 101 bytes ...abs__btn_cab_done_default_holo_light.9.png | Bin 0 -> 99 bytes .../abs__btn_cab_done_focused_holo_dark.9.png | Bin 0 -> 109 bytes ...abs__btn_cab_done_focused_holo_light.9.png | Bin 0 -> 105 bytes .../abs__btn_cab_done_pressed_holo_dark.9.png | Bin 0 -> 107 bytes ...abs__btn_cab_done_pressed_holo_light.9.png | Bin 0 -> 105 bytes ...abs__cab_background_bottom_holo_dark.9.png | Bin 0 -> 127 bytes ...bs__cab_background_bottom_holo_light.9.png | Bin 0 -> 124 bytes .../abs__cab_background_holo_dark.9.png | Bin 1993 -> 0 bytes .../abs__cab_background_holo_light.9.png | Bin 2062 -> 0 bytes .../abs__cab_background_top_holo_dark.9.png | Bin 0 -> 130 bytes .../abs__cab_background_top_holo_light.9.png | Bin 0 -> 128 bytes .../abs__cab_ic_close_focused_holo.png | Bin 906 -> 0 bytes .../abs__cab_ic_close_normal_holo.png | Bin 705 -> 0 bytes .../abs__cab_ic_close_pressed_holo.png | Bin 1226 -> 0 bytes .../abs__dialog_full_holo_dark.9.png | Bin 0 -> 882 bytes .../abs__dialog_full_holo_light.9.png | Bin 0 -> 1003 bytes .../abs__ic_ab_back_holo_dark.png | Bin 709 -> 466 bytes .../abs__ic_ab_back_holo_light.png | Bin 728 -> 438 bytes .../abs__ic_cab_done_holo_dark.png | Bin 0 -> 566 bytes .../abs__ic_cab_done_holo_light.png | Bin 0 -> 552 bytes .../drawable-mdpi/abs__ic_clear_disabled.png | Bin 0 -> 1775 bytes .../drawable-mdpi/abs__ic_clear_normal.png | Bin 0 -> 1869 bytes ...c_clear_search_api_disabled_holo_light.png | Bin 0 -> 740 bytes .../abs__ic_clear_search_api_holo_light.png | Bin 0 -> 743 bytes .../library/res/drawable-mdpi/abs__ic_go.png | Bin 0 -> 1538 bytes .../abs__ic_go_search_api_holo_light.png | Bin 0 -> 570 bytes ..._ic_menu_moreoverflow_normal_holo_dark.png | Bin 0 -> 122 bytes ...ic_menu_moreoverflow_normal_holo_light.png | Bin 0 -> 131 bytes .../abs__ic_menu_share_holo_dark.png | Bin 0 -> 332 bytes .../abs__ic_menu_share_holo_light.png | Bin 0 -> 355 bytes .../res/drawable-mdpi/abs__ic_search.png | Bin 0 -> 2280 bytes .../abs__ic_search_api_holo_light.png | Bin 0 -> 1541 bytes .../drawable-mdpi/abs__ic_voice_search.png | Bin 0 -> 1937 bytes .../abs__ic_voice_search_api_holo_light.png | Bin 0 -> 794 bytes .../abs__list_activated_holo.9.png | Bin 0 -> 151 bytes .../abs__list_divider_holo_dark.9.png | Bin 0 -> 78 bytes .../abs__list_divider_holo_light.9.png | Bin 0 -> 76 bytes .../abs__list_focused_holo.9.png | Bin 1092 -> 158 bytes .../abs__list_longpressed_holo.9.png | Bin 1049 -> 151 bytes .../abs__list_pressed_holo_dark.9.png | Bin 1057 -> 158 bytes .../abs__list_pressed_holo_light.9.png | Bin 1053 -> 158 bytes .../abs__menu_dropdown_panel_holo_dark.9.png | Bin 0 -> 651 bytes .../abs__menu_dropdown_panel_holo_light.9.png | Bin 0 -> 720 bytes .../abs__progress_bg_holo_dark.9.png | Bin 0 -> 165 bytes .../abs__progress_bg_holo_light.9.png | Bin 0 -> 159 bytes .../abs__progress_primary_holo_dark.9.png | Bin 0 -> 572 bytes .../abs__progress_primary_holo_light.9.png | Bin 0 -> 572 bytes .../abs__progress_secondary_holo_dark.9.png | Bin 0 -> 170 bytes .../abs__progress_secondary_holo_light.9.png | Bin 0 -> 170 bytes .../abs__spinner_48_inner_holo.png | Bin 0 -> 1336 bytes .../abs__spinner_48_outer_holo.png | Bin 0 -> 1165 bytes .../abs__spinner_ab_default_holo_dark.9.png | Bin 0 -> 254 bytes .../abs__spinner_ab_default_holo_light.9.png | Bin 0 -> 255 bytes .../abs__spinner_ab_disabled_holo_dark.9.png | Bin 0 -> 249 bytes .../abs__spinner_ab_disabled_holo_light.9.png | Bin 0 -> 249 bytes .../abs__spinner_ab_focused_holo_dark.9.png | Bin 0 -> 417 bytes .../abs__spinner_ab_focused_holo_light.9.png | Bin 0 -> 424 bytes .../abs__spinner_ab_pressed_holo_dark.9.png | Bin 0 -> 370 bytes .../abs__spinner_ab_pressed_holo_light.9.png | Bin 0 -> 370 bytes .../abs__spinner_default_holo_dark.9.png | Bin 302 -> 0 bytes .../abs__spinner_default_holo_light.9.png | Bin 301 -> 0 bytes .../abs__spinner_disabled_holo_dark.9.png | Bin 331 -> 0 bytes .../abs__spinner_disabled_holo_light.9.png | Bin 331 -> 0 bytes .../abs__spinner_focused_holo_dark.9.png | Bin 352 -> 0 bytes .../abs__spinner_focused_holo_light.9.png | Bin 499 -> 0 bytes .../abs__spinner_pressed_holo_dark.9.png | Bin 420 -> 0 bytes .../abs__spinner_pressed_holo_light.9.png | Bin 457 -> 0 bytes .../abs__tab_selected_focused_holo.9.png | Bin 203 -> 148 bytes .../abs__tab_selected_holo.9.png | Bin 144 -> 151 bytes ...s__tab_selected_pressed_focused_holo.9.png | Bin 454 -> 0 bytes .../abs__tab_selected_pressed_holo.9.png | Bin 231 -> 150 bytes .../abs__tab_unselected_focused_holo.9.png | Bin 196 -> 0 bytes .../abs__tab_unselected_holo.9.png | Bin 128 -> 0 bytes ..._tab_unselected_pressed_focused_holo.9.png | Bin 459 -> 0 bytes .../abs__tab_unselected_pressed_holo.9.png | Bin 223 -> 155 bytes ...__textfield_search_default_holo_dark.9.png | Bin 0 -> 106 bytes ..._textfield_search_default_holo_light.9.png | Bin 0 -> 100 bytes ...field_search_right_default_holo_dark.9.png | Bin 0 -> 105 bytes ...ield_search_right_default_holo_light.9.png | Bin 0 -> 98 bytes ...ield_search_right_selected_holo_dark.9.png | Bin 0 -> 107 bytes ...eld_search_right_selected_holo_light.9.png | Bin 0 -> 107 bytes ..._textfield_search_selected_holo_dark.9.png | Bin 0 -> 109 bytes ...textfield_search_selected_holo_light.9.png | Bin 0 -> 109 bytes .../abs__action_item_divider.9.png | Bin 80 -> 0 bytes .../abs__action_item_divider.9.png | Bin 134 -> 0 bytes .../abs__progress_medium_holo.xml | 34 + .../abs__ab_bottom_solid_dark_holo.9.png | Bin 0 -> 165 bytes .../abs__ab_bottom_solid_inverse_holo.9.png | Bin 0 -> 157 bytes .../abs__ab_bottom_solid_light_holo.9.png | Bin 0 -> 166 bytes ...abs__ab_bottom_transparent_dark_holo.9.png | Bin 0 -> 153 bytes ...bs__ab_bottom_transparent_light_holo.9.png | Bin 0 -> 152 bytes .../abs__ab_share_pack_holo_dark.9.png | Bin 0 -> 2878 bytes .../abs__ab_share_pack_holo_light.9.png | Bin 0 -> 2873 bytes .../abs__ab_solid_dark_holo.9.png | Bin 0 -> 163 bytes .../abs__ab_solid_light_holo.9.png | Bin 0 -> 163 bytes .../abs__ab_solid_shadow_holo.9.png | Bin 0 -> 290 bytes .../abs__ab_stacked_solid_dark_holo.9.png | Bin 0 -> 163 bytes .../abs__ab_stacked_solid_light_holo.9.png | Bin 0 -> 163 bytes ...bs__ab_stacked_transparent_dark_holo.9.png | Bin 0 -> 158 bytes ...s__ab_stacked_transparent_light_holo.9.png | Bin 0 -> 152 bytes .../abs__ab_transparent_dark_holo.9.png | Bin 0 -> 171 bytes .../abs__ab_transparent_light_holo.9.png | Bin 0 -> 160 bytes .../abs__btn_cab_done_default_holo_dark.9.png | Bin 0 -> 109 bytes ...abs__btn_cab_done_default_holo_light.9.png | Bin 0 -> 108 bytes .../abs__btn_cab_done_focused_holo_dark.9.png | Bin 0 -> 112 bytes ...abs__btn_cab_done_focused_holo_light.9.png | Bin 0 -> 113 bytes .../abs__btn_cab_done_pressed_holo_dark.9.png | Bin 0 -> 115 bytes ...abs__btn_cab_done_pressed_holo_light.9.png | Bin 0 -> 113 bytes ...abs__cab_background_bottom_holo_dark.9.png | Bin 0 -> 166 bytes ...bs__cab_background_bottom_holo_light.9.png | Bin 0 -> 161 bytes .../abs__cab_background_top_holo_dark.9.png | Bin 0 -> 174 bytes .../abs__cab_background_top_holo_light.9.png | Bin 0 -> 161 bytes .../abs__dialog_full_holo_dark.9.png | Bin 0 -> 2159 bytes .../abs__dialog_full_holo_light.9.png | Bin 0 -> 2302 bytes .../abs__ic_ab_back_holo_dark.png | Bin 0 -> 741 bytes .../abs__ic_ab_back_holo_light.png | Bin 0 -> 661 bytes .../abs__ic_cab_done_holo_dark.png | Bin 0 -> 970 bytes .../abs__ic_cab_done_holo_light.png | Bin 0 -> 915 bytes .../drawable-xhdpi/abs__ic_clear_disabled.png | Bin 0 -> 2531 bytes ...c_clear_search_api_disabled_holo_light.png | Bin 0 -> 1315 bytes .../abs__ic_clear_search_api_holo_light.png | Bin 0 -> 1447 bytes .../library/res/drawable-xhdpi/abs__ic_go.png | Bin 0 -> 1983 bytes .../abs__ic_go_search_api_holo_light.png | Bin 0 -> 836 bytes ..._ic_menu_moreoverflow_normal_holo_dark.png | Bin 0 -> 167 bytes ...ic_menu_moreoverflow_normal_holo_light.png | Bin 0 -> 184 bytes .../abs__ic_menu_share_holo_dark.png | Bin 0 -> 699 bytes .../abs__ic_menu_share_holo_light.png | Bin 0 -> 935 bytes .../res/drawable-xhdpi/abs__ic_search.png | Bin 0 -> 3784 bytes .../abs__ic_search_api_holo_light.png | Bin 0 -> 3037 bytes .../drawable-xhdpi/abs__ic_voice_search.png | Bin 0 -> 3053 bytes .../abs__ic_voice_search_api_holo_light.png | Bin 0 -> 1414 bytes .../abs__list_activated_holo.9.png | Bin 0 -> 158 bytes .../abs__list_divider_holo_dark.9.png | Bin 0 -> 83 bytes .../abs__list_divider_holo_light.9.png | Bin 0 -> 83 bytes .../abs__list_focused_holo.9.png | Bin 0 -> 163 bytes .../abs__list_longpressed_holo.9.png | Bin 0 -> 158 bytes .../abs__list_pressed_holo_dark.9.png | Bin 0 -> 163 bytes .../abs__list_pressed_holo_light.9.png | Bin 0 -> 163 bytes ...bs__list_selector_disabled_holo_dark.9.png | Bin 0 -> 190 bytes ...s__list_selector_disabled_holo_light.9.png | Bin 0 -> 188 bytes .../abs__menu_dropdown_panel_holo_dark.9.png | Bin 0 -> 1362 bytes .../abs__menu_dropdown_panel_holo_light.9.png | Bin 0 -> 1551 bytes .../abs__progress_bg_holo_dark.9.png | Bin 0 -> 174 bytes .../abs__progress_bg_holo_light.9.png | Bin 0 -> 172 bytes .../abs__progress_primary_holo_dark.9.png | Bin 0 -> 1309 bytes .../abs__progress_primary_holo_light.9.png | Bin 0 -> 1309 bytes .../abs__progress_secondary_holo_dark.9.png | Bin 0 -> 184 bytes .../abs__progress_secondary_holo_light.9.png | Bin 0 -> 184 bytes .../abs__spinner_48_inner_holo.png | Bin 0 -> 2769 bytes .../abs__spinner_48_outer_holo.png | Bin 0 -> 2432 bytes .../abs__spinner_ab_default_holo_dark.9.png | Bin 0 -> 395 bytes .../abs__spinner_ab_default_holo_light.9.png | Bin 0 -> 394 bytes .../abs__spinner_ab_disabled_holo_dark.9.png | Bin 0 -> 381 bytes .../abs__spinner_ab_disabled_holo_light.9.png | Bin 0 -> 381 bytes .../abs__spinner_ab_focused_holo_dark.9.png | Bin 0 -> 680 bytes .../abs__spinner_ab_focused_holo_light.9.png | Bin 0 -> 671 bytes .../abs__spinner_ab_pressed_holo_dark.9.png | Bin 0 -> 609 bytes .../abs__spinner_ab_pressed_holo_light.9.png | Bin 0 -> 602 bytes .../abs__tab_selected_focused_holo.9.png | Bin 0 -> 147 bytes .../abs__tab_selected_holo.9.png | Bin 0 -> 153 bytes .../abs__tab_selected_pressed_holo.9.png | Bin 0 -> 147 bytes .../abs__tab_unselected_pressed_holo.9.png | Bin 0 -> 149 bytes ...__textfield_search_default_holo_dark.9.png | Bin 0 -> 126 bytes ..._textfield_search_default_holo_light.9.png | Bin 0 -> 126 bytes ...field_search_right_default_holo_dark.9.png | Bin 0 -> 125 bytes ...ield_search_right_default_holo_light.9.png | Bin 0 -> 127 bytes ...ield_search_right_selected_holo_dark.9.png | Bin 0 -> 128 bytes ...eld_search_right_selected_holo_light.9.png | Bin 0 -> 128 bytes ..._textfield_search_selected_holo_dark.9.png | Bin 0 -> 114 bytes ...textfield_search_selected_holo_light.9.png | Bin 0 -> 126 bytes .../abs__activated_background_holo_dark.xml | 20 + .../abs__activated_background_holo_light.xml | 20 + .../drawable/abs__btn_cab_done_holo_dark.xml | 24 + .../drawable/abs__btn_cab_done_holo_light.xml | 24 + .../abs__ic_clear.xml} | 23 +- ..._holo.xml => abs__ic_clear_holo_light.xml} | 9 +- .../abs__ic_menu_moreoverflow_holo_dark.xml} | 12 +- .../abs__ic_menu_moreoverflow_holo_light.xml} | 10 +- .../abs__item_background_holo_dark.xml | 5 +- .../abs__item_background_holo_light.xml | 5 +- .../drawable/abs__list_selector_holo_dark.xml | 27 + .../abs__list_selector_holo_light.xml | 28 + .../abs__progress_horizontal_holo_dark.xml | 32 + .../abs__progress_horizontal_holo_light.xml | 32 + .../drawable/abs__progress_medium_holo.xml | 34 + .../drawable/abs__search_dropdown_dark.xml | 22 + .../drawable/abs__search_dropdown_light.xml | 22 + ...dark.xml => abs__spinner_ab_holo_dark.xml} | 10 +- ...ght.xml => abs__spinner_ab_holo_light.xml} | 8 +- ...olo.xml => abs__tab_indicator_ab_holo.xml} | 16 +- .../abs__textfield_searchview_holo_dark.xml | 22 + .../abs__textfield_searchview_holo_light.xml | 22 + ...__textfield_searchview_right_holo_dark.xml | 22 + ..._textfield_searchview_right_holo_light.xml | 22 + .../abs__action_mode_close_item.xml | 40 + .../sherlock_spinner_dropdown_item.xml | 26 + .../res/layout-v14/sherlock_spinner_item.xml | 26 + .../layout-xlarge/abs__screen_action_bar.xml | 34 +- .../abs__screen_action_bar_overlay.xml | 42 +- .../library/res/layout/abs__action_bar.xml | 110 - .../res/layout/abs__action_bar_home.xml | 49 +- .../res/layout/abs__action_bar_inline.xml | 118 - .../layout/abs__action_bar_item_layout.xml | 52 - .../res/layout/abs__action_bar_tab.xml | 7 + .../layout/abs__action_bar_tab_bar_view.xml | 6 + .../res/layout/abs__action_bar_tab_layout.xml | 53 - .../res/layout/abs__action_bar_title_item.xml | 58 +- .../layout/abs__action_menu_item_layout.xml | 56 + .../res/layout/abs__action_menu_layout.xml | 23 + .../res/layout/abs__action_mode_bar.xml | 24 + .../layout/abs__action_mode_close_item.xml | 31 + .../res/layout/abs__activity_chooser_view.xml | 70 + .../abs__activity_chooser_view_list_item.xml | 53 + .../res/layout/abs__dialog_title_holo.xml | 46 + .../layout/abs__list_menu_item_checkbox.xml | 26 + .../res/layout/abs__list_menu_item_icon.xml | 28 + .../res/layout/abs__list_menu_item_layout.xml | 59 + .../res/layout/abs__list_menu_item_radio.xml | 24 + .../layout/abs__popup_menu_item_layout.xml | 60 + .../res/layout/abs__screen_action_bar.xml | 32 +- .../layout/abs__screen_action_bar_inline.xml | 48 - .../abs__screen_action_bar_inline_overlay.xml | 49 - .../layout/abs__screen_action_bar_overlay.xml | 61 +- .../library/res/layout/abs__screen_simple.xml | 11 +- ...abs__screen_simple_overlay_action_mode.xml | 38 + .../abs__search_dropdown_item_icons_2line.xml | 89 + .../library/res/layout/abs__search_view.xml | 159 ++ .../res/layout/abs__simple_dropdown_hint.xml | 29 + .../layout/sherlock_spinner_dropdown_item.xml | 26 + ...ner_item.xml => sherlock_spinner_item.xml} | 2 +- .../res/values-land/abs__constants.xml | 5 - .../library/res/values-land/abs__dimens.xml | 33 + .../abs__dimens.xml | 33 + .../abs__dimens.xml | 33 + .../abs__dimens.xml | 33 + .../abs__dimens.xml | 36 + .../library/res/values-large/abs__dimens.xml | 29 + .../abs__bools.xml} | 11 +- .../res/values-sw600dp/abs__dimens.xml | 38 + .../library/res/values-v11/abs__styles.xml | 187 -- .../library/res/values-v11/abs__themes.xml | 12 + .../library/res/values-v13/abs__styles.xml | 11 - .../library/res/values-v14/abs__styles.xml | 123 ++ .../library/res/values-v14/abs__themes.xml | 34 + .../library/res/values-w360dp/abs__dimens.xml | 22 + .../library/res/values-w480dp/abs__bools.xml | 22 + .../library/res/values-w480dp/abs__config.xml | 29 + .../library/res/values-w500dp/abs__dimens.xml | 22 + .../library/res/values-w600dp/abs__dimens.xml | 22 + .../library/res/values-xlarge/abs__dimens.xml | 45 + .../library/res/values/abs__attrs.xml | 426 +++- .../library/res/values/abs__bools.xml | 22 + .../library/res/values/abs__colors.xml | 27 + .../library/res/values/abs__config.xml | 43 + .../library/res/values/abs__constants.xml | 7 - .../library/res/values/abs__dimens.xml | 67 + .../library/res/values/abs__ids.xml | 26 + .../library/res/values/abs__strings.xml | 53 + .../library/res/values/abs__styles.xml | 582 +++-- .../library/res/values/abs__themes.xml | 239 ++ .../src/android/support/v4/app/ActionBar.java | 807 ------- .../support/v4/app/BackStackRecord.java | 721 ------ .../support/v4/app/DialogFragment.java | 396 ---- .../src/android/support/v4/app/Fragment.java | 1339 ------------ .../support/v4/app/FragmentActivity.java | 1213 ----------- .../support/v4/app/FragmentManager.java | 1923 ----------------- .../support/v4/app/FragmentPagerAdapter.java | 135 -- .../v4/app/FragmentStatePagerAdapter.java | 168 -- .../support/v4/app/FragmentTransaction.java | 262 --- .../android/support/v4/app/HCSparseArray.java | 360 --- .../android/support/v4/app/ListFragment.java | 375 ---- .../android/support/v4/app/LoaderManager.java | 803 ------- .../v4/app/NoSaveStateFrameLayout.java | 63 - .../v4/app/SuperNotCalledException.java | 27 - .../support/v4/app/SupportActivity.java | 295 --- .../src/android/support/v4/app/Watson.java | 144 ++ .../support/v4/content/AsyncTaskLoader.java | 287 --- .../support/v4/content/CursorLoader.java | 215 -- .../android/support/v4/content/Loader.java | 358 --- .../support/v4/os/ParcelableCompat.java | 48 - .../os/ParcelableCompatCreatorCallbacks.java | 24 - .../v4/os/ParcelableCompatHoneycombMR2.java | 46 - .../android/support/v4/util/DebugUtils.java | 40 - .../android/support/v4/util/LogWriter.java | 72 - .../src/android/support/v4/util/LruCache.java | 323 --- .../android/support/v4/util/TimeUtils.java | 172 -- .../src/android/support/v4/view/Menu.java | 33 - .../src/android/support/v4/view/MenuItem.java | 187 -- .../support/v4/view/MotionEventCompat.java | 180 -- .../v4/view/MotionEventCompatEclair.java | 37 - .../android/support/v4/view/PagerAdapter.java | 138 -- .../src/android/support/v4/view/SubMenu.java | 30 - .../v4/view/VelocityTrackerCompat.java | 92 - .../view/VelocityTrackerCompatHoneycomb.java | 31 - .../v4/view/ViewConfigurationCompat.java | 74 - .../v4/view/ViewConfigurationCompatFroyo.java | 28 - .../android/support/v4/view/ViewPager.java | 996 --------- .../support/v4/widget/CursorAdapter.java | 484 ----- .../support/v4/widget/CursorFilter.java | 71 - .../v4/widget/ResourceCursorAdapter.java | 131 -- .../v4/widget/SimpleCursorAdapter.java | 398 ---- .../actionbarsherlock/ActionBarSherlock.java | 794 +++++++ .../com/actionbarsherlock/app/ActionBar.java | 956 ++++++++ .../app/SherlockActivity.java | 270 +++ .../app/SherlockDialogFragment.java | 68 + .../app/SherlockExpandableListActivity.java | 259 +++ .../app/SherlockFragment.java | 68 + .../app/SherlockFragmentActivity.java | 303 +++ .../app/SherlockListActivity.java | 270 +++ .../app/SherlockListFragment.java | 68 + .../app/SherlockPreferenceActivity.java | 270 +++ .../internal/ActionBarSherlockCompat.java | 1203 +++++++++++ .../internal/ActionBarSherlockNative.java | 336 +++ .../internal/ResourcesCompat.java | 95 + .../internal/app/ActionBarImpl.java | 1044 +++++++-- .../internal/app/ActionBarWrapper.java | 771 +++---- .../nineoldandroids/animation/Animator.java | 278 +++ .../animation/AnimatorListenerAdapter.java | 54 + .../animation/AnimatorSet.java | 1111 ++++++++++ .../animation/FloatEvaluator.java | 42 + .../animation/FloatKeyframeSet.java | 136 ++ .../animation/IntEvaluator.java | 42 + .../animation/IntKeyframeSet.java | 135 ++ .../nineoldandroids/animation/Keyframe.java | 361 ++++ .../animation/KeyframeSet.java | 227 ++ .../animation/ObjectAnimator.java | 491 +++++ .../animation/PropertyValuesHolder.java | 1012 +++++++++ .../animation/TypeEvaluator.java | 44 + .../animation/ValueAnimator.java | 1265 +++++++++++ .../nineoldandroids/view/NineViewGroup.java | 79 + .../view/animation/AnimatorProxy.java | 212 ++ .../widget/NineFrameLayout.java | 57 + .../widget/NineHorizontalScrollView.java | 41 + .../widget/NineLinearLayout.java | 57 + .../internal/view/ActionProviderWrapper.java | 40 + .../internal/view/StandaloneActionMode.java | 148 ++ .../view/View_HasStateListenerSupport.java | 6 + .../View_OnAttachStateChangeListener.java | 8 + .../internal/view/menu/ActionMenu.java | 264 +++ .../internal/view/menu/ActionMenuItem.java | 251 ++- .../view/menu/ActionMenuItemView.java | 304 ++- .../view/menu/ActionMenuPresenter.java | 714 ++++++ .../internal/view/menu/ActionMenuView.java | 575 +++++ .../internal/view/menu/BaseMenuPresenter.java | 231 ++ .../internal/view/menu/ListMenuItemView.java | 278 +++ .../internal/view/menu/MenuBuilder.java | 1743 +++++++++++---- .../view/menu/MenuInflaterWrapper.java | 21 - .../internal/view/menu/MenuItemImpl.java | 1310 ++++++----- .../internal/view/menu/MenuItemWrapper.java | 375 ++-- .../internal/view/menu/MenuPopupHelper.java | 376 ++++ .../internal/view/menu/MenuPresenter.java | 148 ++ .../internal/view/menu/MenuView.java | 29 +- .../internal/view/menu/MenuWrapper.java | 163 +- .../internal/view/menu/SubMenuBuilder.java | 253 ++- .../internal/view/menu/SubMenuWrapper.java | 154 +- .../internal/widget/AbsActionBarView.java | 291 +++ .../internal/widget/ActionBarContainer.java | 237 +- .../internal/widget/ActionBarContextView.java | 518 +++++ .../internal/widget/ActionBarView.java | 1750 +++++++++++---- .../internal/widget/CapitalizingButton.java | 40 + .../internal/widget/CapitalizingTextView.java | 50 + .../widget/CollapsibleActionViewWrapper.java | 30 + .../widget/FakeDialogPhoneWindow.java | 64 + .../internal/widget/IcsAbsSpinner.java | 479 ++++ .../internal/widget/IcsAdapterView.java | 1160 ++++++++++ .../internal/widget/IcsColorDrawable.java | 41 + .../internal/widget/IcsLinearLayout.java | 410 ++++ .../internal/widget/IcsListPopupWindow.java | 644 ++++++ .../internal/widget/IcsProgressBar.java | 1193 ++++++++++ .../internal/widget/IcsSpinner.java | 703 ++++++ .../internal/widget/IcsView.java | 21 + .../widget/ScrollingTabContainerView.java | 546 +++++ .../internal/widget/ScrollingTextView.java | 51 - .../actionbarsherlock}/view/ActionMode.java | 272 ++- .../view/ActionProvider.java | 170 ++ .../view/CollapsibleActionView.java | 39 + .../src/com/actionbarsherlock/view/Menu.java | 447 ++++ .../actionbarsherlock}/view/MenuInflater.java | 365 ++-- .../com/actionbarsherlock/view/MenuItem.java | 598 +++++ .../com/actionbarsherlock/view/SubMenu.java | 110 + .../actionbarsherlock}/view/Window.java | 63 +- .../widget/ActivityChooserModel.java | 1104 ++++++++++ .../widget/ActivityChooserView.java | 827 +++++++ .../actionbarsherlock/widget/SearchView.java | 1811 ++++++++++++++++ .../widget/ShareActionProvider.java | 316 +++ .../widget/SuggestionsAdapter.java | 733 +++++++ .../internal/ManifestParsingTest.java | 37 + .../JakeWharton-ActionBarSherlock/pom.xml | 170 +- .../update-version.py | 40 - 539 files changed, 35840 insertions(+), 17993 deletions(-) create mode 100644 android/res/values-v11/themes.xml create mode 100644 android/res/values-v14/themes.xml create mode 100644 external/JakeWharton-ActionBarSherlock/CONTRIBUTING.md rename external/JakeWharton-ActionBarSherlock/{library => }/checkstyle.xml (88%) delete mode 100644 external/JakeWharton-ActionBarSherlock/library/.settings/org.eclipse.jdt.core.prefs delete mode 100644 external/JakeWharton-ActionBarSherlock/library/default.properties create mode 100644 external/JakeWharton-ActionBarSherlock/library/libs/android-support-v4.jar delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/color/abs__item_bg.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_disable_only_holo_dark.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_disable_only_holo_light.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_holo_dark.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_holo_light.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/color/abs__tab_text_color_dark.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/color/abs__tab_text_color_light.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_solid_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_solid_inverse_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_solid_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_transparent_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_transparent_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_solid_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_solid_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_solid_shadow_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_stacked_solid_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_stacked_solid_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_stacked_transparent_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_stacked_transparent_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_transparent_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_transparent_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__btn_cab_done_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__btn_cab_done_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__btn_cab_done_focused_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__btn_cab_done_focused_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_bottom_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_bottom_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_holo_dark.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_top_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_top_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_ic_close_focused_holo.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_ic_close_normal_holo.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_ic_close_pressed_holo.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__dialog_full_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__dialog_full_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_cab_done_holo_dark.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_cab_done_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_disabled.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_normal.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_search_api_disabled_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_go.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_go_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_share_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_search.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_voice_search.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_voice_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_activated_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_divider_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_divider_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__menu_dropdown_panel_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__menu_dropdown_panel_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_bg_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_bg_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_primary_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_primary_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_secondary_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_secondary_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_48_inner_holo.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_48_outer_holo.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_disabled_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_disabled_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_focused_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_focused_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_pressed_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_pressed_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_default_holo_dark.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_default_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_disabled_holo_dark.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_disabled_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_focused_holo_dark.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_focused_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_pressed_holo_dark.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_pressed_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_selected_pressed_focused_holo.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_unselected_focused_holo.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_unselected_holo.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_unselected_pressed_focused_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_selected_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_selected_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_selected_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_selected_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_bottom_solid_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_bottom_solid_inverse_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_bottom_solid_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_bottom_transparent_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_bottom_transparent_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_solid_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_solid_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_solid_shadow_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_solid_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_solid_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_transparent_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_transparent_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_transparent_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_transparent_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_focused_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_focused_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__cab_background_bottom_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__cab_background_bottom_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__cab_background_holo_dark.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__cab_background_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__cab_background_top_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__cab_background_top_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__cab_ic_close_focused_holo.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__cab_ic_close_normal_holo.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__cab_ic_close_pressed_holo.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__dialog_full_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_cab_done_holo_dark.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_cab_done_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_clear_disabled.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_clear_normal.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_clear_search_api_disabled_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_clear_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_go.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_go_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_menu_share_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_search.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_voice_search.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_voice_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_activated_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_divider_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_divider_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__menu_dropdown_panel_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__menu_dropdown_panel_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__progress_bg_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__progress_bg_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__progress_primary_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__progress_primary_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__progress_secondary_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__progress_secondary_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_48_inner_holo.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_48_outer_holo.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_disabled_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_disabled_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_focused_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_focused_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_pressed_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_pressed_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_default_holo_dark.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_default_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_disabled_holo_dark.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_disabled_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_focused_holo_dark.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_focused_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_pressed_holo_dark.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_pressed_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_selected_pressed_focused_holo.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_unselected_focused_holo.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_unselected_holo.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_unselected_pressed_focused_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_selected_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_selected_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_selected_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_selected_holo_light.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-nodpi-v11/abs__action_item_divider.9.png delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-nodpi/abs__action_item_divider.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-v11/abs__progress_medium_holo.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_bottom_solid_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_bottom_solid_inverse_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_bottom_solid_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_bottom_transparent_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_bottom_transparent_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_solid_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_solid_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_solid_shadow_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_solid_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_solid_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_transparent_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_transparent_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_transparent_dark_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_transparent_light_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__cab_background_bottom_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__cab_background_bottom_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__cab_background_top_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__cab_background_top_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_ab_back_holo_dark.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_ab_back_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_cab_done_holo_dark.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_cab_done_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_clear_disabled.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_clear_search_api_disabled_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_clear_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_go.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_go_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_search.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_voice_search.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_voice_search_api_holo_light.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_activated_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_divider_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_divider_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_focused_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_longpressed_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_pressed_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_pressed_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_selector_disabled_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_selector_disabled_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_bg_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_bg_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_primary_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_primary_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_secondary_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_secondary_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_48_inner_holo.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_48_outer_holo.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_focused_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_focused_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__tab_selected_focused_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__tab_selected_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__tab_selected_pressed_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__tab_unselected_pressed_holo.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_right_default_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_right_default_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_right_selected_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_right_selected_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_selected_holo_dark.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_selected_holo_light.9.png create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__activated_background_holo_dark.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__activated_background_holo_light.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__btn_cab_done_holo_dark.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__btn_cab_done_holo_light.xml rename external/JakeWharton-ActionBarSherlock/library/res/{layout-large-land/abs__screen_action_bar_overlay.xml => drawable/abs__ic_clear.xml} (71%) rename external/JakeWharton-ActionBarSherlock/library/res/drawable/{abs__cab_ic_close_holo.xml => abs__ic_clear_holo_light.xml} (71%) rename external/JakeWharton-ActionBarSherlock/library/res/{layout-large-land/abs__screen_action_bar.xml => drawable/abs__ic_menu_moreoverflow_holo_dark.xml} (77%) rename external/JakeWharton-ActionBarSherlock/library/res/{layout-xlarge/abs__action_bar.xml => drawable/abs__ic_menu_moreoverflow_holo_light.xml} (73%) create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__list_selector_holo_dark.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__list_selector_holo_light.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_horizontal_holo_dark.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_horizontal_holo_light.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_medium_holo.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__search_dropdown_dark.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__search_dropdown_light.xml rename external/JakeWharton-ActionBarSherlock/library/res/drawable/{abs__spinner_background_holo_dark.xml => abs__spinner_ab_holo_dark.xml} (70%) rename external/JakeWharton-ActionBarSherlock/library/res/drawable/{abs__spinner_background_holo_light.xml => abs__spinner_ab_holo_light.xml} (74%) rename external/JakeWharton-ActionBarSherlock/library/res/drawable/{abs__tab_indicator_holo.xml => abs__tab_indicator_ab_holo.xml} (85%) create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_holo_dark.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_holo_light.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_right_holo_dark.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_right_holo_light.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout-large/abs__action_mode_close_item.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout-v14/sherlock_spinner_dropdown_item.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout-v14/sherlock_spinner_item.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_inline.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_item_layout.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab_bar_view.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab_layout.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_menu_item_layout.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_menu_layout.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_mode_bar.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_mode_close_item.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__activity_chooser_view.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__activity_chooser_view_list_item.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__dialog_title_holo.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_checkbox.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_icon.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_layout.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_radio.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__popup_menu_item_layout.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_inline.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_inline_overlay.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_simple_overlay_action_mode.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__search_dropdown_item_icons_2line.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__search_view.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/abs__simple_dropdown_hint.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/layout/sherlock_spinner_dropdown_item.xml rename external/JakeWharton-ActionBarSherlock/library/res/layout/{abs__simple_spinner_item.xml => sherlock_spinner_item.xml} (96%) delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-land/abs__constants.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-land/abs__dimens.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-large-hdpi-1024x600/abs__dimens.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-large-land-hdpi-1024x600/abs__dimens.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-large-land-mdpi-1024x600/abs__dimens.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-large-mdpi-1024x600/abs__dimens.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-large/abs__dimens.xml rename external/JakeWharton-ActionBarSherlock/library/res/{layout-large-land/abs__action_bar.xml => values-sw600dp/abs__bools.xml} (75%) create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-sw600dp/abs__dimens.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-v11/abs__styles.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-v11/abs__themes.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-v13/abs__styles.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-v14/abs__styles.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-v14/abs__themes.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-w360dp/abs__dimens.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-w480dp/abs__bools.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-w480dp/abs__config.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-w500dp/abs__dimens.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-w600dp/abs__dimens.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values-xlarge/abs__dimens.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values/abs__bools.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values/abs__colors.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values/abs__config.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values/abs__constants.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values/abs__dimens.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values/abs__ids.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values/abs__strings.xml create mode 100644 external/JakeWharton-ActionBarSherlock/library/res/values/abs__themes.xml delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/ActionBar.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/BackStackRecord.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/DialogFragment.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/Fragment.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentActivity.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentManager.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentPagerAdapter.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentStatePagerAdapter.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentTransaction.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/HCSparseArray.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/ListFragment.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/LoaderManager.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/NoSaveStateFrameLayout.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/SuperNotCalledException.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/SupportActivity.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/Watson.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/AsyncTaskLoader.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/CursorLoader.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/Loader.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompat.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompatCreatorCallbacks.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompatHoneycombMR2.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/DebugUtils.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/LogWriter.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/LruCache.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/TimeUtils.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/Menu.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MenuItem.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MotionEventCompat.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MotionEventCompatEclair.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/PagerAdapter.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/SubMenu.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/VelocityTrackerCompat.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/VelocityTrackerCompatHoneycomb.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewConfigurationCompat.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewConfigurationCompatFroyo.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewPager.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/CursorAdapter.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/CursorFilter.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/ResourceCursorAdapter.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/SimpleCursorAdapter.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/ActionBarSherlock.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/ActionBar.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockActivity.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockDialogFragment.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockExpandableListActivity.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockFragment.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockFragmentActivity.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockListActivity.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockListFragment.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockPreferenceActivity.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ResourcesCompat.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/Animator.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorListenerAdapter.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatEvaluator.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatKeyframeSet.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntEvaluator.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntKeyframeSet.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/KeyframeSet.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/ObjectAnimator.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/TypeEvaluator.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/ActionProviderWrapper.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/StandaloneActionMode.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/View_HasStateListenerSupport.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/View_OnAttachStateChangeListener.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenu.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ListMenuItemView.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuInflaterWrapper.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuPopupHelper.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuPresenter.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/AbsActionBarView.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarContextView.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CapitalizingButton.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CollapsibleActionViewWrapper.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/FakeDialogPhoneWindow.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsAbsSpinner.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsColorDrawable.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsProgressBar.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsSpinner.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsView.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java delete mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ScrollingTextView.java rename external/JakeWharton-ActionBarSherlock/library/src/{android/support/v4 => com/actionbarsherlock}/view/ActionMode.java (52%) create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/ActionProvider.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/CollapsibleActionView.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/Menu.java rename external/JakeWharton-ActionBarSherlock/library/src/{android/support/v4 => com/actionbarsherlock}/view/MenuInflater.java (50%) create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/MenuItem.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/SubMenu.java rename external/JakeWharton-ActionBarSherlock/library/src/{android/support/v4 => com/actionbarsherlock}/view/Window.java (51%) create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ActivityChooserModel.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ActivityChooserView.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/SearchView.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ShareActionProvider.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/SuggestionsAdapter.java create mode 100644 external/JakeWharton-ActionBarSherlock/library/test/com/actionbarsherlock/internal/ManifestParsingTest.java delete mode 100755 external/JakeWharton-ActionBarSherlock/update-version.py diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 115bc4f4..38125faf 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -22,7 +22,7 @@ android:versionCode="154" android:installLocation="auto"> - + @@ -36,6 +36,7 @@ android:label="Transdroid Torrent Manager" android:description="@string/description" android:theme="@style/Theme.Transdroid" + android:logo="@drawable/pixel" android:hardwareAccelerated="false"> + + + + + \ No newline at end of file diff --git a/android/res/values-v14/themes.xml b/android/res/values-v14/themes.xml new file mode 100644 index 00000000..fb09dbdd --- /dev/null +++ b/android/res/values-v14/themes.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/android/res/values/themes.xml b/android/res/values/themes.xml index b83dc756..936edc41 100644 --- a/android/res/values/themes.xml +++ b/android/res/values/themes.xml @@ -1,15 +1,17 @@ - + + \ No newline at end of file diff --git a/android/src/org/transdroid/gui/Details.java b/android/src/org/transdroid/gui/Details.java index cf355b21..79731ec4 100644 --- a/android/src/org/transdroid/gui/Details.java +++ b/android/src/org/transdroid/gui/Details.java @@ -22,10 +22,11 @@ import org.transdroid.daemon.Torrent; import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; -public class Details extends FragmentActivity { +import com.actionbarsherlock.app.SherlockFragmentActivity; + +public class Details extends SherlockFragmentActivity { //private static final String LOG_NAME = "Details"; diff --git a/android/src/org/transdroid/gui/DetailsFragment.java b/android/src/org/transdroid/gui/DetailsFragment.java index 78a2a45d..54be2007 100644 --- a/android/src/org/transdroid/gui/DetailsFragment.java +++ b/android/src/org/transdroid/gui/DetailsFragment.java @@ -42,6 +42,7 @@ import org.transdroid.gui.util.SelectableArrayAdapter.OnSelectedChangedListener; import org.transdroid.preferences.Preferences; import org.transdroid.util.TLog; +import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; @@ -50,27 +51,29 @@ import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; -import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuItem; import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; -import android.view.MenuInflater; import android.view.View; -import android.view.ViewGroup; -import android.view.ContextMenu.ContextMenuInfo; import android.view.View.OnClickListener; +import android.view.ViewGroup; import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.Toast; -import android.widget.AdapterView.AdapterContextMenuInfo; -import android.widget.AdapterView.OnItemClickListener; -public class DetailsFragment extends Fragment implements IDaemonCallback, OnSelectedChangedListener { +import com.actionbarsherlock.app.SherlockFragment; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +@SuppressLint("ValidFragment") +public class DetailsFragment extends SherlockFragment implements IDaemonCallback, OnSelectedChangedListener { private static final String LOG_NAME = "Details fragment"; @@ -172,7 +175,7 @@ public class DetailsFragment extends Fragment implements IDaemonCallback, OnSele // Show the torrent details getListView().setAdapter(new DetailsListAdapter(this, torrent, fineDetails)); - getSupportActivity().setTitle(torrent.getName()); + getSherlockActivity().setTitle(torrent.getName()); if (Daemon.supportsFileListing(daemon.getType())) { @@ -675,11 +678,11 @@ public class DetailsFragment extends Fragment implements IDaemonCallback, OnSele } // Close this details fragment if (torrentsFragment != null) { - FragmentTransaction ft = getSupportActivity().getSupportFragmentManager().beginTransaction(); + FragmentTransaction ft = getSherlockActivity().getSupportFragmentManager().beginTransaction(); ft.remove(this); ft.commit(); } else { - getSupportActivity().getSupportFragmentManager().popBackStack(); + getSherlockActivity().getSupportFragmentManager().popBackStack(); } break; @@ -804,14 +807,14 @@ public class DetailsFragment extends Fragment implements IDaemonCallback, OnSele } public void showDialog(int id) { - new DialogWrapper(onCreateDialog(id)).show(getSupportActivity().getSupportFragmentManager(), DialogWrapper.TAG + new DialogWrapper(onCreateDialog(id)).show(getSherlockActivity().getSupportFragmentManager(), DialogWrapper.TAG + id); } protected void dismissDialog(int id) { // Remove the dialog wrapper fragment for the dialog's ID - getSupportActivity().getSupportFragmentManager().beginTransaction().remove( - getSupportActivity().getSupportFragmentManager().findFragmentByTag(DialogWrapper.TAG + id)).commit(); + getSherlockActivity().getSupportFragmentManager().beginTransaction().remove( + getSherlockActivity().getSupportFragmentManager().findFragmentByTag(DialogWrapper.TAG + id)).commit(); } } diff --git a/android/src/org/transdroid/gui/Torrents.java b/android/src/org/transdroid/gui/Torrents.java index 3a7a8a19..2f6f9a1b 100644 --- a/android/src/org/transdroid/gui/Torrents.java +++ b/android/src/org/transdroid/gui/Torrents.java @@ -21,17 +21,18 @@ import org.transdroid.R; import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.ActionBar; -import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.SherlockFragmentActivity; + /** * Activity that loads the torrents fragment and, on tablet interfaces, hosts * the details fragment. * * @author erickok */ -public class Torrents extends FragmentActivity { +public class Torrents extends SherlockFragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { diff --git a/android/src/org/transdroid/gui/TorrentsFragment.java b/android/src/org/transdroid/gui/TorrentsFragment.java index 513938ac..d92653b7 100644 --- a/android/src/org/transdroid/gui/TorrentsFragment.java +++ b/android/src/org/transdroid/gui/TorrentsFragment.java @@ -92,18 +92,13 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; -import android.support.v4.app.ActionBar.OnNavigationListener; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuItem; -import android.support.v4.view.SubMenu; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.LayoutInflater; -import android.view.MenuInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; @@ -123,6 +118,13 @@ import android.widget.TableLayout; import android.widget.TextView; import android.widget.Toast; +import com.actionbarsherlock.app.ActionBar.OnNavigationListener; +import com.actionbarsherlock.app.SherlockFragment; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; + /** * The main screen for the Transdroid application and provides most on-the-surface functionality * as well. Server daemon and search engine communication is wrapped in adapters. @@ -130,7 +132,7 @@ import android.widget.Toast; * @author erickok * */ -public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTouchListener { +public class TorrentsFragment extends SherlockFragment implements IDaemonCallback, OnTouchListener { private static final String LOG_NAME = "Main"; @@ -468,7 +470,7 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou // Update the navigation list of the action bar ignoreFirstListNavigation = true; - getSupportActivity().getSupportActionBar().setListNavigationCallbacks(buildServerListAdapter(), onServerChanged ); + getSherlockActivity().getSupportActionBar().setListNavigationCallbacks(buildServerListAdapter(), onServerChanged ); } @@ -485,7 +487,7 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou // Show which server configuration is currently active ignoreFirstListNavigation = true; - getSupportActivity().getSupportActionBar().setSelectedNavigationItem(lastUsedDaemonSettings); + getSherlockActivity().getSupportActionBar().setSelectedNavigationItem(lastUsedDaemonSettings); // Show the control bar startsettings.setVisibility(View.GONE); @@ -493,7 +495,7 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou statusBox.setVisibility(View.GONE); activeLabel = null; inAlternativeMode = false; // TODO: Actually this should be retrieved from the server's session - getSupportActivity().invalidateOptionsMenu(); + getSherlockActivity().supportInvalidateOptionsMenu(); } else { @@ -504,7 +506,7 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou // Show that no server configuration is currently active ignoreFirstListNavigation = true; - getSupportActivity().getSupportActionBar().setListNavigationCallbacks(null, onServerChanged); + getSherlockActivity().getSupportActionBar().setListNavigationCallbacks(null, onServerChanged); statusBox.setVisibility(View.GONE); viewtype.setText(""); @@ -512,7 +514,7 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou startsettings.setVisibility(View.VISIBLE); controlbar.setVisibility(View.GONE); activeLabel = null; - getSupportActivity().invalidateOptionsMenu(); + getSherlockActivity().supportInvalidateOptionsMenu(); } @@ -790,7 +792,7 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou } @Override - public boolean onOptionsItemSelected(android.support.v4.view.MenuItem item) { + public boolean onOptionsItemSelected(MenuItem item) { // Check connection first (when not opening the settings) if (item.getItemId() != MENU_SETTINGS_ID && @@ -815,7 +817,7 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou break; case MENU_SEARCH_ID: - getSupportActivity().onSearchRequested(); + getSherlockActivity().onSearchRequested(); break; case MENU_ALTMODE_ID: @@ -1009,7 +1011,7 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou // Show the details in the right of the screen (tablet interface) or separately if (useTabletInterface) { - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + FragmentTransaction ft = getSherlockActivity().getSupportFragmentManager().beginTransaction(); ft.replace(R.id.details, new DetailsFragment(TorrentsFragment.this, lastUsedDaemonSettings, tor, buildLabelTexts(false))); ft.commit(); @@ -1429,9 +1431,9 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou private void refreshActivity() { updateTorrentList(); - if (getSupportFragmentManager().findFragmentById(R.id.details) != null) { + if (getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.details) != null) { // Marshal the refresh button click to the fragment - ((DetailsFragment)getSupportFragmentManager().findFragmentById(R.id.details)).refreshActivity(); + ((DetailsFragment)getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.details)).refreshActivity(); } } @@ -1855,7 +1857,7 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou private void updateAlternativeModeIcon() { // By invalidation the options menu it gets redrawn and the turtle icon gets updated - getSupportActivity().invalidateOptionsMenu(); + getSherlockActivity().supportInvalidateOptionsMenu(); } /** @@ -1987,9 +1989,9 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou // Clear the old details fragment if (useTabletInterface) { - Fragment f = getSupportFragmentManager().findFragmentById(R.id.details); + Fragment f = getSherlockActivity().getSupportFragmentManager().findFragmentById(R.id.details); if (f != null) { - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + FragmentTransaction ft = getSherlockActivity().getSupportFragmentManager().beginTransaction(); ft.remove(f); ft.commit(); } @@ -2118,8 +2120,8 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou private void setProgressBar(boolean b) { inProgress = b; - if (getSupportActivity() != null) - getSupportActivity().invalidateOptionsMenu(); + if (getSherlockActivity() != null) + getSherlockActivity().supportInvalidateOptionsMenu(); } protected View findViewById(int id) { @@ -2154,13 +2156,13 @@ public class TorrentsFragment extends Fragment implements IDaemonCallback, OnTou } public void showDialog(int id) { - new DialogWrapper(onCreateDialog(id)).show(getSupportActivity().getSupportFragmentManager(), DialogWrapper.TAG + id); + new DialogWrapper(onCreateDialog(id)).show(getSherlockActivity().getSupportFragmentManager(), DialogWrapper.TAG + id); } protected void dismissDialog(int id) { // Remove the dialog wrapper fragment for the dialog's ID - getSupportActivity().getSupportFragmentManager().beginTransaction().remove( - getSupportActivity().getSupportFragmentManager().findFragmentByTag(DialogWrapper.TAG + id)).commit(); + getSherlockActivity().getSupportFragmentManager().beginTransaction().remove( + getSherlockActivity().getSupportFragmentManager().findFragmentByTag(DialogWrapper.TAG + id)).commit(); } /** diff --git a/android/src/org/transdroid/gui/rss/RssFeeds.java b/android/src/org/transdroid/gui/rss/RssFeeds.java index 0bce4852..82b9e0b4 100644 --- a/android/src/org/transdroid/gui/rss/RssFeeds.java +++ b/android/src/org/transdroid/gui/rss/RssFeeds.java @@ -20,10 +20,11 @@ import org.transdroid.R; import android.os.Bundle; -import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; -public class RssFeeds extends FragmentActivity { +import com.actionbarsherlock.app.SherlockFragmentActivity; + +public class RssFeeds extends SherlockFragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { diff --git a/android/src/org/transdroid/gui/rss/RssFeedsFragment.java b/android/src/org/transdroid/gui/rss/RssFeedsFragment.java index 57d9ddd1..b1c51958 100644 --- a/android/src/org/transdroid/gui/rss/RssFeedsFragment.java +++ b/android/src/org/transdroid/gui/rss/RssFeedsFragment.java @@ -25,23 +25,25 @@ import org.transdroid.preferences.Preferences; import org.transdroid.preferences.PreferencesRss; import org.transdroid.rss.RssFeedSettings; +import com.actionbarsherlock.app.SherlockFragment; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuItem; import android.view.LayoutInflater; -import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ListView; import android.widget.AdapterView.OnItemClickListener; -public class RssFeedsFragment extends Fragment { +public class RssFeedsFragment extends SherlockFragment { // private static final String LOG_NAME = "Transdroid RSS feeds"; @@ -69,10 +71,10 @@ public class RssFeedsFragment extends Fragment { useTabletInterface = Transdroid.isTablet(getResources()); registerForContextMenu(getView().findViewById(android.R.id.list)); - getSupportActivity().getSupportActionBar().setTitle(R.string.rss); + getSherlockActivity().getSupportActionBar().setTitle(R.string.rss); getListView().setOnItemClickListener(onFeedClicked); - getSupportActivity().setTitle(R.string.rss); + getSherlockActivity().setTitle(R.string.rss); loadFeeds(); @@ -107,7 +109,7 @@ public class RssFeedsFragment extends Fragment { // Show the feed items in the right of the screen (tablet interface) or separately if (useTabletInterface) { - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + FragmentTransaction ft = getSherlockActivity().getSupportFragmentManager().beginTransaction(); ft.replace(R.id.listing, new RssListingFragment(getListAdapter().getItem(position))); ft.commit(); } else { @@ -122,7 +124,7 @@ public class RssFeedsFragment extends Fragment { }; @Override - public boolean onOptionsItemSelected(android.support.v4.view.MenuItem item) { + public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_REFRESH_ID: loadFeeds(); diff --git a/android/src/org/transdroid/gui/rss/RssListing.java b/android/src/org/transdroid/gui/rss/RssListing.java index 4da82117..529487ea 100644 --- a/android/src/org/transdroid/gui/rss/RssListing.java +++ b/android/src/org/transdroid/gui/rss/RssListing.java @@ -21,13 +21,15 @@ import org.transdroid.R; import org.transdroid.preferences.Preferences; import org.transdroid.rss.RssFeedSettings; +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.SherlockFragmentActivity; + import android.os.Bundle; import android.preference.PreferenceManager; -import android.support.v4.app.ActionBar; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; -public class RssListing extends FragmentActivity { +public class RssListing extends SherlockFragmentActivity { public static final String RSSFEED_LISTING_KEY = "RSSFEED_LISTING_KEY"; diff --git a/android/src/org/transdroid/gui/rss/RssListingFragment.java b/android/src/org/transdroid/gui/rss/RssListingFragment.java index 9c870836..4380dd44 100644 --- a/android/src/org/transdroid/gui/rss/RssListingFragment.java +++ b/android/src/org/transdroid/gui/rss/RssListingFragment.java @@ -33,6 +33,7 @@ import org.transdroid.preferences.Preferences; import org.transdroid.rss.RssFeedSettings; import org.transdroid.util.TLog; +import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; import android.app.SearchManager; @@ -44,17 +45,12 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.preference.PreferenceManager; -import android.support.v4.app.ActionBar.OnNavigationListener; -import android.support.v4.app.Fragment; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuItem; import android.text.Html; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.LayoutInflater; -import android.view.MenuInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; @@ -71,7 +67,14 @@ import android.widget.SpinnerAdapter; import android.widget.TextView; import android.widget.Toast; -public class RssListingFragment extends Fragment implements OnTouchListener, OnSelectedChangedListener { +import com.actionbarsherlock.app.ActionBar.OnNavigationListener; +import com.actionbarsherlock.app.SherlockFragment; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +@SuppressLint("ValidFragment") +public class RssListingFragment extends SherlockFragment implements OnTouchListener, OnSelectedChangedListener { private static final String LOG_NAME = "RSS listing"; @@ -121,14 +124,14 @@ public class RssListingFragment extends Fragment implements OnTouchListener, OnS addSelectedButton.setOnClickListener(addSelectedClicked); // Swiping or flinging between server configurations gestureDetector = new GestureDetector(new RssScreenGestureListener()); - getSupportActivity().getSupportActionBar().setTitle(R.string.rss); + getSherlockActivity().getSupportActionBar().setTitle(R.string.rss); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity()); allFeeds = Preferences.readAllRssFeedSettings(prefs); ignoreFirstListNavigation = true; if (getActivity() instanceof RssListing) { - getSupportActivity().getSupportActionBar().setListNavigationCallbacks(buildFeedsAdapter(), onFeedSelected); + getSherlockActivity().getSupportActionBar().setListNavigationCallbacks(buildFeedsAdapter(), onFeedSelected); } if (lastLoadedItems == null || feedSettings == null) { // Start loading the items @@ -136,7 +139,7 @@ public class RssListingFragment extends Fragment implements OnTouchListener, OnS } else { // Set items from the retained instance state if (getActivity() instanceof RssListing) { - getSupportActivity().getSupportActionBar().setSelectedNavigationItem(feedSettingsIndex(feedSettings)); + getSherlockActivity().getSupportActionBar().setSelectedNavigationItem(feedSettingsIndex(feedSettings)); setListAdapter(new RssItemListAdapter(getActivity(), RssListingFragment.this, lastLoadedItems, true, feedSettings.getLastNew())); } } @@ -169,7 +172,7 @@ public class RssListingFragment extends Fragment implements OnTouchListener, OnS // Show the (newly) selected feed if (getActivity() instanceof RssListing && feedSettings.getName() != null && !feedSettings.getName().equals("")) { ignoreFirstListNavigation = true; - getSupportActivity().getSupportActionBar().setSelectedNavigationItem(feedSettingsIndex(feedSettings)); + getSherlockActivity().getSupportActionBar().setSelectedNavigationItem(feedSettingsIndex(feedSettings)); } // Read the RSS items asynchronously @@ -326,7 +329,7 @@ public class RssListingFragment extends Fragment implements OnTouchListener, OnS }; @Override - public boolean onOptionsItemSelected(android.support.v4.view.MenuItem item) { + public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_REFRESH_ID: loadItems(); @@ -456,7 +459,7 @@ public class RssListingFragment extends Fragment implements OnTouchListener, OnS // Create a result for the calling activity //setResult(RESULT_OK); startActivity(i); - getSupportFragmentManager().popBackStack(); + getSherlockActivity().getSupportFragmentManager().popBackStack(); } else { @@ -487,7 +490,7 @@ public class RssListingFragment extends Fragment implements OnTouchListener, OnS // Create a result for the calling activity //setResult(RESULT_OK); startActivity(i); - getSupportFragmentManager().popBackStack(); + getSherlockActivity().getSupportFragmentManager().popBackStack(); } else { @@ -501,8 +504,8 @@ public class RssListingFragment extends Fragment implements OnTouchListener, OnS private void setProgressBar(boolean b) { inProgress = b; - if (getSupportActivity() != null) { - getSupportActivity().invalidateOptionsMenu(); + if (getSherlockActivity() != null) { + getSherlockActivity().supportInvalidateOptionsMenu(); } } @@ -591,13 +594,13 @@ public class RssListingFragment extends Fragment implements OnTouchListener, OnS }; public void showDialog(int id) { - new DialogWrapper(onCreateDialog(id)).show(getSupportActivity().getSupportFragmentManager(), DialogWrapper.TAG + id); + new DialogWrapper(onCreateDialog(id)).show(getSherlockActivity().getSupportFragmentManager(), DialogWrapper.TAG + id); } protected void dismissDialog(int id) { // Remove the dialog wrapper fragment for the dialog's ID - getSupportActivity().getSupportFragmentManager().beginTransaction().remove( - getSupportActivity().getSupportFragmentManager().findFragmentByTag(DialogWrapper.TAG + id)).commit(); + getSherlockActivity().getSupportFragmentManager().beginTransaction().remove( + getSherlockActivity().getSupportFragmentManager().findFragmentByTag(DialogWrapper.TAG + id)).commit(); } protected ListView getListView() { diff --git a/android/src/org/transdroid/gui/search/Search.java b/android/src/org/transdroid/gui/search/Search.java index 0a07d046..d136821d 100644 --- a/android/src/org/transdroid/gui/search/Search.java +++ b/android/src/org/transdroid/gui/search/Search.java @@ -30,6 +30,12 @@ import org.transdroid.gui.util.SelectableArrayAdapter.OnSelectedChangedListener; import org.transdroid.preferences.Preferences; import org.transdroid.util.TLog; +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.ActionBar.OnNavigationListener; +import com.actionbarsherlock.app.SherlockFragmentActivity; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; + import android.app.AlertDialog; import android.app.Dialog; import android.app.SearchManager; @@ -42,11 +48,7 @@ import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; import android.provider.SearchRecentSuggestions; -import android.support.v4.app.ActionBar; -import android.support.v4.app.ActionBar.OnNavigationListener; import android.support.v4.app.FragmentActivity; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuItem; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.GestureDetector; @@ -76,7 +78,7 @@ import android.widget.Toast; * @author erickok * */ -public class Search extends FragmentActivity implements OnTouchListener, OnSelectedChangedListener { +public class Search extends SherlockFragmentActivity implements OnTouchListener, OnSelectedChangedListener { private static final String LOG_NAME = "Search"; private final static Uri TTS_MARKET_URI = Uri.parse("http://www.transdroid.org/latest-search"); diff --git a/external/JakeWharton-ActionBarSherlock/CHANGELOG.md b/external/JakeWharton-ActionBarSherlock/CHANGELOG.md index 5fd4fe28..432230bf 100644 --- a/external/JakeWharton-ActionBarSherlock/CHANGELOG.md +++ b/external/JakeWharton-ActionBarSherlock/CHANGELOG.md @@ -1,6 +1,196 @@ Change Log =============================================================================== +Version 4.2.0 *(2012-10-07)* +---------------------------- + +**Maven `artifactId` is now to 'actionbarsherlock'.** + +Note: The `.Dialog` themes are now deprecated. These will be removed in a future +version of the library. + + * Add `SearchView` widget for standard search interaction (API 8+ only) + * Fix: `ShareActionProvider` in the split action bar no longer fills the entire + screen. + * Fix: `ShareActionProvider` now does file I/O on a background thread. + * Fix: Automatically correct `ColorDrawable` not respecting bounds when used as + a stacked background. + * Fix: Ensure fragments collection is present before dispatching events. + * Fix: XML-defined `onClick` searches the correct context for the declared + method. + * Fix: Ensure action mode start/finish callbacks are invoked on the activity + for the native action bar. + * Fix: Allow tab callbacks to have a fragment transaction instance for any + `FragmentActivity`. + * Fix: Ensure `CollapsibleActionView` callbacks are dispatched in both native + and compatbility action bars. + * Fix: Remove `.ForceOverflow` themes. These never should have been included. + + +Version 4.1.0 *(2012-05-17)* +---------------------------- + + * Fix: Altered technique used for menu event dispatching through the fragment + manager for greater control. + * Fix: Do not dispatch menu creation event if the activity has been destroyed. + * Fix: Correct potential `NullPointerException` when expanding an action item. + * Fix: Correct potential `NullPointerException` when the hardware menu key was + pressed in an activity that is forcing the overflow menu. + * Fix: Do not set a listener on the native action bar tab wrapper unless a + compatibility listener has been set. + * Fix: Ensure the compatibility animation framework is always available on + views even if they were previously detached from the view hierarchy. + + +Version 4.0.2 *(2012-04-15)* +---------------------------- + + * Upgrade to r7 support library. + * Fix: Do not trigger menu creation after `onCreate` if activity is finishing. + * Fix: Prevent overflow from displaying if there are no overflow action items. + * Fix: Long-pressing menu key no longer triggers overflow. + * Fix: Use proper tab state-list drawable to mimic ICS. + * Fix: Ensure dispatching menu creation and preparation to fragments can + properly return `false` when appropriate to avoid rendering artifacts. + * Fix: Properly save and fetch action mode tag on ICS. + * Fix: Add missing density-specific resources for certain asssets and remove + unused assets. + + +Version 4.0.1 *(2012-03-25)* +---------------------------- + + * Add `ShareActionProvider` widget for use as action items. + * Re-add 'Styled' sample to provide a more comprehensive theming example. + * Fix: Do not dispatch options item selection to fragments if the activity + handles the callback. + * Fix: Prevent menu key from opening the overflow menu when an action mode is + currently displayed. + * Fix: Ensure fragment transaction instance is not `null` on initial tab + selection callback. + * Fix: Displaying an action mode while using stacked tab navigation no longer + throws an exception. + * Fix: Using expandable action item callbacks no longer results in a possible + exception on older devices. + + +Version 4.0.0 *(2012-03-07)* +---------------------------- + +Complete rewrite of the library to backport the Android 4.0 action bar. + + * The minimum supported version of Android is now 2.1 (API 7). + * New base activities are provided (e.g., `SherlockActivity` and + `SherlockFragmentActivity`) which extend from the native activities. + * The support library sources are no longer included in the library. You must + include `android-support-v4.jar` in your project separately. + * Theming now mirrors that of the native action bar through the use of multiple + styles rather than through `ab`- and `am`-prefixed attributes in the theme. + * The action bar can be statically attached to an activity view without the + requirement of using one of the provided base activities. + + +Version 3.5.1 *(2012-01-03)* +---------------------------- + + * Fix: `NullPointerException` in `FragmentManager` can no longer occur when an + attempt is being made to save to a `Bundle` that has not yet been created. + * Fix: Pre-3.0 action item submenu dialogs now properly dismiss themselves when + an item of theirs is selected. + + +Version 3.5.0 *(2011-12-18)* +---------------------------- + + * Library now uses the `r6` version of the compatibility library for its base. + Ice Cream Sandwich-specific implementations are currently disabled, however, + but will be added in a future version of the library. + + `MenuCompat`, `MenuItemCompat`, and `ActivityCompat` have be added back in + to ease transition to this library but all their methods and the classes + themselves have been deprecated. + * Rewritten menu and action item support from Ice Cream Sandwich. + + * Removed the need for the custom `Window.FEATURE_ACTION_ITEM_TEXT` flag. + You should now use the `showAsAction` attribute and/or the + `setShowAsAction(int)` method on each `MenuItem` to control whether or + not text is shown + * Action item dividers are now added automatically only when necessary + to distinguish possible confusion between action items. + * Fix: Action views now properly size themselves within the bounded space + of the menu. + + * Fix: List navigation no longer becomes unusable on certain device + configurations. + * Fix: `SubMenu`'s `findItem(int)` method now properly returns the support + version of `MenuItem`. + * Fix: Invisible sub-menu items are no longer shown on the pre-3.0 popup list. + + +Version 3.4.2 *(2001-11-09)* +---------------------------- + + * Fix: Stacked action bar now properly sets the tab bar background based on + the theme. + + +Version 3.4.1 *(2011-11-09)* +---------------------------- + + * The `makeFragmentName` method in `FragmentPagerAdapter` has been changed to + `public` scope to allow for easier access to your fragments that it is + managing. + * Action bar will now animate when calling `show()` or `hide()`. + * `SherlockPreferenceActivity` now provides full fragment and loader support. + * Examples for the plugins are now in their own sample application. + * Fix: Home icon no longer erroneously clipped when it exceeds the size of the + action bar. + * Fix: Tabs will now scroll horizontally to mimic the native action bar + behavior. + * Fix: Plugins now properly DO NOT inline their `R.java` integer constants. + * Fix: Tabs below the action bar are now styled with a default background so + that they do not incorrectly inherit an applied background unless explicity + declared. + + +Version 3.4.0 *(2011-10-30)* +---------------------------- + + * Library now uses the `r4` version of the compatibility library for its base. + Ice Cream Sandwich-specific implementations are currently disabled, however, + but will be added in a future version of the library. + * Context menu callbacks now use the support version of `MenuItem` to maintain + consistency. + * Added preference plugin which provides an action bar enhanced preference + screen. + * Fix: `abHomeLayout` theme attribute is now honored. + * Fix: `onPrepareOptionsMenu` is now properly dispatched upon menu + invalidation. + + +Version 3.3.1 *(2011-10-20)* +---------------------------- + +ADT 14 is now required. Maven 3 is required if building from the command line. + + * XML-defined `onClick` attributes will now check for an `onClick` method that + takes an `android.support.v4.view.MenuItem` instance. + * Tabs on medium screens in landscape now display inline rather than below the + action bar to mirror how Android 4.0 behaves with the same configuration. + * Fix: Menu inflater properly checks activity context for `onClick` method + declared in the XML. + * Fix: Dialog fragment properly saves its `showDialog` state when not being + used as a popup. + * Fix: Return `-1` when in tab navigation but no tab is selected. This brings + the library in line with the post-3.0 behavior. + * Fix: Removing a menu group no longer throws an `IndexOutOfBoundsException`. + * Fix: `getSelectedTab` and `getTabAt` no longer throw `NullPointerException`s + on post-3.0 when no tab was selected or no tab existed at the specified + position, respectively. + * Fix: `findFragmentById` now properly returns fragments attached to + `android.R.id.content` when run on pre-3.0 devices. + + Version 3.3.0 *(2011-10-11)* ---------------------------- @@ -11,7 +201,7 @@ Version 3.3.0 *(2011-10-11)* [StackOverflow](http://stackoverflow.com/questions/5637894/dialogfragments-with-devices-api-level-11/7560686#7560686) for more information. * Fix: Popping a fragment off of the back stack now properly assigns its parent - activity. + activity. * Fix: An activity result no longer causes a `NullPointerException` when the target fragment no longer exists. * Fix: Action item dividers are now properly initially hidden when their diff --git a/external/JakeWharton-ActionBarSherlock/CONTRIBUTING.md b/external/JakeWharton-ActionBarSherlock/CONTRIBUTING.md new file mode 100644 index 00000000..30d38336 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/CONTRIBUTING.md @@ -0,0 +1,11 @@ +Contributing +============ + +If you would like to contribute code to ActionBarSherlock you can do so through +GitHub by forking the repository and sending a pull request. + +When submitting code, please make every effort to follow existing conventions +and style in order to keep the code as readable as possible. Please also make +sure your code compiles by running `mvn clean verify`. Checkstyle failures +during compilation indicate errors in your style and can be viewed in the +`checkstyle-result.xml` file. diff --git a/external/JakeWharton-ActionBarSherlock/README.md b/external/JakeWharton-ActionBarSherlock/README.md index 75a94a00..6506c361 100644 --- a/external/JakeWharton-ActionBarSherlock/README.md +++ b/external/JakeWharton-ActionBarSherlock/README.md @@ -1,22 +1,26 @@ -Action Bar Sherlock -=================== +ActionBarSherlock +================= -ActionBarSherlock is an extension of the [compatibility library][1] designed -to facilitate the use of the action bar design pattern across all versions of -Android through a single API. +ActionBarSherlock is an standalone library designed to facilitate the use of +the action bar design pattern across all versions of Android through a single +API. -The class will automatically use the [native ActionBar][2] implementation on -Android 3.0 or later. For previous versions which do not include ActionBar, a -custom action bar implementation will automatically be wrapped around the -layout. Support for this goes all the way back to Android 1.6. - -Try out the sample applications on the Android Market: [Feature Demos][4], -[Shakespeare][5], and [Styled Action Bar][6]. +The library will automatically use the [native ActionBar][2] implementation on +Android 4.0 or later. For previous versions which do not include ActionBar, a +custom action bar implementation based on the sources of Ice Cream Sandwich +will automatically be wrapped around the layout. This allows you to easily +develop an application with an action bar for every version of Android from 2.x +and up. **See http://actionbarsherlock.com for more information.** ![Example Image][3] +Try out the sample applications on the Android Market: [Feature Demos][4], +[Fragments][5], and [RoboGuice][6]. + +Continuous integration is provided by [Travis CI][7]. + Developed By @@ -29,7 +33,7 @@ Developed By License ======= - Copyright 2011 Jake Wharton + Copyright 2012 Jake Wharton Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -50,6 +54,7 @@ License [1]: http://android-developers.blogspot.com/2011/03/fragments-for-all.html [2]: http://developer.android.com/guide/topics/ui/actionbar.html [3]: http://actionbarsherlock.com/static/feature.png - [4]: https://market.android.com/details?id=com.actionbarsherlock.sample.demos - [5]: https://market.android.com/details?id=com.actionbarsherlock.sample.shakespeare - [6]: https://market.android.com/details?id=com.actionbarsherlock.sample.styledactionbar + [4]: https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.demos + [5]: https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.fragments + [6]: https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.roboguice + [7]: https://travis-ci.org/JakeWharton/ActionBarSherlock diff --git a/external/JakeWharton-ActionBarSherlock/library/checkstyle.xml b/external/JakeWharton-ActionBarSherlock/checkstyle.xml similarity index 88% rename from external/JakeWharton-ActionBarSherlock/library/checkstyle.xml rename to external/JakeWharton-ActionBarSherlock/checkstyle.xml index 87be4031..cfde0eaf 100644 --- a/external/JakeWharton-ActionBarSherlock/library/checkstyle.xml +++ b/external/JakeWharton-ActionBarSherlock/checkstyle.xml @@ -30,9 +30,9 @@ - + - + @@ -84,7 +84,7 @@ - + @@ -92,9 +92,15 @@ - + + + + + + + @@ -110,6 +116,6 @@ - + diff --git a/external/JakeWharton-ActionBarSherlock/library/.classpath b/external/JakeWharton-ActionBarSherlock/library/.classpath index a4763d1e..570891c6 100644 --- a/external/JakeWharton-ActionBarSherlock/library/.classpath +++ b/external/JakeWharton-ActionBarSherlock/library/.classpath @@ -1,8 +1,8 @@ + - diff --git a/external/JakeWharton-ActionBarSherlock/library/.settings/org.eclipse.jdt.core.prefs b/external/JakeWharton-ActionBarSherlock/library/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index df27f3ee..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,12 +0,0 @@ -#Tue Nov 01 09:28:45 CET 2011 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/external/JakeWharton-ActionBarSherlock/library/AndroidManifest.xml b/external/JakeWharton-ActionBarSherlock/library/AndroidManifest.xml index 83e3d30d..7b8a8482 100644 --- a/external/JakeWharton-ActionBarSherlock/library/AndroidManifest.xml +++ b/external/JakeWharton-ActionBarSherlock/library/AndroidManifest.xml @@ -1,13 +1,6 @@ + - - - + diff --git a/external/JakeWharton-ActionBarSherlock/library/README.md b/external/JakeWharton-ActionBarSherlock/library/README.md index 4b22e6fe..e8a2c080 100644 --- a/external/JakeWharton-ActionBarSherlock/library/README.md +++ b/external/JakeWharton-ActionBarSherlock/library/README.md @@ -5,11 +5,11 @@ This folder contains the main library which should be linked against as an Android library project in your application. For more information see the "Including In Your Project" section of the -[download page][1]. +[usage page][1]. - [1]: http://actionbarsherlock.com/download.html + [1]: http://actionbarsherlock.com/usage.html diff --git a/external/JakeWharton-ActionBarSherlock/library/default.properties b/external/JakeWharton-ActionBarSherlock/library/default.properties deleted file mode 100644 index 3ac5a46b..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/default.properties +++ /dev/null @@ -1,3 +0,0 @@ -android.library=true -# Project target. -target=android-13 diff --git a/external/JakeWharton-ActionBarSherlock/library/libs/android-support-v4.jar b/external/JakeWharton-ActionBarSherlock/library/libs/android-support-v4.jar new file mode 100644 index 0000000000000000000000000000000000000000..99e063b33a53c8ba7980a5b5244ce0e0da46ae54 GIT binary patch literal 271754 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≥sIk_JB}>^^o^5z%WdNSw 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 R<#YeUTUpqmYLV9y{|}w)s%roM diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_top_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_top_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..564fb34b4308750b6922f320e9e114b080ecd538 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^SqC8z3Ln02py}XdO!9jra;!2L@ z<=I|~`ucZlc5hPnsi>TGwM)Is^N?0TPy5{UQpwgqqAoKG5)ZX-3ak0R7;B{1mWZ}( p*lxaUe)ue*Z}vC-G%ee~_}P|!&DqTD7lF1gc)I$ztaD0e0st(KG%NrB literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_top_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_top_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..ae21b760fb1ebecac3389164251b0fa14f580f5a GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^SqC8z3Ln02py>gKAfB^?4dC zy{Qwe+I<(;Zrk3}qFy7o$Hqotreyxi(D>i`gF-*@tj&^T;Xws!Omj@dZ?l#4Y_?*} ivA^-x{8q}NM@;fbHo20HF^oW47(8A5T-G@yGywny6)bE3 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_ic_close_focused_holo.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_ic_close_focused_holo.png deleted file mode 100644 index 9d7f9320824e805a66428fb71ee8c464a1c9c0ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1292 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCwj^(N7l!{JxM1({$v_d#0*}aI zAngIhZYQ(tK!Rljj_E)ete@fByPj|c1{MKN7srr{dv9ml&KGwTId1sq2<)l zOJ+Bew%MG~v6W4$v)+9B)0XF%-`~8M`93{8{n?zxOJ3S*w_KXHT-8)+l2q?wfz6ud zck?#N?qxZ{sC9thf~@-;T_u?r>}SLbcR%WAPv)C&rNXs5uyhyDrP!r9(827p>)Gh&)${EOcSnT7$2!;n8P+rNP6lr8;JO^llJ)_>bkr8v7uoEu0;#tqciQ z4A!xf85rfOF~&2l|Lve+s+RTf?4i4iIYQs{GdjMMXPt|hyNN-r^Y!NgzK<)pKDya* z=>y?3*6)RnftpLzHoHpJ#c=o>*6w3=RKJYXG%Nr8OoTXb^gv}`j+*O z;r|gq=dUbjdW)-+wlWKE$u|4IY;ZrriXn%&PIzDRiu(se_Fubn)&GE<^1Y`PkM=t; z@O4D4sK44GaYbOi)vsH;Yc|?gbJoad-IG4RXc+9QV=&9^lE8kBc-QXuT+UjiABP0$ zHTz!u|9y}_YLTn+lAQtCugarR8ecg0p5WTRUU6OMlf;LmJN}D*eY*DuJM)#sA958} znKlYXFs|9uV#QRW`|fw+YQ;yzj1~%M4EGmaVwSh&snLG-JK*Q}3D18YWsniLZ0b^d zY;}8ywdOwKzIl3c&$Bx?n=CH7E|N4$Z2OUqryQ@$@mvcuzPOY9e9o4>zvo}f-6Z~^ zWJ@hij7d$c>k)CLf;Ss>Z(MJ-z%A2$L(C5&;R8CStvhocl{3Dt++){q%He5Wt#RLu zx$fQ{I9R&uIb%#~La!YAy6wYLxlRR!_8;eE9`!G{)ZBke_>lAhzp$VCmi`QMGg~?D zW6KBMXEBd*BcBF_ROQ~{33->YOtyK&q)&4`RG#OYKg(im;?f_o^B(<{h)laYaYx#o z$$dwn4?VXPiZm@es#rI7=}*J%AAS!uHSBobka0~QEilFU*hhAUw`(>r{J*03&tmcB zQ_EjE%BKemhQ zmk*U*er@hl?VloFeOJ6OvYnslIJM2bt;0NN*2*6~4`d&#$tY9rn`g<$$$mjLth9Zb z^D>2xr3y>#_A3AT(kUEtB|K0xJamWrBCZb)yu2KA%$iaOr$RMTRdP`(kYX@0 zFf`CLu+%j+2r)FaGBB|+vD7s%w=ytjxukLvMMG|WN@iLmiUuPq6LTw5sD}Nqz5jt4 wBtbR==ckpFCl;kLIHu$$r7C#lCZ?wbr6#6S7M@JC0V-nfboFyt=akR{02O#C=>Px# diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_ic_close_normal_holo.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_ic_close_normal_holo.png deleted file mode 100644 index 641507dfd263e0be919b5c3d33f43662c3492018..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 957 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 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__dialog_full_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__dialog_full_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..79e56f522b2837bd9f579b28f037ad5eafaaee8e GIT binary patch literal 1414 zcmV;11$p|3P)cSnqT^=WQ7*OFqW%ysfqGq3fLYCng$eebY1E zq0h)!qMt>^T{!1KLrdv5=!(bMwnfb7mMF4BgVA@!3k##^X|etG%o8VLfn)&kp1$5* zAHx|3EF9@?)w)=}!OothSF(h}LSVs2n}u~V8rR2gA&m?6GFm9LT5i!5ovh2$`aOLf zDMwpCv(UIN+s(qhT71rU;E=VYR%2(wIy9)U9BqNMU?EvKj~0!zxmxOREjkZzh+iq_n}2*GaEP(@ILD!5 zWBguqUH^M`clY;tz5a@wsI&tR0g7j89WEv$&WS`s3jmAj>+65+@9$R+4-crSDsl+t zoXD~ai^by4tE;Qe>-G9CHN@f2j4rXz#$jzQA^^+B$H$Mix3`1-5a+ZsO@p#5Q53}= z0G4QnFC7vyL_!;@%<@Jv>_k)mSUx>Hz18n=PE3d}%kYsC@*I)N0NNv^lI%s;wg9j! z%knLLgEIoQ+bysY63^&#(^_eOc(NT6QxTdoZI(#S<~ro`ne!tS(gH7T&zUX-UZRk7 zy|5!F77`FowzZg?X(M)KAw}<4SRP51e8qZ>m)V;$Z3?tS#CiaZ^hhEi?U_=yRh(%c zcGk9kwMUBGYjYt@pHyCSltyExNUHHFevMy@-l#r~QEjQ;(4?Q~r4samHh{FF{bU7StYxgeBAZQ`6E7N`VLYGS_ z;oj>aHT`D+d1$*FJhVBd!G+`uf(ywR1Q(Js2reXN5G)~C&xiARXWFDHmGF81Z6U>K z;#g%)oXa8RP+ENtZO$MZBP0)Pm&4Jv?h_KbHF>VdnKo?a-t;CVB(9^gh389`0#_~3 z>r7%ovdX{d8amFjk%uF>Vp~*9sp-GKg_vAO(?{&AZLdjA|Mdo3?oA8H>)1>mc|==# zB~EQxV&cD40$n%8&w#s-rjOWJ+ddiIQXYxR!^y#)tE&3)24CJ80l~J_MCXPu>Ml3AI+9BHcJ4%0r(Kw z@2dYHj4#nGKH!fqjRVUuh**Aw_CvMrs{b>Lm!YwzO4di>6N@*}Phg5Tw&B1fy2S@v zNaMh=r`Sx3>1SxA8q+hl==5I;NtblfC(XkF^KkH7ZKuDGcq0~@mC!ryi=K7WXgde? zOwz>rq{P&!A!(hIr~D!&pe-W#G7`?LQYh|`P7hzs(O!weT#2|xih3m$l64(P7wFd8 z$(YnkvI-Blh{l8EAha{kf+|%%mTX6hk;YCcRo{6`6g>|oKBz>Tb24JLyVyI4p!izS z!8wv9b%$RIiIZ@y?B&nGjRPyvaF~-xlb-U|=!P~^8?n&FNw@wIvQA!p;xDy1AK0dR zu~CaAl^btMM>A?9->NQ&|AnVmzdt!!WF>xutSl`;$84s2a_=ari#ecl- zo|KSyJXTD=1$2JI1Ql!6el7Y8-dCZ-i%gs^mMBu<;eLzP8a;YIXA&Hxi>7JtAFa#2 UvCQ(L;{X5v07*qoM6N<$g1g$KMgRZ+ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__dialog_full_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__dialog_full_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e029f210b9a81ed4765d31e90b6e49dc8aa37bed GIT binary patch literal 1537 zcmV+c2LAbpP)P*hY@RCILOyI+)4*Y%ioMH6eaT8-v42qXrI z0|4iGEk=d4Xm52^#H?WUz%bBygG}I|;L!cJM*+u%I9T*&&%x@0sx#0Qk0mTmeRX1h$MIxNMY&% zsz{Hz01C^N@8p~dFgXbIRub%{CUOKKzAQ3rfl0r3M&j^DZL~BnC0R+zNTfH*0>l>% z6xe!^4oO*vg0sbY%(i4Znw@-;nUbs&1zN~PIe02zy)Qcz&8uA?+OU=`?e2Zs5}uJN0M*6C#a{)YX?>^k&iO8v%U{pV&i+9YXUL@sAe1fQs10%V6ikBo z^7Qod_s{$xhgN}Tci-i5`3pX{;N4;1Au(Bm7x@)z#1I9LmdL~RrF4uC5rsHs>tE+w zbjvJ)LKv+{MYbuBrU=TBLj=6Xm=@t7;baF+QjNr0K02$09MPPz_Q^dZ5CLh8#Oov4 z0!TsP8|Jz<^->fRi@r;w5OrSCkw6L?N(J|#V;?nA78HxV{Q97DD=gWeOHxKs4U)p3 zSoD>;waz;geHn?ahed6Tq%7rduPgn zV$nDE$&ajtWS5-`4=n>hvFJNE&bxxNGnt2!k)T-g9UO0!_0BFb6cm%bLuC>qYeBK* zyN@VHxuTkNE#cFa@PaJz!! z*)p0eo;YjAyoc}Lcn`@)ql2XA#Le!l%y)3C`#|D`qk*LC#Leoh&{v9irz@IDt(4j|E-ey3YJCdAoj z17Q35`nvale)TKB+I=4%AAxk%w!OMGAf++t+Mb@Cemp-vW4j&J%V|A%#TR&cd&9%S z1Mctdf1tZ-6W>Id5JKwGXhvG!+}wOSKR^Gos;Zyq!S}5X*>+05G4|7V9G{hQ?!VjH z+iw8YkTX)YMrymYx~{`?w$U_yh$q-O1#m*zu<(hQDx}lJ70s)V5Io{ZN7v2rMwVC7 zhTm_2@1*&pTK&uP8_~o&lye*5+om^+1{h zqafFH?O0X{OUO1M^YAPb=F`bd6<0LB=s!LE=ilN39Gach?DYt$CL6UhXTc;$2zpT2dqqQrIZWT*_yH->_|IcgE|Y&S_AJ4lX{3 zlIkT6RWeyS^JtZ1q^3@yK=Cm?J&*-y*C;dpYgTSF&bztX%>V7a(kL+ra#JUT-|=or zs-McUNbE?uO3e#!@v#wf-Fu%ryG^`~69lNs`%MmnTRbrM$471B$+eE{K4hK$mCQ9h-Z$E`tJc<=E)8`p?U8s&`700000NkvXXu0mjfb2aWW literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_ab_back_holo_dark.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_ab_back_holo_dark.png index 7855cda9a8ac11383c8cba9e511cef47da34d7cb..897a1c11a06923f0ee630a3ec44b40118c1fa4d3 100644 GIT binary patch literal 602 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1rX+877l!}s{b%+Ad7K3vkswhI zFm^kcZ3hx8D{xE)(qO#|6+TOsF)%PDdAc};Se)*?;+-wxD8l++z18QgepiI9o*=R4AA9|r|3}>uTm;M6YILUxmVi!uBjgaN)~;(wEWpmNk!cW z(d%Z<{E>P~YK!lT=8FgRsYuTJwQ$0$u+I~@?rdLb^6_f+5jpHV#tRQqPS1ijb30F2_W#pYUFO#_XV=?h zOHP?#2^DqDa literal 938 zcmeAS@N?(olHy`uVBq!ia0vp^DnJ~5v|}#;DW)WEcNd2L?fqx=19_YU9+AZi z4BSE>%y{W;-5-!(S%G6ZkOu2z2)9V81ZwN`ba4!cIQ;h7`ED6kiDMuAuf9?F?JO8l z)Zyjl_CZ0TxudIV*P%u0PR`e?2-vJP!L);G-2<7HioigDl&K9Y&1u%VXKV4_z5Hdz zUE{s%`j^h9&U(3hf9(0-{7}95$2O7=N)Vt@CEQ zsC+H7X(Ds{>CX?Q#x0v99$O}#lD=1;d(*xJQlDFV%T*jVy=${|ocCvS&c}+Tl(VVI zJuKPZ-p=#MXIv4u?dcw8M={x-0fDz(*($l*ELP)lNlB0SzS?5`Ij4Z!*K>4_D?}Dw z4nK5K?iEYuwoMtg+map4zP0&f7_!f=;O z@3`-GFV(GeD7E6R+|Feh`E{{>rvGx$D>J@qw|(R>VeOC8$Afmx*>x>C=b+0??|CcL z=8A^jedV`Yd$B_0on_TcMVIz}e4BIWE3+@hrpn7F zeJazUlkePEddbK;_FBU6_vcP{n8g_B-A=eAZ=yT>=>2t94vOnlIB%Wo_q$2U_@Mv3 zEozEZA2xM=npC^!YSb}a`{=cwD~~s)I{W=@%nB*UaZgm?=9|0u>W2I0Z!M7t-jct) z%VyW>$jL{)?aEUE&J=hTfIHjbk!>^ z@x5l%Nw@f~Z1_HR?=C^E^}7_d+FxeOx^a7JeCxd4z3E$RSDq8R`i)C|r@q3D=X=gZ zx}Im=v`zf)qtB}>o0;`1cC8f@Yfv*5ng8=3o14-$TOH2j7MZW@&X?UOdg1V}FLb@~ z`RLdG7n-h%pVcd}{FmLV>W6{JJ!@ILukL-Mep+4*lt>)^r~hTP7Cn)1$Gxo(m`cS; zTq8=Hi&7IyGV}8kLNaqx84L~e4bAlp4bHAP!vs{J3R01hSdwa$3{sZLU}RuusB2)X zYhWH?Xkuk#Vr2qkTUZ$w%xvJ0MbVI(pOTqYiK)Q|szGnlPBowg8ITRZ`DrEPiAAXl njw$&`sS0kHMXBZaMcKs)&cUXITOXSN)iHRw`njxgN@xNANkNij diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_ab_back_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_ab_back_holo_light.png index c06277341b79ba8c24133b40787307da8cdc2a02..0c89f71407e8d51f92ff6a10b1ae40ec902aa04e 100644 GIT binary patch literal 546 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1rX+877l!}s{b%+Ad7K3vkswhI zFm^kcZ3hx8D{xE)(qO#|6+TOsF)%P{dAc};Se%}E<)W9gqsXz3_j5LNPFu1pO1DK} z+N#=yeg8w_ofMzAMJao1SUGXl-8U7Joy@GYEX@zknfd?wSxaLcYqyHhr&soQ-EO{p zw!~UfNcQJK)l+|B(yvWaZRmKvsC8=g<+E=!6%t;!XnxPxBUZuOVKlwt*0FipR-Y02 zmCh$xWIQ?dubRMH%k4r1TjlOEFztJ(`Lu4f+1J+&0<|T}CPeP?x_?Pcpm5>hNwa5M zzkQR1sjpY$)<2WmGuJ)*zvffcmaNUK`~10Vr~dw8eVc_z%*|+OqxE^sCGQ0OTrOO6 z<>J@Zf0Ym33CMeTp!xW+<7NU=B(%1ExnpuV-^$?oQTEn-hjMN&=46?A$U{|X$JUzr zjr;q)=$3Bvc`c`@@Ze;4?7{TSRWGgUnXHd<-`o)9JVUa&78r!8C9V-ADTyViR>?)F zK#IZ0z|c_Fz+BhBFvQT<%Fw{d$P~!6GB7Z{-*6d4LvDUbW?Cg~4NgrK`9KYlARB`7 r(@M${i&7aJQ}UBi6+Ckj(^G>|6H_V+Po~-c6)||a`njxgN@xNAF&x-_ delta 924 zcmV;N17rN61kVQ{iBL{Q4GJ0x0000DNk~Le0000a0000~2m}BC06;5U(vcw;e+v=- z01FZU(%pXi00009c5p#w0000a0000~09QC-c>n+cvPnciR9M69*2{|=RT#$M=bV~O z?2b3oc-;#@iO8DI7dyGyjMSgDDK|1+-au9;}!b z8e*cC^`yuoc6}vV1g|wRm3qZRQ;<3A9ho506g0=IJMWHEkm~u&mx64tZ`$g5f>hT< z2@*lqHJ>i0w*pj}c0u1rkcr0LvzOayToIzoi(axTB6G+mw#CJCR)XfXe;#+i1f;sY z@rAIwhH62DtxWWmBPN1O$1NYuW-PC$Sc{2x-5GnuoZtgHxvi>&S(j0i+VGmYB2qn{ z`$5cYX#$$3^N=@-P*eB$$t9}OsRWgp{)R`51(`K}d0(1ur@H+XD=<;!Rp*MPv*sf= z>eH#qC`cW5-amr8>0i4%e`~sCpaDVVu(x%j#q-d|rSF@8HfQM^E9!~%yj#5`4z@<8 zbV{WMS(+&+zYO&QwrqI7RFLWFyON(oeZ!`p&Ai5un_iF#g0Z8bpYs}5p%y@W$OM1t zIAc_xPT6)VZ+}D3Fh{|!PI}B(Kw{mudHnS?C5x{GDo72TlgI=Ue-FFgcdP9s`v(eC zbjQe9V?i*oZpXD%_LAkHc~ZZ7!m+|$=7jJ4U2m@fG`GjLv$|5jRL@bD^YfqzRRJp5 z+qL64)1rG%n%c_kEu$(yC3`pYoGuo^#7V!nU7b`7sATUq&w8*}=Z743B~NXCO*NpB zy|L?_mt!X$(eY!|e?q7Q&Fw|EMH@x}CQi8S=CZvNpy3R~mZv>sA`wKVTyWdJcTFEKYS1~D+rtjq$Fj{zDNGc7PT zR53I4ZLn02pop#z!+EApeUwz>goe2TrwSq2J zirU3kvaXhOUTIG}?do{Paly7dd_m%&JI?q_-onB2%KO8{j^-Q>wzNlYp6R5&dH;Rm z|KbvtPbZZ7*R_9QUBqkhp({MdL+G`PeiKVkcC&4Y!{nAd6Z!S-oqj3U!mzMkIqyf? zf)_G(nEp@p{`aZ-I!9g5h7aq1927O&FPT&GvG@NuQA5$TGve!iOqW^IxiY{>!{pzO z!{3V<)Sk6$zkBfg;!caFvF0E2Z#WAV9{aHQL)vPusEmizHw=GVH2J}B^#kKc_ZNxM zzDF#RGe0;TaIo&I-m~b0*sP8To$2@Yde+QKc8kg_`XHU5q@;HFk@ug+O{X5aZ~nk~ zjknIKwfM~0Z^b864VUMM@zwGAdYt)v<(Nz4IlImB@8#qJ%zn(A@Z29bd}4MpKn$sTM506307QmPCTFYr(@#O zpZ-(V%YE!?30QE(DXivDMdI0PFM+AKOT1>hnX-6tX;O6(d#2d)iSBZ_kN7m7WzTRr zzEA`h)2bz|5hW>!C8<`)MX5lF!N|bSP}jgh*T6i)(9Fuf$jaCl$hI;t2>JhQGm3`X z{FKbJN)!#IR;K1a1kqq?mJtlpAPKS|I6tkVJh3R1!7(L2DOJHUH!(dmC^a#qvhZZ8 Q4Nwt-r>mdKI;Vst0K3d3fB*mh literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_cab_done_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_cab_done_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..ed03f620f8ef9e969d0471ab76329038e25c9f0d GIT binary patch literal 737 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}trX+877l!}s{b%+Ad7K3vk;OpT z1B~5HX4`=T%L*LRfizez!?|}o;S3CnFFjoxLn02py%z6(IY8q0$M=`{k_{&Q=;t<2 zt8!*r>&D`|W2$+>pS=eAb}M##+^cbdA4dCLPr0$oL~Mm8Bn#4$+9@L$(#*Pp%fW0&@t4F~+Q4$6OeIrG`|nG22@uVa-C zJ=H0n)NABBE9V2ZrDh$}Ob?>#U7^{{%b z^;_|*S@)*|RLscvyw85$_Y2}8p?L-UY)vO;|NFUQJ(sNEA?BESpVrme#d7mboB7l} z-Tl+e|M{(6F|!lpnSU$jtXi?CXvKcs<;$n_y<4FKOaZDTt`Q|Ei6yC4$wjF^iowXh z&`{UFLf61N#L&#jz{twj7|6CVFbMhoZ8M67-29Zxv`Q2WrdForKm^fXYnBlV)F276 tAviy+q&%@GmBBG3KPgqgGdD3kH7GSPrLyp3str&PgQu&X%Q~loCIB{EJ2wCT literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_disabled.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..d97c342d53690e6d286efbe5f37562747a49b96d GIT binary patch literal 1774 zcmVU8P*7-ZbZ>KLZ*U+lnSp_Ufq@}0xwybFAi#%#fq@|}KQEO56)-X|e7nZL z$iTqBa9P*U#mSX{G{Bl%P*lRez;J+pfx##xwK$o9f#C}S14DXwNkIt%17i#W1A|CX zc0maP17iUL1A|C*NRTrF17iyV0~1e4YDEbH0|SF|enDkXW_m`6f}y3QrGjHhep0GJ zaAk2xYHqQDXI^rCQ9*uDVo7QW0|Nup4h9AW240u^5(W3f%sd4n162kpgNVo|1qcff zJ_s=cNG>fZg9jx8g8+j9g8_pBLjXe}Lp{R+hNBE`7{wV~7)u#fFy3PlV+vxLz;uCG zm^qSpA@ds+OO_6nTdaDlt*rOhEZL^9ePa)2-_4=K(Z%tFGm-NGmm}8}ZcXk5JW@PU zd4+f<@d@)yL(o<5icqT158+-B6_LH7;i6x}CW#w~Uy-Pgl#@Irl`kzV zeL|*8R$ca%T%Wv){2zs_iiJvgN^h0dsuZZ2sQy$tsNSU!s;Q*;LF<6_B%M@UD?LHI zSNcZ`78uqV#TeU~$eS{ozBIdFzSClfs*^S+dw;4dus<{M;#|MXC)T}S9v!D zcV!QCPhBq)ZyO(X-(bH4|NMaZz==UigLj2o41F2S6d@OB6%`R(5i>J(Puzn9wnW{e zu;hl6HK{k#IWjCVGqdJqU(99Cv(K+6*i`tgSi2;vbXD1#3jNBGs$DgVwO(~o>mN4i zHPtkqZIx>)Y(Ls5-Br|mx>vQYvH$Kwn@O`L|D75??eGkZnfg$5<;Xeg_o%+-I&+-3%01W^SH2RkDT>t<8AY({UO#lFTB>(_`g8%^e z{{R4h=>PzAFaQARU;qF*m;eA5Z<1fdMgRZyw(kRs!-6#o(LP%Wr3O<1=S3ZFo9z$bj(u70=3}tI#6DWj&F;Ob99q4>t z7t_JEGi|0s7bcyiT{LI@zd7fguOSTo_Tn%A3;+W_$om&@e+U59{C2xK>{t*000Isi zc-XLE_dt-QB?k*OY(G1$>uu7@#B2;ALf{;yd>Fer3 zxz>Q~gZLw#9*+Wwy1biLp*!&n>VXAqU0c|%HDJZ1jZ6!oDKES7+VWmrg9gjr1HUt9 z$&h=(yP22-u6mx^E9uZ+0pKCX;bJ-&1r%+uT+pDpXT$;nS`cq%Mnv${vs}4kKnFnO zP;ojL1*vOGZSwsAS`q0H5q$MLS1wr~GAT|cBOrBcX}?{*UqB~HsT)hjem%$S zQCYe=d4(eMUA?{!rJtE>6>2uC>s{nMUVQiovq!7(tSuZUVsBCpu612n+{HyeG&{C3 zg%Qx;Ym2+tg`4}D-D9)knmeH3*ac5hx88#8rcKL0fWiC005AajcYxmm08)I=nXx}} QjQ{`u07*qoM6N<$g6k0wDF6Tf literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_normal.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..33ad8d4b891b14d934e470b2222571ea859c77a6 GIT binary patch literal 1945 zcmV;K2WI$*P)U8P*7-ZbZ>KLZ*U+lnSp_Ufq@}0xwybFAi#%#fq@|}KQEO56)-X|e7nZL z$iTqBa9P*U#mSX{G{Bl%P*lRez;J+pfx##xwK$o9f#C}S14DXwNkIt%17i#W1A|CX zc0maP17iUL1A|C*NRTrF17iyV0~1e4YDEbH0|SF|enDkXW_m`6f}y3QrGjHhep0GJ zaAk2xYHqQDXI^rCQ9*uDVo7QW0|Nup4h9AW240u^5(W3f%sd4n162kpgNVo|1qcff zJ_s=cNG>fZg9jx8g8+j9g8_pBLjXe}Lp{R+hNBE`7{wV~7)u#fFy3PlV+vxLz;uCG zm^qSpA@ds+OO_6nTdaDlt*rOhEZL^9ePa)2-_4=K(Z%tFGm-NGmm}8}ZcXk5JW@PU zd4+f<@d@)yL(o<5icqT158+-B6_LH7;i6x}CW#w~Uy-Pgl#@Irl`kzV zeL|*8R$ca%T%Wv){2zs_iiJvgN^h0dsuZZ2sQy$tsNSU!s;Q*;LF<6_B%M@UD?LHI zSNcZ`78uqV#TeU~$eS{ozBIdFzSClfs*^S+dw;4dus<{M;#|MXC)T}S9v!D zcV!QCPhBq)ZyO(X-(bH4|NMaZz==UigLj2o41F2S6d@OB6%`R(5i>J(Puzn9wnW{e zu;hl6HK{k#IWjCVGqdJqU(99Cv(K+6*i`tgSi2;vbXD1#3jNBGs$DgVwO(~o>mN4i zHPtkqZIx>)Y(Ls5-Br|mx>vQYvH$Kwn@O`L|D75??eGkZnfg$5<;Xeg_o%+-I&+-3%01W^SH2RkDT>t<8AY({UO#lFTB>(_`g8%^e z{{R4h=>PzAFaQARU;qF*m;eA5Z<1fdMgRZ<`$>NYxmjX{xd; z@m&{rFo*<6ia-&%?9S}Yj1NoMU6_?!qi=gB^D?>lzI)G{bI*)0`G1E*K~NAB1j^1w z0>tKJZeH2PwwY!w0t6BY3JN+p33SuQLYI(HkdcX#K*!j*7|BwgVB_Kabv%L#JBpC9 z;EQnJ<+1&B?8Szh`#X@?^XlV2b_Y-K5FTsACcc7-srF!J%cFRa5f;nX88so}^!n$z zoaNXjzHYk7GONT$qz7ti^`5C0{0Fct&sMz04AGszwAz7*v3&RHh^`S091pfpv3(b5 z_*4F8KwG3jHT04 zL)Y{;8%;+;M^cIuK77Jo4_dVE!}GH&5hG!l3Z``(DA*|D!7J6TwaW^Q$!{BPvBY1f zfE_QM@bQ{@gcj@j`1~x3tfQh^)q%AjL($PLWE_*Djkj1Kg2074d~6f{Nje^K7u;94 zsJv3$@rsafhDHP55kG-dHIPmFAA9=;s{MWcddV( zJFI2mtpvLr*Csj|Q8r$mAN(8x6+<_AKkZ*4LX3DO{@?b4Jsi2Lc%zUffeHejlb9+rq0PNT9OD z;u|vq-{=}^jSayj%5h_}ZkgGdzKgPOi{A&T+VkZWUN=qCxUcB??b4_oXFbpmY{r8l zAAy7`+*;!URqf8e1DIx-VoXo49%u+2!egDT);TPBON$juHQN2v;6f%oLvg2T=HjTH zV68;SR?~`g%UoVKaQk-bqv^ppmWX8HlM0b+kmj2@1ok$Lvua%nR#_xaD8_}Gdqhyt zw&OGA*(k-%DiJgiJLg#o1Tr!L6T|w0FfHFCBm_osWr=J^mg5%t6~${t-Jw00000NkvXXu0mjfxs7-r literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_search_api_disabled_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_search_api_disabled_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..3edbd740858acce452a65675b594d87cd85c4cde GIT binary patch literal 1504 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%xRe+5hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8nflaTYtD^x(vzwcwbv89=@ zo12R>knQRQ)9aa6T#}fVoC>oy6KF3~uNhvwR?bDKi6!|(A^G_^uoMuGkzbNuoRMFk z;2dnK;G3A7nFr#7q6gwzm(-%nveXo}qWoM1aQIqfVzJ-F(A>z`+0Dqw5#euVHw$9} zR|{85phuLTdQ->=Gku_A^g)RODY3wWfGH5fgeQF<2cCIS^ME;~2$(fE*e!Y)7?=b+ zT^vIyZoLURops1T#P^YM)`G6?uC=+kf7_B4{*@J9^x)duU6<$Tu^imLQtVB+#DuWI zKp&sr#e2ikRF+h_7hGg6C3|* z?e*8ufgcND|MEKid{9C;-~RZ9Bc^sP~EP3ND_zG5Dxwk6j&$wE~4;Qc*`ssan{ zzn`9=dZ&RsirvSfCP;`whUHEmQ}f9$MSB`#rfaa*Eq?H{s4_-JY+eJUGP9%1oq zJCJw4f2WB2si`MZ$~H#$*nP`3S@opI(pSE?i0N0@>$2Vb7oL|#u)gB_!dQ1$La5q` zDeOVQ4#QJ|EiB?JGJhRxA5Ld^&RpYp@TAicHpRs4(vR3C88QC9{5(weR))#4lPN-s z1=7=NbKU$Nr0Hgbao(RTxaH2IZ#(aDrMoH3_0umA{h;I6BI6;^&o0#XM(`ImzsjuT zTnrQ3)U=jJbp=fS?83{ F1OTcH9Pt1E literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_search_api_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_clear_search_api_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..90db01b5bcf1246d6a94e83930cac63c93a6cf83 GIT binary patch literal 1540 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 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..2abc45809c62513224e9d695542cb8dd8e8087b9 GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezt=sPZ!6KjC*gdALL|E;9+*q=6m<7 zlueVX_4IZHnJ0qE#_rG0T(kiyWMEjjhCTn?qu5pu`=4q}27?c$C=-xvpo(CHaDZeV Zn6Yoz!5==w*?y}vd$@?2>|OKBsl;8 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..bb6aef1d069a14a7fc1cea9780c919c61679e4fa GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpUtXipc%kc@k8uWjUIP~c#3xZ62X z=G4p^oaPsfxfS0Jish)R3f(&WG9yqa14Evg(y_dGGlfCy2iXqR3?>_SEs{VyhV?DH iJ0OaDc|iOR772{!kNsXaOPT8&i0|p@=d#Wzp$Py$I4IEo literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..6f747c8f065940a8844587c682fb3c9443ad1ca2 GIT binary patch literal 467 zcmV;^0WAKBP)SO)@i{}u0qYYqHziBfu2L*;{L?D;GxhmUqDjP ziMkTn=nm+BxmDP>FsP2fGnnz3AAnfGAiD%ptMDlguG*u-2|uL;kN%Xenfoz6Wm9neQuJ_f08buH`WL4SA>8mzG9{4uwy+$BT^9a|eO3@D0j4;gS>^u3i8D002ov JPDHLkV1mHE(I@}_ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_share_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_menu_share_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..682b2fdec4cdcffe042a0eaba5574fcb553c6fab GIT binary patch literal 505 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 AsQ>@~ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_voice_search_api_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ic_voice_search_api_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..3481c982862cd524654e200187445a774446567f GIT binary patch literal 1833 zcmbVNX;2eq7~YUb1P`!K89?kB6p2E1Hz5g$1PR%s1`Ngo6*2bY*3mT(eCwGjDt30z@ADk&)ul!ycbSpXq2nas~26ecnniH=emg*g*#j@Uj16nB_N zi=DC%Hqg(A)tr+Y(ebG%LzlQPJO*&###LsqLlu9w;l%7DLh{2@p8E^+tOq!T_lW zAkrjQDugA;2orvi3RR;rF{(mPu~6K{@h+@VEmI|-Ny!?GN`oM%Mu|v7GKol|K~;>b z*7RYuHV1{-On9GN3uBkTDuptM`n_1Wio`LBAhQXgsILR`g#<-73JE)?GKxVRX0q7) zdw+ReMT_F3WiD>kkc1U{nP0i(9rjT~DpaX7!gS@^xK)~D5v)#TJVPYB*I4ua$r;2r z1NocdKh4s2#B`uveAD{O=FRZnHfCZ-W;Dvr_J%MMH(iS=vz?dnp7r*Q|0OM8=!_4l zs;ZL3zhAiUWdL6Q-YyURf{oFuq)uPWZD82qEi67Cysi1BvmZvMgw)Irq>e&MQ~pM`Lu=nbBxwasjL&Tsbadl%z!58�PUR2s z;--Gn6L-Y44d%`7eX(hACTrQSaf!p)CX^44OWKiL4CvZ6umi8K5;zZ2#*ykw_khy5-2;-x4w&2R z09{9x#xx})BvjJ}TI2cLeM%Juon}o2C0ni%oPP$#W_j{v7Fn&)Y4-+12-XAz2ixMp zdk-dG3-j7Z^7|(bZX9v*jq7?`Wn~?YeZGM=J3B9(I(X1G#M{BXSmw#wPX}s^Mx$a& zd* zptYy_ughebWX6!_=*!|<*LPvVhwlqoZlfEYtjvv>6wjfX3p_g?JMFdJ!co__^o#We zw=b#O^i`T}%SWdnY zptrVi4hONM1>8N+Q_^*Hw7fWo0bv~uaDGTec^ju?7ft7iw};GWFmT;t zmqkFIFYh$^o^;LBh6ZkJNGZ)@ubCQlP9ArdMLX{p^!g2)d{G45wZD$82#Akx7wY?a zz21Agb)mdb(PM7iyy?!^d2(dCvbWL2&n$1d$2oqkM7b5PX3wkWY%R=ajlH#S8mQ3! ge6yDA3jkPwzzE(HQ|OAY)&8HCR-J`5r{^yG7imhbuK)l5 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_activated_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_activated_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..4ea7afa00e2bfe057472ed5a196080fc80ad7383 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqhEX7WqAsj$Z!;#Vf2?p zbb>IW`N`93fr2)kE{-7*QBRJJkl{&7FVVepxUS$Rt1LT2VAvn7lLLt0oo!v4%( tpjG6n=4tr&fORvYRP%q%M>EqU82;Q9of*be(FHVz!PC{xWt~$(699PnDoy|Z literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_divider_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_divider_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..986ab0b9746301f2dd9401829da09e00995621b3 GIT binary patch literal 78 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1|-8Yw(bW~qMj~}Asp9}6B-)+^BAxRtXRm= az`@Yw&#rLZUbzUUfWgz%&t;ucLK6T(%Mo}0 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_divider_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_divider_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0279e17a123f8cbb3c7e3a9ce5c5af8e693b6977 GIT binary patch literal 76 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1|-8Yw(bW~!k#XUAsp9}6B-)+^LX%RmN2q0 Ycy4A9FVZ~13zTN?boFyt=akR{01+Y(GXMYp literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_focused_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_focused_holo.9.png index e354629abcb251566c9ac0a611406da603b01937..516f5c7399c853d112a31d1e17c8c7f17180f9bd 100644 GIT binary patch delta 144 zcmX@bF`sdQcs(}<8v_Hw$~EO`K#HZ<$uool2x>S|I)Hr60*}aI1_tg<5N0$#d3r5S z(9zSyF+^f&vcbJyQy6*wxF0G=*z;ABS$WFC?sd$vbG}Zycf`d*&`2TjV|~-A6Q(m& qj`lFW=V8m>`KR8}yWK98fkDkx!gA}s?Gr#YFnGH9xvX?W6uY-vbHoe45hKIHJlC(_|T1VP6uCUJ8RqSwwrODSeZ22+yX1kum zgWv=idXODNMe#OehzAi-P!SIbiXaN!ysGS=UWECjU8je!gMsAx$@@Id`+H$>;%IO8 z{%(RGdedWa7Oy?{WjovPcj@E7BwhwlDvze@BC4n^BqZG~Kr(HrC76Y(zIgf-j1fd@ z(a7adJ~J+Awi#4?n_$&+Fq$A@qg6-M<{%;quw+ieT76lv&j>SQ9tv06#IyHKPj8#QUU_zvlRde3*#A=+X^NM)yU(*y>H$ii8s^L^VGf5_G7n0#1 z2xuSz$Osc;xDe0tBP0tLKm(R$*Z{+e94i7qZax%NbM>N_m6c5`e2PBm*K_D~l7bz@s=FSqDGItx8}!PRg*ibG8>&fU&Jz9IHTJmwm> zDC)dyYYQf{P+E>t_)kzbbTJ_-DUK0XDZzqBlwqPugq0(qa3ah`gpd+#a%_iXl7LT! zc%T4IVHjBv1c{dwhEtN^RD$E#CN^z(NVPQB)HSef0~=9x#EMB5s>pV8wmskMfXT9r zY_DuPWO6D@W>n3v{Ig%4Mzk_?jWbYJT-zk;`4x?A^pz-&eda@eZ^SL}2`MTuKmZ(< z;yHoZ#OnW(Ga5TX`_1uBvox=82m0Hs*2jmf;ei&O7#EMm^y`*YJXW=|Eaj@73coit zMq9;MU2p5&C_V3cd1v4NG5EBlF!FG<V*mgE diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_longpressed_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_longpressed_holo.9.png index 367c7d9ee09d5279c5230bcbe12bdde2c548a973..4ea7afa00e2bfe057472ed5a196080fc80ad7383 100644 GIT binary patch delta 139 zcmZ3&F^h46cs(}<8v_Hw$~EO`K#HZ<$uool2x>S|I)Hr60*}aI1_tg<5N0$#d3r5S z(8klnF+^f&a>9(tHb&k*?uR%GKJzduPib7p%)Df_gt1^q3yVkCpZN>4ihR{P4Idw{ lZf2Bf{?GYnX1WB!pSz+n!?-HCfaWlGy85}WtaD0e0suWoDc1l1 literal 1060 zcmbVL&ui0A9FOY|oem}ZC2iA$)tV-aE39*Lg%wXrlh-zE$&1OG&2|y= zAnu}P&mx}u2Rx`S9D^MMJ?Ql0LGUErh56DS)5F-oK=OX%`}usnKOZeF+#DafIL0u{ zcxBG0(e(^{#ZxEgckA;Noi0jq7|p>=#8y13jcUkpHty`AS%yiq+E)e_}B|5nqg*(abVf2h_Fr6cKrhP^VMsPb)5pYoUMXtprejEw;7_P&4s$X zxoRs8SG>;7#wsQ75V6?UTk|6|E^s|wmF|;kfn$3nWVOKcooZAUSsjOn&GH~^gB)OU zkcU!6mgQ@#2p|xEC_pg{WmOVY0NBC9QMJ%%sWrnKXwg%F>ktyCg3#@D`L4v{uq{AE zQ4$VOOjC<=wBZvgPW#dHkikHa9l8N=vCk%qRuiw20!KaVhu{U(>LIZo4H89DCd5`C zKpqI5m&Dbxjz|stb>m3usJ;;(p@t&79@?}Xt?40{=I(f*#E^QU-U?k>6l=}E_PU3B zQZWh~{lh!1qm~S_EI~!oN+QVRA0raTFHnK-M$4ya^-|Lc>%P zO*Tv@nR>Qdl4Nm+t@shKd>ajQU8+04%Ew|=Jwz74VIAYOVFxUBFu_p=2duu7WviC$ z`pG#dPd{1%h3;MCm?8GqUVc^g2z@gzQ=jDwko$3Ka!Jc;5GX*B%Ce+z1FZ8uITNTe zLed=nG|TXcc3`qSY<+q-93JG;i3#aw?0h;mL&vIKF|>NT-~4@WP)w;Sjx#!T(B7Wd zc|LiGnR+wQdM547n5pxr(<}8~FTR~vJUjpK!P}|r@7n&uclT;v_wrAlm=_*jz5HWq gw^N!}eh)@QCz%g7CeiKjFU4eTE9C{_WohO9AL!>whyVZp diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_pressed_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_pressed_holo_dark.9.png index 9eae8f41c82bd6ed7d765660bd2f897999863b02..5654cd69429fd0a3502a05b5f827bffab89cc7e0 100644 GIT binary patch delta 144 zcmZ3=F`sdQcs(}<8v_Hw$~EO`K#HZ<$uool2x>S|I)Hr60*}aI1_tg<5N0$#d3r5S z(9zSyF+^f&vcbJyQy6*wxF0G=*z;ABS$T?~a4fr(#cSQU$6P!FjT9n3);Fy>VLDUg pXbr7!1BjSUOs!hk$Hg@O1TaS?83{1OS8+EK2|Y literal 1061 zcmbVL&ui0A91m{JF&T=WYzp$0!49$}FG<@pp>?!P;|g}puEU;WY4X~JEqPh;X0sig z2Nef`7sbmCBJ-jk9t02Wpoj-Syy-zf5Rd)?LVf9v>0#_(AbCIX{d_*(pSR}cE{u+x z9$^?}v^cAk>3WpD;_wjt-u^t1r^`4gRLKIala}ElCTrmu0!7DYpfWP7_0{(%%`gLX zyHX|9(nZz84rfF*TO2i?GF=`PD)?H$RF*lg(GiWFlsw)SRXlBta3gIT0pPf{@aaqLz#&atSf1#Pw94V?V5rhf*??(sd~5 zf}rV&l9e@Gko0__kdtJwk1e_ZFSfJ@lUh#uV@EG+r8GOhrQuJE}a;kj>h31KcCUDS}bbWO8BMryWO4{P?s!g zaHQRMbNt=ou`|s0?xEWBx3_m^?+i^1o!H&^e);Xd_SpTMBb(CA51TKJZM7f0e6Sjy p*gAK1G5zV}y{|XG^KD~r7&6mO#-~m_{CG7Q++tx)dzxFi{s*n^Od0?H diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_pressed_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__list_pressed_holo_light.9.png index a9131fcbc5b5236c0f5f6e0a1315027f607925e1..5654cd69429fd0a3502a05b5f827bffab89cc7e0 100644 GIT binary patch delta 144 zcmZ3&F`sdQcs(}<8v_Hw$~EO`K#HZ<$uool2x>S|I)Hr60*}aI1_tg<5N0$#d3r5S z(9zSyF+^f&vcbJyQy6*wxF0G=*z;ABS$T?~a4fr(#cSQU$6P!FjT9n3);Fy>VLDUg pXbr7!1BjSUOs!hk$Hg@O1TaS?83{1OS7BEJ^?X literal 1060 zcmbVL&ui0A9FN-=GB+54u&IZ)3`B8FUXr$H!fI)gW-FLEx_~_{O61)vW#ES=EzVyfRFm^DIydU{~KA-Q;z15Yasfnu-48u&- zmi0PaFVR=LI8ML&pXM~W%#vz@tl<{v+7V*PE^Z=F^X)dOBir46@Bu9{%xKHA8l+*~ zRUPbec51^Ven`;_vsg+(+u1+_G*R0NitP7SM=bE%B6~k)LNnA*$6MZs(Av(54A5Xf;bu?BHJM(RC&JJ?Q&g-!%>?T6h%on zL@`4xGVyjm>?9M!^Fsz5#ZKgf#KQqd8SN(CB1M*Z+7H1GP4kpEhzE(HDdQ76)6^35no3!-ijPrkJkJUOmla>P-;lMQSU__EsDLVV`s}p0jcRl zmj2;f&s8hBQI!NmELTLBF9<@x$cuVDo2%r+yplBvLyohsf(E60L6Hn78G@i2ic*$! zLy!zDSFK30IKm+`%Ex)^fnK9WO}F zX?gn5>L~IaBG-tp4|@4ky)*QUf=qpuvrz8GU6w25LRo+cl%%RGDeM62{!h+$>I|PY z$3M+7yrLbLZckgE9!`e`1$1H}IvU3d(?@iyteRf7lF!ZGCnu#*b=`HxCQjOKr{6!D zxyH=C9%((5eqBD;-P;|5FB0nqb94O0@tZG`&7a_#_O)~?Xk9m#5B8U?JR$Gg?A+tq cotX!ytdud6iMT7O&4bD*mP3eKws)UN7D2k#e z%DbYt@4NEYnkjlINEK7=*RV3zwml#Px9r!q%}Y$QM*NqHEZ-wscn^ zf4p9=Kg#ZZAKY%YZvc!aCbL}F6eGxtBSzy=smEUmc6C{?q1YCQrid~5o$!73+BeU$Ee{DI^Yo4#-o87 zao*xiE9Z<+s}ttlWw19HGlEA1nW09+*~|#}a;CkeJh%bU1g9CP5h0^O2}4Hs%y=Lc z5q!OY8j*^uk~rBBK?ljmh#jL84Ev;rDo>_H#K|6e%Mo=CgLzw$rI$Y4Z-kUy6U47Z zMI2w^tmuV~pH%tJq!^(yWY-hbFl2;G2g)+VPqud2Sicc+jL>MvBTKK;HbN#jlrS<8 zl+;FqdPULzJ~Kh_!?j8>!xs^*nQAm$#290~ue;BBnY1w&wMw4#m(pwEDZd_oY1{Ux z>$>N)H(eWD*FCpw`-IsDKF28-6~1bz!JGs-W6Z&R1n>#KR{&q8us99Q}8ID#(NJr3oa@N-D4Rc$qhA--bT2} z_Wpf@Z`4749}#V+fwWJz^oyZKO1~J&exY-1*Kg?D$hu!fixvAiNfpmG;mo&f5BSEA wlE;@gYed_N;JFm#Y)Zw{1W}kQU9GkF3xsHEK4Myn7XSbN07*qoM6N<$g18=|djJ3c literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__menu_dropdown_panel_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__menu_dropdown_panel_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..924a99d173082ba58ca7527822359f228bb14dec GIT binary patch literal 1061 zcmV+=1ls$FP)#d)-&;4-At916hopygyW1WQa|lkCWZ4-q&QLYwjy>%Jd>?UvK6*fy zdt!`Ep~K-gOUxeEG;B7TCA&L&Y`5FR`f3tF5S^VH!lJsKJqkfK0&PN7nPcRS?`4Ev z7V~vPKouy~L@5%v*=&-(hy0cgM*ETwjWz&8F3NVhH7#V4$3+kVgi2lPw-adOTXm|2 z;f`P0rx+seIw-H@dwPaOx@-q(hY$i2BS4u1XM~+%LI5%mN(D;0XOsl63U@~43e6EU z5mrW96C~;L2O}H%p$jmGc5)7LM&^oyAacV=14{s_wp`K^YIpyDFEM02mXk3OSEw-p zdORS~SGTvf|Cjl{`o#71_3u-2KzcK(ZU7La5JAil5&>9olp#5yVJhG_L?OnQ2x7(v zIfg2+Q2z$cZ7gkJK~)>%8)`3CJSNBlBGKwWz;6QnLDPCN+(q9 zAJ*09wM4d_hZLYxWa z2;mvCbu@F-B1H21)loz{?U-+?@nqk8kw`Vm31QkJFg_V%{OMfZr8mlq(-<|uJGVoHpVClAlh&-bsduQ(hI zi(GsU`1tt1hf_X{d`3<68b|S{tXYwd2YXzXl8Izg4y^21 zp<@H92ON{kB3P1HizBE$;EP~xzks74y{^`3Ur7(FmPO0@t2+WXW`VN|Gc9|AJ43ds z=_5ZJGT6$YN8bIa6HYZ^jFIn`&>W#9La9l$?6@3`ET&WsUkjFK0@?|yO)(6`*1l_s~_L1z$~& z@jZM)qqe)$B+Pe}79nG2sji9uR0#8Z){~%#a(p4yPG;@1CipK8G=YCTO^$u*mj`Me f=rGa5Ym5<}3Pv>t$oVA_00000NkvXXu0mjf+qu}} literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_bg_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_bg_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..310c368e7a68479307866c479d1e4eefcf5db311 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^96&6^!3HF|1ZAax6icy_X9x!n)NrJ90QsB+9+AZi z4BVX{%xHe{^je@`h^LEVh{nXLlN`Ak3Qu?vqkba5WyT9CKZ;N%wBhP~?hKK2LK3q{Q@b8ror6q0>Kp=4vJYD@<);T3K0RYm>I5PkM literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_bg_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_bg_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..70cb7fc7e0bcfb850d4b365f1bccb5b743913e21 GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^96&6^!3HF|1ZAax6icy_X9x!n)NrJ90QsB+9+AZi z4BVX{%xHe{^je@`fTxRNh{nXLlN`Ak40u@7AASF0zb~yy)74d)-}Q|XM+&=H%L1l~ z70X`DZ5Q8J;=>T6aJiv_zhUdQx9rw$B!4Wi^!v;8!uD-LM?h!CZ3$B@rZO?tz^Iy& QK(iSCDOJO>Ym5d24oA2hD9A9kkZ#C-ocYxQulY$%dG^s1`jD zWrBMf{hI5z?Ps6d&cAMwxpu9tAQSLC;sV+l?CI!atlqGv_K~X}S&7D6#irA$G%zcr zGa^}SvXODrvrsWB#ZkB-c}-Y}>Q0!#L#9IQCX$ZI#7DnF9fJ8(R=8iR{NJvIR3GfdBS0fGXvSYugM@B@Fy~s_l`Jy)|ccqHxmVzApHz{x4N{y z#Xj0V$LH=@zsWY)$4Z)6--edG^VYGh&b$}$F3XeLt5=Uu0`p37@FaypB&t$KuAm9R zq*|yt7WOdr(m%g{dU1bs0-qy(nh~3JDc<<|K^(;cR4G!8UrKd|p;N zi5zZftW#Kk#vM}fdS+hLQ#;Dq?H?_`8P1nhqmR=j>Au${MMR)hh&5HCA z?cjx6pHV1ZFFx`ra1m|YMALE$u3RAxZp(6Eus@DJwzn!G7Cw2Mm%K&AN5Ia`DuuPd r`dvHM#yxB2nYDo;0!e2cs)*3P7gB8$K+RT%00000NkvXXu0mjfr&_ZI literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_primary_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_primary_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1c269205e874bc6addc308efe5be4fb7c5da0edc GIT binary patch literal 917 zcmV;G18V$CDOJO>Ym5d24oA2hD9A9kkZ#C-ocYxQulY$%dG^s1`jD zWrBMf{hI5z?Ps6d&cAMwxpu9tAQSLC;sV+l?CI!atlqGv_K~X}S&7D6#irA$G%zcr zGa^}SvXODrvrsWB#ZkB-c}-Y}>Q0!#L#9IQCX$ZI#7DnF9fJ8(R=8iR{NJvIR3GfdBS0fGXvSYugM@B@Fy~s_l`Jy)|ccqHxmVzApHz{x4N{y z#Xj0V$LH=@zsWY)$4Z)6--edG^VYGh&b$}$F3XeLt5=Uu0`p37@FaypB&t$KuAm9R zq*|yt7WOdr(m%g{dU1bs0-qy(nh~3JDc<<|K^(;cR4G!8UrKd|p;N zi5zZftW#Kk#vM}fdS+hLQ#;Dq?H?_`8P1nhqmR=j>Au${MMR)hh&5HCA z?cjx6pHV1ZFFx`ra1m|YMALE$u3RAxZp(6Eus@DJwzn!G7Cw2Mm%K&AN5Ia`DuuPd r`dvHM#yxB2nYDo;0!e2cs)*3P7gB8$K+RT%00000NkvXXu0mjfr&_ZI literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_secondary_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_secondary_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..40d0d1645cbf05e30bf092ace45403281da7f318 GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^96&6^!3HF|1ZAax6icy_X9x!n)NrJ90QsB+9+AZi z4BVX{%xHe{^je@`oTrOph{nXLlMZq=7znVWA2oV&$ZSjW?F|h7ziq5jS#e}ezd(V) z{M(JTeF@SBrcbxn{QE=WZYK^04VRD=846z*9&b9ovtVvpnl(eT%D#{N!SzC3^S3#* f<|u1MCr7h0-;i__`(soEw28sf)z4*}Q$iB}%FaDT literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_secondary_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__progress_secondary_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..40d0d1645cbf05e30bf092ace45403281da7f318 GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^96&6^!3HF|1ZAax6icy_X9x!n)NrJ90QsB+9+AZi z4BVX{%xHe{^je@`oTrOph{nXLlMZq=7znVWA2oV&$ZSjW?F|h7ziq5jS#e}ezd(V) z{M(JTeF@SBrcbxn{QE=WZYK^04VRD=846z*9&b9ovtVvpnl(eT%D#{N!SzC3^S3#* f<|u1MCr7h0-;i__`(soEw28sf)z4*}Q$iB}%FaDT literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_48_inner_holo.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_48_inner_holo.png new file mode 100644 index 0000000000000000000000000000000000000000..c8358e9cefce502030416e05dc8faff139b886b2 GIT binary patch literal 2081 zcmV++2;TRJP)YIdx5%v}IY-E={))x>B}kD^;1aO=v<01PBB|;(|LQ1lm?k zLWq;Nn-CY=ae0(~!^>I`t6s zs-B%JpquWw-vVT&b%#DKYKZiAR|9AYVtSC>+D1~E4^t2*_YE}4C7t2scS_b&i9ji7 zBYSvMwdlT0Go+O!I1;=rq$n|BisnJx=53v0;@hqm(7l)*=4rJMo!clNrP~Z@m{E-} z^JZ{ZNHx@{flX?mQSo``X|C|5u79fpM_&?X60Kt|A5rbxJ7+XZpRQ<_6xsZ!_#wo! zj#h1_U5!M-Io2>ob>UEYg+LRijsxnVI$Sub8=TigMynU~iXTIjns`*ZXjCM8l?je< z^3e1OfW}cB&*(9#LY#4(p+|S(CFYo)RH;RK=~N=zD5YZ@e|b@)#etF>)Z-yez@UzD zxn@bF&zGN~8oIPk4dfy-rEX5Ww8$EZ0F70%U;9F1W%-Z($&Ga-Maup1vncKQ7_DKl zn9!@7d$FjFqs1PKM)U|Dr6$Db)oTnV%fNxx{Okxr+DM%Qs^$R=K0p5VBBLXP|Go*uWAqrP!s#9EjG3Y5H)_%&0w$xIP8)2<gS?toB)4w_5VP~5v52jeNf?a@l%z&Ft# z7nB8|dUgD~fFBhAa+9}!Fnz66uJJUZMq$&Z-=x+YQJfJpw%hO;S zbE}u#&MHNeP>Upl#AP)>l0hdeKfNO4(#tQm-Akeu&02@RbFR7XY>6_k1%f(YAT(#fsAW zCKBlg4QBOIpq?mn>zJh1X=9x9hp4F}kQ(@481j?!sz3o)0BA?xOCB;{@vwLHR_qA* zZA`n>5_V~?==zrnj46C`9p$WNjB&zGc+-W7;QUT(*KSn_p>ds2!NyfVppL*7{NFHR zx3J%}=U0sLd(^D`)P?PxcXaJb1;-WXet3d^dmIcA@AOk%p(p(THF8j!=km|#V)bYd zpicX$PljfTc@O)})|@FD=Z~mC2i2imPj;N6y7k2(V~h2N*p=p#-z6}HxcB*hYkSJV z`IFSdb9yY-P}dA6b@>ZL?=z9&3we?^d^OD4aqs1Mx13&f#Qiy{cDn?wohTPSPjL-WpW1m}O&Ju5YPHyotYlm=9`GcY zrwYvY8;-f&ZSM33oCpsge2-Ip%afm3V!sl6q6gM{kN3J3%|Xrhwg)`uVUIiGY!FzE zIO3Qa-0aQX;)a}NjB&uQ|K;9KmvHqg(MeCoc*sw<&DEj$2|GyBp7MmJgBi=!jyvfZ z$6Ymtf^mwAKHp@Hd-~&L-Nsi~>l_hPjymE9wjDU*%(E+7 za!uA`P2O+vKSpg~;?JJlUH||9C3HntbYx+4WjbSWWnpw>05UK!F)c7SEiyAyF*Z6g zGdeOeEigAaFfi_TCsF_a03~!qSaf7zbY(hiZ)9m^c>ppnF)=MLI4v?WR53O>Gc!6e zGc7PTIxsMwC7)_* literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_48_outer_holo.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_48_outer_holo.png new file mode 100644 index 0000000000000000000000000000000000000000..f62f74bb38e8818fd970b7ec1f7862e543cc9d07 GIT binary patch literal 1811 zcmV+u2kiKXP)Q(x@RlU0R z*6*F+o^#JDHf2*b#j2Gf_PMBSbuGRn) zDJUkGcinCw!4`)d@_D~EMJnC5dvGXBz z^GjW6Gg4BPB{MBwxqQWN<0fP#?6J=Sj@WNJ!AH@8Kl`>9L$xnJF(@mqT0WPnt1qF1 z=Fx+;deGw@bGK5OQ+L*P{Upq+6DX1yGQbK>T~%EkI?XGa@}$o>ppa%>^8?Sie*2l7 zfHK3%D>%7|N++0Avr7*8vd@}G^Jo0fcfyUHfnsLZ&jU?a6Rn7I58e-AIzUHA66jy!AvGyBgcAIA_8&ya%2-o5w@+x^Frq z7x5uqjDu?ciVPZ-34&-=b^T>U$i3owu8N|PCmm@W9a)>Z@0e@OLVt>;Q1iTBsK`Y- zJ#Dm0pva)1q@Sv}wFUZZ<(6Yki*muoJ=kjDtmVDYq#tH=k$<|@5vTpkf+%-~CzQJb zDj5=FGBxvks&SW*YJTnCqA2*7ySf013>jGQpITpe;Jn|eigLRhZQhTXHIx~a$pm$C z{nZbIsz13R7nL1tHd-@KF*$Um(og?cC1;!x<)VYeI|B_UB@HdgHw5UWlj@?}cDp+O zMal|-j9w2i9i`?Cb8^v;J)JZZ3@FG_LfsGv{MVdZZorO4w{8Y134%<%0TH$=m)%OW z_@u(SziK>nET6ihG`KOcU?%zJh~m2+ycN)r5;qQq+h%%Xy;f)Ejn0a3UnsuS^+vZqWP#0th z#x}@k!|oI0qU+rNRV>J4GUFR$v|a9z%jMoM-5IE6CMAy{ll?bZ%p5f-7cDwzt|L%b z^86*Y-fp1pM3X+OAj(~JqWJ*PYCpbZCY5MgZSAj)V(>vz$zUg(ZywPKsOqx1Or~s4 ztCPVxWShrQgx&N<^IZW2u9-7hOofKj5BzxpoW= zdO}GqH|+&2+j}j6LUh@cv}2FCzaLvtWZ?^TwHb8;v&L-C`+P^-e$fT!yBz5Da{oL7hj@h;h3%R$P7X_J;dmT2? z8&V8*_<~22M7c%3b3D}BjlNwczv7fZds1ebGU8;svesTmESU0X4=BlHYF_eOt8iaY zL0I~yq8N;M$m4dU73%)xM=srNe&@#dxWo1;CZw8+{^f0pouFbc zV#*`lZz%0)HGlQf<_c&{Ktx7;z}?CzodgvZopY&OUp7)Q;eaFVO?})iuy4L9j zyLs2K^qSz1EvYP7>Ws{|~_-QddT;IiL%she&}m+lY?b~t3u zik_CPT+O0+6?K`iA!CLOr{nnY$OW(ay)*42s|TRe$lC9I+YPJ$b-IG8H~q!myML>= zroa>ruDyrb zV`&jHgSNQCgmI$=lu=hRYuXKOo3_xM&-4jsmA;l<3@^Ph&(-?zXM#=Hludb0$^QZH zs3&Vcm*{c;001R)MObuXVRU6WV{&C-bY%cCFflPLFgPtTGgL7)Ix{mmGBYhOH##sd z?sz9s0000bbVXQnWMOn=I&E)cX=Zr$HaasiIx;gYFgH3dFrOu# z?f?J)8FWQhbW?9;ba!ELWdK2BZ(?O2No`?gWm08fWO;GPWjp`?002ovPDHLkV1l}_ BPJaLZ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_default_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..eb28ff9a5516c15667fa8fafbc22d608d1f77a06 GIT binary patch literal 311 zcmeAS@N?(olHy`uVBq!ia0vp^%0O(y!3HF+1t+BgDVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9s(?o1QL?ArY-_Z*Jr|WFXM+FkX}IYI~tj_}8!bFJ^a4j((ibs-&WN zGIsXEx)Wtn`lnsEAmpSFI79ccn9RKAsn<`<tk;t}o>yjV{qp%WbL{dki&M)*dw`x~@O1TaS?83{1OTcY Bcf0@q literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_default_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_default_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d281adb553af892f758407b846bf31810b9d776b GIT binary patch literal 312 zcmeAS@N?(olHy`uVBq!ia0vp^%0O(y!3HF+1t+BgDVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9s(?Tb?eCArY-_Z*Jr|WFXM+FkX}IYP%rckLbO*zpbz{y7bYSIrPClD)2Hc3qcaC*%7oYhKR%+5DyWbJ~oU4#{OKNlluqE0VJm zR?Ud&kaA;Q)O4{aB-unUR3g{I@EB82%f_aZWF5r`AFqi`v@HN~5*v&Qo>cRA$gv99 zHaapFv&*%1#4~?bwda`9)~}vNKHF@K`t|cGZ}Xb{RR4x!PC{xWt~$(69DLj BcXj{( literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_disabled_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_disabled_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..b2985860907ac324b509b76731e8ef9e01bcef39 GIT binary patch literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^%0O(y!3HF+1t+BgDVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9s(?E1oWnArY-_Z#r@{8;G<#%>2r*^uo7)-)HXL@_O1Ny%Iq#{YfeF z(mvLmIJH1t&`=}DOJmBWhqv04yB582t6X;JXNKdwfEg3JZl{PztUeIIdQ8h8YDr!LqoiBzejNy&kDcJs%rP689)vmGI{X_;^jtl6gm^<0^v)GdFRa+YOJx z7F>vKtz@b&Rr+MtRJ_Cdn)*bIu9V&{pI@`*?C`z(Yf|Vzp#K;=UHx3vIVCg!08ssU A5dZ)H literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_disabled_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_disabled_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..4215396dd4e51fea9239323d313b72fde0ba86d6 GIT binary patch literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^%0O(y!3HF+1t+BgDVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9s(?E1oWnArY-_Z#r@{8;G<#%>2r*^ujlV;{V25Ur(E)S0c!zKPhEi z+Q+&RrxwTy8fpZ2X-wJl@K&30*P>T$mCG*u%y7IHFk@oZ?G!PI)dwP2k7*f%?N0KT z=P~Pe`QZt37-AUDv?qm~sFi(Y>bsQr3FCw4S+92))lbOG-Y30G>`_~0 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_focused_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_focused_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..a280eabf59b5eb69fa2a84280402b63d5e1bb8f0 GIT binary patch literal 524 zcmeAS@N?(olHy`uVBq!ia0vp^%0O(y!3HF+1t+BgDVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9q_DjO#pI977^n-`=$MKI|ZI{A2#4tV=npb9cQAXy4X!_bwM}{Q4K( z1sl8bnxc=22fURRmTQmkS`l-5N%{4LzmAq3{WkJ?oSyR(lyW*m>cW(jDj1r7drC_% z+Ahf4U7%?EfVHA#U$%eE)HUhV{* zGqMRv58QeS1t+_UJh{!Nwtjop`q`x&KXzE!mvvsrOU)9V|3+xFYu0w7ttSN+pN66C zV4oMA@AG&3wK%+`$wcPZ<#Ux2T-c9-*heq_yZUm|{V%D1UlxhJm0zYfUETgVr;hpA zt-Fj|Jsx=O$lYh^6WL+vBibSA6WURD#!g`Ij9SHG25Jg!2FnzxlYN}N9h%V=a_mM! z$e|leQ;yweap>IrEpmd};fhV2Zrn5uN|m^)*v*dyQIi{G2ej@g`j zy#1roz10ezmNeBYwbLI^0W9{MT&2dcxOa)`zb@?O?Gu2 z*S413TzCHUdV}>`f)DaiKP_4HkL&Y-WAl>F%y}d1AGY65et#XKh5dqWo7Y|}14bu< Mr>mdKI;Vst0N8Ej(f|Me literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_focused_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_focused_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..f8d619b4d47ab5b104d6b1042c27fb16a3beca47 GIT binary patch literal 523 zcmV+m0`&cfP)C3<00004b3#c}2nYxW zdK`GU$CA-E+tg1FUj3CV1Ez}l7r{NB_YWZ zgb+-Kh;2qAgunr)owSNT9jE|#(}iQ{0=K~F)j_f4%AIwfW*LI4SCjSena$3zhl@?`-N)f>fC&00iU>|7tSL}YGdG832Z z7Ry93w=$W@5~IozqskJa$`YfBUCf~8@-tLEe(Yg7ZJ&$d5^vAJVlkbz&)H#>=1rCU z=lI*@D9QucAy4<)W_$YF0~q6}sI5vC!>ie*fX@E1>5KTAKqegRE>ywO`Fw(I}^ N002ovPDHLkV1grX;W+>R literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_pressed_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_ab_pressed_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..955a2f34061ae8ac853050da355f89409fa0a784 GIT binary patch literal 464 zcmV;>0WbcEP)C3<00004b3#c}2nYxW zd0`Pl=$b2!s#>@tS z$Y#JV#)+K6SU+tW#+_RkXYzpRi_e9eTN!5>F{(z4su81V#Hi{OLkTB`etUYuM1<4( zFh4)_STHCiBAh-(+2ze7j|0M$*V@)G5^^0JhFHh^fzV_7Tf?-4Si|T*tYCB@#xY$W zMloF>#xN!zMlhxzoiQdMoiL^$+87%UEsQNlYm7|@05m?}iO1-}bYl(D3Ue3c7gw}A zD?zp;CtICi-;5NDtN#ybjCs$)&yQmArGt<$4!&l7(HXO5p7J23`oDJvMC3<00004b3#c}2nYxW zdPRE!~6H3V|7LaeL+kwzxO}{DvWjdA^uWhB*Ox4MVbeVt$Spwgkx< z!VkuXjKgSuY)h6Hw=%|LL;AyKLdLC(F?ASO9Y$7%k=0>jHH%rr7Kwb5&>UvDaCo}j z=j+357qeVAJX{{~a_138(!I8ROa__X7ee%7enXtUzOE0mAw(ah0z?m{B1Ao=21G5U zCPW=Z0YnW(5u`pwA*3EgF{C<11Ed;86J&FYMhHOp8-||_vny?o%`ne52fWVraQiWC zKdv-wupMF9(yd;3%<<_PN8|TOh%C!a80|#$F{54SO;q)d{~Z)(nS?QFWpYf|szS`q zFpt2hCCEz5&mZk`@i_(t4MLWruXxh=CcXUn1{k8P{&E{)e*gdg07*qoM6N<$f@(ay AcmMzZ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_default_holo_dark.9.png deleted file mode 100644 index ac36c068c3da9b9c824794671975d92c8cb4812f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 378 zcmeAS@N?(olHy`uVBq!ia0vp^`9N&X!3HGXc~6@Tq*#ibJVQ8upoSx*1IXtr@Q5sC zVBqcqVMg_WfJqdrAMK_h9#8?~%|J;E`*ao0NlWUVRlS_&a9mP<#>XaXMC=ERCX>1H%O=Am z#mtUX+>AEAwT6+syww^g zdi~YJf`mP0{cS+Lg|du9{;thHRm-f5fy`N(4+EJiIM|PAhl}#{m>bk7Vi>B zGy418$@X@hl`NMNhi}5V(@$P|Pg3y=nsGYw8(&G!LnleSDOiXroc;VBhks18oC=f7 z3k?0b%{*@h>tC1Ow`M2rIQpmS+b;9-1>8GLr6lqszq>FW)_r&{BVotOJ|NS#)C4Fx z%Y9Mf!(|m9<_@uo2MV0GcCocdFH1EsxFfK3apS{XuLXG@EPa~vYxSyojm97DROKEn z4GK+vu=x5fJ1y%Mvc5ZQ=1o6Uu#iU_8}TYLf5R#}_gt6%xwpUBR`UbBWqz}EwakL= f@x5vH8KY diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_disabled_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_disabled_holo_light.9.png deleted file mode 100644 index fdb4bdff00a2313fef46347ffb4ea0530fbc1879..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^c|dH(!3HExUDe|OQY^(zo*^7SP{WbZ0pxQQctjR6 zFmQK*Fr)d&(`y+R7!^ES978JRyuIV=b;Ln}?O{7E#4)N zX7u;FlkM$1D_Jfl4&Q`zr=Ps`o}}U#G~;yUH@=ddhfb1uQ?L+MIQ#iM4*!^FITa?E z7a00=n|a<2*1s;lZ_Q5Lar95uw_WDv3%GZhN=f8Nes^I$to!g@M#7GleL$vfsR>YY zmiwZ{hs!EJ%pGDE4-`0W?P6<_UY2TNa7SS6;>L%&UJLR*So$>S*XmXG8jU~PsmeWE z8WfuTVDa@|c3RdiWPNwq%$t6yU?Gny=M%lu~TYMBM! f<9pNY$D4<%SxdC6eR$dl7=R3(u6{1-oD!M(ZL?81}u3HK)&izSJm2<8Uh)ajQ0b=bC?Oqh9`3dN4vJ2T|1r%BJ|t@#fvJLahJksbsna<*xm~MowW5+ z>1Mlm1;z;xTV`Lsy!q6GM!y#AoRBT|Ub_QjFL}pbBq2SCh^H&!t^zf_gKjTvR!vI?)QK_(hS+iEHQt7Sy%)(V)Py*=6 zjq0h-%VYGXlx(v8Wi?wA7-BV#`otL+X6P>cKX=JKKb^n7C;enjYrLDpmhi_66xg1w KelF{r5}E)&kKX?P diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_pressed_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__spinner_pressed_holo_dark.9.png deleted file mode 100644 index 3b260170c683924ecc009fe9680e3d98ec4de664..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 530 zcmeAS@N?(olHy`uVBq!ia0vp^`9N&X!3HGXc~6@Tq*#ibJVQ8upoSx*1IXtr@Q5sC zVBqcqVMgE9%yGx5+JPCOm;4IF&?CeQP`MUFAlho=fUusU7;1HAg#jWc*h~oFa2#9m-J7HPexzU_fX?w)y0_>1$$I-gnhGqqU3t5`EVu2fb##3!*89aFY)93H!w2`& znV#f2J~PbjrJ84$g@nQ!%|kPlun?=d_VY)q>Y9CO+K!M}a0OFC_FrFlR!TjF^K13o zTZi8sJ-DWnBitzdV%y>GUn5@&u5k|o_PlR3n%F1o04$aS-i zNoPTz4oLXnrw%p2bpe&GlR3g?*ev#J(RR59RKhB*G)raevz>;2zSPujy;)nCRoBy& zU70_-pz%)Ze6#y;yKgVtc7CZ*!-b0~=XNNRefN)=6s7q6pk#Vi!7>i4gx2f0)I}#B zA6+~9^V}qU_RF)X-TNnRfBF22cH~1gDSvhAzm7*tJ@ij-U7xqdXl7Z>{mGff?F1MM lM1Gs=d|BhRaeutQ{7)haG^%BtUjd_*!PC{xWt~$(695c<>f8VT diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_selected_focused_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_selected_focused_holo.9.png index 1ba35d554811207106066427813fcb04219ceca0..673e3bf10d60cc54b6dfef2fcda24575073adf61 100644 GIT binary patch delta 116 zcmcb`IGItgGr-TCmrII^fq{Y7)59eQNV5Vl9|s$de7@qE+C)VSFH=t!#}J9B$p-g+ zO=)awd}z-jonL$E07vQ!1BZi=`7e!qcp@0W9L3n!Is{ol`J5ctau}HynmUBt*ESo} Q0S#jCboFyt=akR{0Q6uWFaQ7m delta 188 zcmbQtc#Bc7Gr-TCmrII^fq{Y7)59eQNQ2m39Be?cDeLIPiHaKaHJ&bxAs(G?ui0`n z81S?`G!OdV6t~i%g5#@z>=EtCg?@#BIe#0ix;RrZ=RaE<9T4ibG+Lg0m4#qp)TVC3 zN`{7xfVszQLk&x!kI1>-Hem4ae)cQ;Vh~rix|B)Ag$0hyY`p&%xf=LCZgN>>TK-kt m?lWr#zhIy0-)*%WYYY|&DO@%R_!t0m5QC?ypUXO@geCyo#Y0K} diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_selected_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_selected_holo.9.png index ef913cc8e5934d06c04d90547972f2c5ef4179ba..d57df98b501944b4ba63623766c396b5bccc29ee 100644 GIT binary patch delta 117 zcmbQwIE7KMGr-TCmrII^fq{Y7)59eQNV5Vl9|s$de7@qE+C)VSZ!=F9#}J9B$p-g+ zO=)awd}z<({FCRuWWd3CH8vfF)e6eY%*@RnuPrZ7K3CVaN0n SesMsP7(8A5T-G@yGywoJigP)Y1NsF{aOK#K&;wFc$Z$xU^={HaR;mz@qPDK%u{~pFAqmB${!Ru73zB$v zOMmS5*G~YjT)qxAl30}CAaY~_U{l7aYXLy}_nWO7cDv^-0IXKG!R_Vl*AWc>0YD&y zlwbVr(3w%fr1LE3KXMGr42d)SPC~dCH0k=0Lkpd3GDn5xDltV>3XMdo%uz7^ogn>V@560bfA5((B0S2iz-E2Wt04z_4dP<YpSBT8lrJKTrMg2EfG8n8-eoq$FOo$>0! zRWLIb+6;Zq1UiaIR#Yw8kfWw^tdJRsVhZ)d1(3A|qKRy0Lsz|LbmFrjV#Cj4Yi$bv zjp+jb%#KH6`{j-Vfc54uIz-0n@&4*x9FYElBi5S(kPhjS_j+@{H`$fQ!T=IjPXGV_ M07*qoM6N<$g0^_tDgXcg diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_selected_pressed_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_selected_pressed_holo.9.png index b8b1fcfe26558d8465c82a517b81f59ed9e15673..6278eef472153576c2d1d3f8a39a7c66917724bf 100644 GIT binary patch delta 116 zcmeBYn#`!!8Q|y6%O%Cdz`(%k>ERLtq*;NOkAn?JK3{Q7ZK9%vm#L?VV~E7mWP^LZ zrZhG-KD6hN&aXXnfFsq!$l+jQ{>v&gHXVl53f#=hM>v|a*cU1=Z)0F&Xj2h(zpyU( QG0-3ePgg&ebxsLQ0OgAz9smFU delta 241 zcmVd=MNVNh$=52^k6po0d90igz_JVcDiC`zj&$e#A zql`XAHt%KNQi_^SOk7hKA;)IPN6~$)VL`fJet^)pl(t3$!y!wk3quzU&9eDUb-%+q r{Zxh9_4~5B{HMS)M_50$X^#8=Jxe;hn=C&300000NkvXXu0mjfe34~S diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_unselected_focused_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_unselected_focused_holo.9.png deleted file mode 100644 index 256e8e7302e490535b52dfe719dae0c40c4434ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^Ahs6=8<1?uI(iXEu@pObhHwBu4M$1`kk47*5n0T@ zz}*SLjOHg#uLTNLdAc};cyzwKX3N*)Akp%$oTpR#k=L<9&I{TXD8zMgNA~i%)Hy|P zNgKs)I{R+({VmP8VvisG(aX{DEcyH9q3KVC1{J;2rP0AWs}+-a9>;xVdGTvzHlOQi z5wUz87_iY6Ik5KcnpK}m?)AU6KeZuu$=z?O^q=n)|J67l-~`YW44$rjF6*2UngCq( BO<@24 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_unselected_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__tab_unselected_holo.9.png deleted file mode 100644 index eaa306aee14b3074962b9eb69f7d66f40b3bbc7b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c8!3HGtQ{P+w2^2edhHwBu4M$1`kk47*5n0T@ zz}*SLjOHg#uLTO4db&7DJBbQD0#AUB zH}C^0-a~%p}r-FEkk`qbJ!z4GNE43s#KK zNDRs@3KsWHgcd0#zy)_t5P&p3Jj$#!qre@_`~aORytx@CS|N~E-DYX7!3q)ywwf#R zi~LF{d_BSz^f=YGK|9ZM0fn=bk}vu+>y{m!nweA@)C183mI|l2t~*ywL~IbQ%zQ@4 zjBbYqbD2|k7rF+l5n4N-Q9@^P4dyB)b11YKCe8!~6qBszTC`ZB>NPgV3`H}Adi(;& z=z(Y=hl8P;erL4fy&+@A?PjoH0D#W)0RU#3jdA!27YP8@x1Y1W&i>rr94*ncBrxA_ awZm^n)5h{@F-;->0000ERLtq*;NOgM$r78h$jjo~WqdVeIMR7{W0#+2G!< zDUFSd5AAuR^J`BX;7BzwayS^7|FTMrO^0E*g7Pi}?kVfkSIlLcJ()p*UugH_3QjSg OF$|urelF{r5}E*XJ0LRv delta 235 zcmV8;JPzd=SNlH;w09}J5 zB6@o+SAf_3q=DuHK#Cx(1X5NQh%=E%^+%fWB@PwC@i$|*x-|pJ96e(PW@?NbXn&Ip z{R-N>bRoNY8K{(`(-V`>Bt{TlK`)#2SaZxkjIlU?(5RHMlMp6`EU8WmRdDsP`%blA l5re*~#O3^X%&X9TY+tubIN1y9^z8ru002ovPDHLkV1idQUMK(n diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_default_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..70c0e7396edf0237e8830748f2ee74dd505fc0ca GIT binary patch literal 110 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~k!3HF)wbmE`DN|1u#}JM4$v^)8w`Z37Am6po z+v)2g(?*6L{Kh9|q|6ntUCgFX+;C&MOHPl_^o);w9EZO$F?5z?&pxrv{5Q}522WQ% Jmvv4FO#o+NBeVbj literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_default_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_default_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..36e71d85d08310865a37a38a5876dc78d4372af9 GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~k!3HF)wbmE`DFaUz#}JM4$v^)8w`Z37Am6po z+v)2g(?*7d*QRRDn?J5#Tv6p96EC#Ua9@Rb%R>f+&Xuw+O+F;e0P1D%boFyt=akR{ E0I7Z;-v9sr literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_default_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..4be4af5fab3a09cce65144c747f24c6ade600359 GIT binary patch literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~k!3HF)wbmE`DPvC;#}JM4$v^)8w`Z37Am6po z+v)2g(?$k`c>N1yj{}(xupO|Bb9m#eWaid)`oBujjyMLj^RWk-B)8T8wKI6S`njxg HN@xNA1NtG- literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_default_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_default_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e72193f5921ec091dcbdb7a6da540c6ae62a0abf GIT binary patch literal 103 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~k!3HF)wbmE`DLqdY#}JM4$v^)8w`Z37Am6po z+v)2g(?*5`F8a+MS1=|pKR7U*C#OeuU+2*R28QEj<(b@LKCA=kWbkzLb6Mw<&;$Tx C%ODE? literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_selected_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_selected_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..8f20b9d2673d84e22fe4f92da5c6fba5524bd7c9 GIT binary patch literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~k!3HF)wbmE`DN9cm#}JM4$v^)8w`Z37Am6po z+v)2g(?$k`;P+>Y&mX9;kTm#w#$Mr{KU16J0f(K87k2#dS899B%AjFfa`@;vsXm|~ N44$rjF6*2UngAGyC2#-$ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_selected_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_right_selected_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..04f657e1db10e9694c00a2d0240c4dd96a062c37 GIT binary patch literal 111 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~k!3HF)wbmE`DKk$O#}JM4$q6$m+Zg$O@E^Uw z81lZJ?Gxk7s`Po4Y{w3tY?zt;Z*oT>n?b-q29KD3>Vk*AGBMnIke8aaIU*2f0)wZk KpUXO@geCxD+9O{8 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_selected_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_selected_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..99309ef6d3e32a2d3303400aa061e0508a70f758 GIT binary patch literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~k!3HF)wbmE`DN9cm#}JM4$v^)8w`Z37Am6po z+v)2g(?*7dS92?$NlFNF3%qKd&uD!9kGjy}NRLj&jF%7WCrYdnXQ&Wp*=?oVF$ZV} NgQu&X%Q~loCII6IBdP!Z literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_selected_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__textfield_search_selected_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..9bde7fbdce15a1c2873eb0779ffc0617fd9b15c4 GIT binary patch literal 112 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~k!3HF)wbmE`DRWO3#}JM4$q6$m+Zg$O@E^Uw z81lZJ?bE^f8J_14%!p_Ru>Zp|qw<;kM2WLbT|5rH?EgED6zpZtm|hnx*$^-bXas|& LtDnm{r-UW|n`=evwJLPDoBk{4*AEnmdKI;Vst0H2gA*Z=?k literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_bottom_solid_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_bottom_solid_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0706c8af658bde9602634950dfe3d5fa5886163f GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%zMd|QAs)xyUfsxfz<`JK;_Z5A z-Y@ApO*&r-OgQM+#9X>wkYiu(tId138dhyGKCm}H$eLN@qysZ=3D*)nlM7YC@0xyy hn}nCMmBhQI$CPR`ipOiMnG7_T!PC{xWt~$(698&aE5rZ* literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_bottom_transparent_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_bottom_transparent_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d814d02d31183b8f00f475a05c124004983d9eff GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%PM$7~As)w*fBgS%&%9EC|%_%783w8jlt8^&t;ucLK6TeKPwmj literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_bottom_transparent_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_bottom_transparent_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..b139c8e49168e4404df0a46b30a4b30e90c1ccff GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%PM$7~As)w*fBgS%&%9ECY>s_{MVWOZ(=mjBT1_sGr W&p6(H%v1uJ#^CAd=d#Wzp$P!PC@9VV literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..738cb38d072137cb68723c576a801e3f3471bd3e GIT binary patch literal 2849 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 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..2ed75a767a87ac573cb7306686035f2100459fb5 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^Qa~)n!3HFaZu8v$Qfx`y?k)`fL2$v|<&%LToCO|{ z#S9GG!XV7ZFl&wkP>{XE)7O>#4jVIz7XKNB(EC6kA5Ry@5Rc=@2?~6F)PwUxdYTwn zdMu8}YM6Xys1i$1bTr(^uv&TM3(=CrV!crU$Q6V-%Qg7n#gTe~DWM4fl0G)# literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_solid_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_solid_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..743d00b6cd7e446c7badca9dd11d1579404569cc GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%KAtX)As)xyUQ!e~V8Fq8aW6aH z`M>?!MSK0VJ5DH+1)MRKpSquM-S5BdOIN+&sn~jE%jQNlsf-1UY_}X6mMgq#dKVMx ha^q%Y#@a>3az|3`-r6;1y%^A322WQ%mvv4FO#tkfF|q&v literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_solid_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_solid_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..17c1fb921f9b7b46aaeefe7afb8302874fb0abd1 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%KAtX)As)xyURua|z<`JK;_Z5y z;?s*`91mY+Vs~LvSAIRQ|I~ek>wo_(4hk(}+Y^;`>!t%UugL`m=C=w5f(6PQ%h%~C hy?JA^CG4Uk|5eN5b2qlEYyz6g;OXk;vd$@?2>`YpFM0p~ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_solid_shadow_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_solid_shadow_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..ddfc8e3d5c4131f2460254f183938477fc5a0679 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rhed`}n05R21qr&#kfCPg`@kT=WR_nY-)l@u)2m z9YjR(TNrC5J8zlf@MOx-MX#^q?zd~tP;1Ok`WbQLQ#YGy{=Yfu7pEGW;JmVaai5Cr S@!LSF89ZJ6T-G@yGywoUXh2*5 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_solid_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_solid_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..007a4b239244212339b817f8de9474a4dc34fde0 GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%zMd|QAs)xyURua|z<`JK;_L&H z*gyPBj&nSGnTg$nOT)YjBQU;+O3-o%)BNS9GKrK90(RDcPwA0 ir}XBH&6co>lKfV`a~Jh`>I4G~X7F_Nb6Mw<&;$VSc`p(G literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_solid_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_solid_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..ad6e1a4d9f3c81e20676f979a53cea2084ce903d GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%KAtX)As)xyUQ!e~V8Fq8aqs`F z7bNtyi1zwxcbrft3piseKXpIjy5E1@m#%ulQ?d2Tmd%Z9QW*;x*={*DELV8f^e!gW h<;Km*jJ1o5{)rFFF7K literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_transparent_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_transparent_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0ad6c888b4c7e436e7d7c78432dbfdaecc95a7ac GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%Zk{fVAs)w*fBgS%&%9ECxB?U?=uVx Y$^4u51wHGE0Gi0)>FVdQ&MBb@0N@ZURR910 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_transparent_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ab_stacked_transparent_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..19b50abcb536602cf2cd36d5a19805464988bd20 GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%PM$7~As)w*fBgS%&%9ECmdKI;Vst03^XH%m4rY literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_default_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..5461b9c00fd3fc513aa4465682e70e87cca36a6d GIT binary patch literal 101 zcmeAS@N?(olHy`uVBq!ia0vp^EI_Ql!3HEv&)kdyQaYY4jv*T7lQS|h5*V8PD@dJb zGfWV2j%0YY@&Et-(u-Ft=sZxsVYp-gbGr;f^5z}?TUWk$0o2Ff>FVdQ&MBb@07WJt A3jhEB literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_default_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_default_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..5dc6f804aea8ca344275ac6eb497b6bfe0f117f3 GIT binary patch literal 99 zcmeAS@N?(olHy`uVBq!ia0vp^EI_Ql!3HEv&)kdyQd*uajv*T7lQS|h5*V8PD@dJb xGfWV2j%0Xds4&4P&{4SYp+J&{BRiiZ!)425)ejdW>;mdy@O1TaS?83{1ORBM8sz{0 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_focused_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_focused_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..a70b53c59af769e3c98973ad9718670ce27259ff GIT binary patch literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^EI_Ql!3HEv&)kdyQYM}*jv*T7lYjjGZ_h07hy7xL zS%<;BUsuG{45zRSgeB^>bP0l+XkK D`1l&; literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..85d7aadd4dfb619883f68f1cc63e629698b5dab5 GIT binary patch literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^EI_Ql!3HEv&)kdyQbwLGjv*T7lQS|h5*V8PD@dJT z6Fe3@|6GeFPb#ATqtK84|Mweqan0i3X%}$jvMQLwz#trO`SaWQ^{znO44$rjF6*2U FngE5o9^U`} literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..f7b01e012f895bfe2c4241e1d48771fc372b35cb GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^EI_Ql!3HEv&)kdyQU;zbjv*T7lQS|h5*V8PD@dJT z6Fe3@|6GeFPb#ATqY%TTAPubyB?B2J9?cgAJee4pt{u!zH{AaisF%Uh)z4*}Q$iB} D0X-aq literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__cab_background_bottom_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__cab_background_bottom_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d8f1c8bd54f4f091e79389603095c99cf825cb6c GIT binary patch literal 127 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 IM6N<$f=1Pyg8%>k literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__dialog_full_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__dialog_full_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..f18050ea589eaa31233bc08e4f8a4e361747bc94 GIT binary patch literal 1003 zcmV%vbFc60S)hq5aquQtN zO>~Q-PMt}eDy?tfo9G5^U3x~HVu{=o-l^#5`3AXbFq#7CZ= zx~R)Z%-PngELWXE=jG+4wH{HY%RHtL$z+_dj#xsD@Y&isDVlJd1j7%A; z{S3ob2!NCVl}{yrl8B^V**9f-6IC==^T()w$-W%VAY54pg(^F>UjitZxrB-eCn8Lf zB*stQ-rl}17K`6RG#lbS(&{_eIc1V`#=6_}di{5~T>e4x!ZPZXM|a{QRmt`XV*pbC z)5T)(D?{j2cRHWXf1>hHw<=z1GC@s9Ro2lk0Wc$?r`}K3Qx5<^GzKt(+iwt@SwZ#Y z1K3Z>bSEt!roEr8rydA`NJoVD>nPSV+2(05UE>4T005_GAOuI89vS#iG4B18N9tN{ z^Z@tNBTj+gCOB47*w+ z+2Hb~>!f2H1$Hq!D=_Sb+i%D|qnZ-1^bbIwX<}v&QHjdz0&e>kOOQ$(hHgzP5DjJz z0f>y6M3En>w55Wi4nf3bKUf4p>o0~xvY>6}4YBjHqH^B)8ba{Lja`ks{5OurR;$m< ZjQ=n8%sUGgc=rGR002ovPDHLkV1nUn!$<%C literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_ab_back_holo_dark.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_ab_back_holo_dark.png index ae3e6bfb84d412c7f9cb402a3baa1e2b4b6fbe0e..df2d3d158e201f4b5bc8f478bfe194c819c762d1 100644 GIT binary patch delta 411 zcmX@gdWl)FGr-TCmrII^fq{Y7)59eQNDF{42Mdtg`pf*)L`8{u1`i;|gTd`&wjGec zSytef4pIZgF~`;(1~P7Wx;TbtoG-n&*UQ;agylj0^lT1}q(o7jHzGPN25TKZ$?cov z|H%JTL#sl^G%-PL@1yqbV!QX6-}ErLn)q$b%tW({iMtl6ckR2%5+cSiDfjudJ-c3< zSha(HQtU>)g_uQmUhGGNWo+VotE}_5b3Zj`hnf_E}Q2koV^c&!VIW zreR+T-g@7!2<2C~cxLXYh02~hOPyXw&7VgTe~DWM4fR05nB delta 661 zcmcb_e3VtOGr-TCmrII^fq{Y7)59eQNJ{{*1qTa|^u6@Kb)up~J+}}81Gf<4rMq>1 zfTEmb1&--3bqsG$Gy;_}uJCkm4DmSr_KJ75aH0h3gXgnj3^(ZGWGt}nJ^f}V{KrP+$zV-W=#rICv z=xjV96x{NvpngvM?6mfGNr!Z7=Pvsjs5sB=%GHUhq~!u%b6=hIBrAan_t8B)L`pmS`g5iQiH@=)TR9^jVYB5*)%(V-7ukgea@4N9} z(xHWGPq42qW%;tkqlLBpj-pV`P1BFTr{~s)))!}A>FK-nB>s*!tJk%*PX*H>9@RfE z_gUM(@MPiq9$*}bmAFQfI2WZRmSpDVDTHL^rZN~B>KmHt8ycKlbA}11Lbb$ovMZyA zxUsH*d5EEjm63^+36O1JWneI~fkSq30i%>RlAIA#PH)prHK1-8kom#+X(i=}MX3yq mDfvmM3T~N2spa`a*~JRZ!KQ^Jg9t diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_ab_back_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_ab_back_holo_light.png index c61e3fa86d8abd80e30157fbda7404fa7722ba0c..b2aa9c265b33ecd7504db45721f6277bbc69c44d 100644 GIT binary patch literal 438 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6n3BBRT^Rni_n+Ah2>S z4={E+nQaFWEGuwK2hw1@3^B*n9tLvudAc};Xq?Zzc+iX4P{i%w`)y*!lC}nMxxP5m z`ipDd|3l#c1q-`17wzs7jap-@cWTC&8}(D4%&X3GaM#!SkY4?Tswdc+PM~^5?gXjDEJr|A(9^w&s1cyzt=Kg=58+)D;SHpB%sRSHFHUToUy>RV`*x3 zp=*`d7Z@F1xvAFw#q#fW_g_%cHx(CZDFFIJwZt`|BqgyV)hf9t6-Y4{85kPs8kp-E z7={=cTNxTy8JPmPRt5&f_Zu#wXvob^$xN%nt--0uA|I$h5@bVgep*R+Vo@rCV@iHf fs)A>3VtQ&&YGO)d;mK4RpdtoOS3j3^P6 literal 728 zcmeAS@N?(olHy`uVBq!ia0vp^5@Izc ztfq{xOI)Ec1&|=b^Bq*e2j?aGI!^4pDg*W zdWdV; z9sc!<_r}D3uO7vmuGYH|y!9z(u7^PlKF&LpHDtN{I1z6 zF>|Hsk5{u!>?_{3^~j}JVTJ_)Rqk1l{%ami?dz~9Vz_ch=w`{q%GmC6H#jsmoj4N2 z@FU~so_V|W@hf^V8n`9N+ONG~e&NG8zk6YshqhhuaEk8-btu}R#1_50nfko&3eHM9R6kW9$Y{^opCbpI5SJr{&cyRCY1m);24z9QH0 zYWBqyhwuL}_1ZPr@Td6yr94JPD>4MqXT9A2%3MvNXWB&>hq=Hw6)SO#C~+=IO)SaG z&r=A=%uQu5G}JdV*EcjcyXFiNP=zW;MM`2xs#P*bSt^5(fuW(Ufw8WEd5EEjm63^+ z36O1JWneI~fkPHWLvDUbW?Cht1|z5jy-hpSfEr{#HU#IVm6RtIr7}3C@sOG%WxC diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_cab_done_holo_dark.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_cab_done_holo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..a17b6a78920848c37a67246a76749b4cc1425a15 GIT binary patch literal 566 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(epwmK8Xr18D^?ZvQoBE&~Ijou`Xqh{y4_R~-EgIfxwlm><>K$vu5h!wc4! z9iP>XtrZVs65@3e-rKIN%Hh(x{ewWxt1j(s|L*kJ zSoUnickXv5=i7?TNH`^EJfpg4#&4;Y0qR0+drTg2JXGfUq3}Rr;{P9f_n*&gD7KkW z&D4IqLivGGRq&kmAH6(eA0`F~7S8rex88HAVS=03cY~80?cpzkFa4S5A6;t}xJ7Q# z9-saRVPfVT##U33AAO3A+Ypl|_94?@cK)tT4*8AF;-^j1iVm!a-M-<=iX&Itr@TnW zJpXO;4EOj9!Ar}#BHVL6_dHGGELXBQqN>Q8)gj~`k@s=>rw|ur?|x;upO5s^{asBY zKb@S=&SWDRsQzHyR;N3i0@8Cfnf~0l`P3PA4VeH(Ut{H!I{}l<<aB zB5gMTgH*M|HKHUXu_VC#5QQ<|d}62BjvZR2H60 RwE-$(@O1TaS?83{1OW6u*u?+< literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_cab_done_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_cab_done_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..b28b3b54f4c81d482f797f31936cbd4013c093b5 GIT binary patch literal 552 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 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_clear_normal.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_clear_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..86944a879b986d941e6567d78fbac16c87ae9244 GIT binary patch literal 1869 zcmbVNc~H}M6fTFTAW9JhxeNgj51OPWje@pKfI5QEBA|d$+W@sTscjVKdVuS?9w2h9 zu!^p(ipSu+I*za)qKMZh4tTpGiYF)@D~E`is<``y;~$%us6_Qf>3EP7d8-+ zSuC3rZA?5JA2A(OQ+kfdV#CSM8yGZ;HF-*gL8aCaG%$}y)sn&B%ahe0pw$F}ae@dq z!XP8kwBcqWp)^OvsLeXHSOZQ80VZdl41u1YRX~P*0ck=rg27L`C^NTgLm=?Ugw_Rv zpPh=2hyrAkkpKi7I8Y4>VL*s*5FTG75={iSFakp`7ecs!hzR9zQ5XikJRqZH)TE#a zEcA;OvkC^&Xxe~6PXctnG=pit3hET2u2VQ z9~N<8VGzQE&zE61CKg~a1QT!t{T$!IN?{zwL_!$n$z%wEg-T!nU&6;R9*)6ME??M> zm6Ik~MXHH@T`i;g87m0=E*6y;2^CElV<>7te+5LPQ8Z;rqYQvdDF7l=YAtD5TdwDG zv>0L3E+#agMoJHS$}g(@hCVJsqzKOFTO4KL4hj`=LnW957mEdaK`0OWg4O(=oI#8; zkfk{OQ!M>kOa)q|UrV1^d~F_rWID#kv<4`i7|nFtQaL7x$+*=PcRNxkacMnTzT(!p zfRg6DJ1Y_~Z$G;tw~$ix*L@nh0_gy+q{K6=O-)U1ZBL7fiw9T#wcP7iz?I7*wg8n!aY@L* z%F1466IZ9xDGw&8Ca%%8-9N%k=5}B-gNg) zDs^~|+ru7gAfdUoeO*+YE(gj=-VB=VaaeB5#xy?WU;B+3~rnji3!zw~u|NB5xDgMA*Ab}CoKR1b4{ zl>=_SIAEWB^HRqqsb8t5;#}&X_CmjxL@oZX6x`u-Nm{2|`y?pbN5T8(*$@T`ZH%+J z9q+wi#oajjm>l)vpmE_mr&lY%70+^a$7TKT;qFtqhuwA!$jh%>ho3F4%BgGKv%2K0 z$HF4;&SJ>7KIHm~u<^wO_8Z;3y_c~N@r~v)LwjwHt(kkY;`G=_K|x(kncTb+Ti2eM z7yH!X-5fzxm)r79(!ZaTJ+c?A_7b`^xjVa7S5;ayZg6q=sKBA)LhBfI?7p4HG-EdX zGM##G-t1BC0PE-nz1YH|+GW>beOJO<&x4C?Y3_ohAr4Hb&I{K{y07O> zYq)siMdY38b0^FH-T7Vnp?+Dwy~?6uy>H4FYTQ}9{^zjW>fFu1k;Wnu$QYKv+~3MD zkL9@kLKD%Thtmq5^yY3(U$KE}2<_4f7b{3i<6pkgb<{dv;FI&fmd#{QXNuR<0GE-t|?<-_xFWf6rQD zvp1?(m;K#mK7kAc23PhCb9_I|Uwpe=_~P7`{<9hKeqT15)CmrGep&{}lJt6uiX0l6LDtGM?vvS&HSN)*I> zeOGt*EnBDP@;N{6y`LG()$~n&=KfpyvX&R-FPte;1xy60C9V-ADTyViR>?)FK#IZ0 zz|c_Fz)aW3GQ`l_%D~9V#8}q=$S`=EA9fW*LvDUbW?Cg~4U>%CWdb!wf@}!RPb(=; nEJ|f?Ovz75Rq)JBOiv9;O-!jQJeg_(RK(!v>gTe~DWM4f-EB1! literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_clear_search_api_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_clear_search_api_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..15b86cbb21eb3bfb82d36aa9ce750906297a9225 GIT binary patch literal 743 zcmeAS@N?(olHy`uVBq!ia0vp^q9Dw{0wkH`a%F)OQ-Tee`#-|*CiUbcIg;ND=p zYvDSd^|6iLOdqf$Xmz|*HxtvIt|l!1HU7>O^~bA&&;Fj*b;Hx}3d6&UEnVN=_&rrS zyUca-tl4jMo@$nFEpTFXzIjD+{<)ibKgss#-rp9f6_EGh??g@(2S&3=!i$ftp1=NR ze5Ls1tv8DvCnWJd(z*Zhh{1dQ0Dw1}N=Vgur< zo}V(7G@F#*B=UQaz!7tS(%x&E*VO)~n0V|`)7|K^f!Elpcvl1$gq+H{_D)QEMqY%8 z_vf1aTF*LU_FtRc+)-?b!3?Ao)T}9E5o1c=IR*74~B%^nkKn;>08-nxG qO3D+9QW+dm@{>{(JaZG%Q-e|yQz{EjrrH1%F?hQAxvXq8M>Z zk&z^%c%@bRQ#)+nOe){kHaX!!Ue%|-vcG@vo7s2MJqBDZfk5<_)|-ZFZPj9NlZ$EDG$w6h z^v#+%T(e!=j16si)bzU4HWV6_^stND&E;|5`nfYv$?gux?t!>a1t>hEvKg8)f3B--`qJ5Vc+(!(3AIVr zEf|cmkv%DM(IHdcJ}Sgr>#(5~Tn4TISAy%nrQvE?Laps69ZLLT!~WS0QV)l|q?Zr( z+%hOrq1e~am)EDre9b1+$FL^?hsoiT)~9EmS!B=eNVF1PP(kFFm`ljix)2F8;hG8d=#8;jP)h%8u`(ez=ZN9^bNjAY1@m$qMwqc*3 zT<9Z^7q-4S8p!6dM-010M=(>rk1eytHi>R-cR}tW4SUbF89%`nk>dMSnMgg-f@tvLl z8zJ1Aj<77hi)&@}=LO_3nTIUJfhLK?)MTgjijKG^e1tcvx@U?wd-4zBd{w~Rm8u&) z61IEoor<-v>QlY};sLy%=GMYsYZW#7TiibW&xJ?UJ`JsgWSk4`n=4tN;yWe=Mb9;n zrw!^kvCo<)%-&D;l)PgTvU~Z|j|VKn#)IlF_j=`rkH?YbC)&niUyM-$#5;BRtd~Vt zvDwmlW4up^P2AqKxmr=aNvNMq0%A$n_A&Ybf8s&n?eE2(zp1N=^sXKmlORRu-MwkG zqSrlb4;RY>`GT2~ewsriQ0>5-Cr@@n4LZ4_+db%Z)RR$pECx zV&kKm<~rTWsF|5CovUxbAuX%rMqUY#bK_3MXl`zRlnnCM)JOk#@Q|`yZle2b!xrs+ z?}@SMBoaxAn*F`n4c~I!tWN%NL;nce-(Ln9T2XV@wz0+fUe{x3EWBVphWolE&ZMpy zk=t+u)*ULX*vshr>?xS>+y1VFi$&0ZQQaET*YU40s&SgZh;!v@8ZAA*DJJ>D=a=0< zFKXQ=k&~NZZGoK2o`n~+R8w?*R>uuBc#s$EF{m0(={u8TU3kQEm9SfChYCn7J#=g4 z(PaFJU1FFZJS#?cN?VCdd62LmX1(Q&iCokv9@0&`0c7bz75vdTSAVg)Dte++U_U8a z)M|^@vmd{xiq;M1c-`XC1_k!;*hJ-2+0wh;$&M)lJC}axPr((&K~D-GVw^}ZK>;xo z8*&r{B7jDjnH@k`96(zW%`9zDXdCl`2T+hey^ru3{!bx1A}HkS<^L~SLob9t1%PwH KV``51)Bgpr>#?r@ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_go_search_api_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_go_search_api_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..8518498eb6c93e3d4f9f5c806362bf3117b17852 GIT binary patch literal 570 zcmeAS@N?(olHy`uVBq!ia0vp^q9Dw{0wkH`a%F)OQf4-y`wRCHWT>4=v6Z~W)^Ex~}&Cks#3Ph?YL zYs=^PA1JbT)~OR;KkxqfX5VYCuTH8yF+BVMK5jv$P8>M!p?~7X|K_(-ZNE?1#j0+Y zX}rfdsOO!o8=KoP`};Z1zsHB36rFKS#YJJm49Wj>o1-q)hN%bb=nB|jWMKUFU(#;% zzNwwTK`8{^tVraaWCe_M$vxef5w0QpFdP-veDuD zxhegZ|L;vckoBsbjg4*D|NoLZ`&-4e?`K!s|My<3S%8^2?NH;i6Q(?qt2KRNl&_PX0wV*1 z5qGtn%`^R9z@Swvag8WRNi0dVN-jzTQVd20hK9NZX1Yd}A%^Bw21ZsU#<~VThQZ_f zu&XEx;QVw%w1wevX{81fiqT9$oZHH(4a215zM2{s3I28IOo7eJ#J d>KPlRN5&o6d@ywr|9haR44$rjF6*2UngC}HDAND{ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..6bf21e307ed392bf00fe80b162a6ce9115e62c84 GIT binary patch literal 332 zcmV-S0ki&zP)h$s=>Sb2o({EW84x$2Sq@4Qvb1mj$j~;VIQBr2GX>%-APxay9!he7 z8W7h*gD?q**@0LXh%12j6cFzN;xHg)rA0Yl3bh0|IM)O5QD`2|BGz~0I$#-|1SL$5 zlJGbV2jtPKD8?58g7k0zp)`;V#9XwljI@z*K`Om-0V(CcdbDyt4~XM{*o)XuqGd@4 zDx{8=fp<=lEG6&%R0000-rS^s>8d@5ni2hppU0iV;YH8gwNa0%) z{Cz&}Jx|SbT`f+uL?986Pnf0|l@f5k0jz*^zeXXD13Pe$Xi*7R9^s5FmB7$P;6x!% z=kMH0V6IZ20v0@I38qpwTN6bU0_>(U;T<=GYX-1E8)QG}f-;!!681nE=wJ-aU=KPV z^-i_I3K%>@EawIsd5_!T)2R?x1}rE&N|%HcIQa;SqE5+gRv=Fy@M;YVKt`niqbhVk zpSlae%z=$G2Wp@TnqrmWnuKgf72^IDIDhdq{E7X5-;T%%62M`q*b}mOv3|8DyoG;R z;O#l^2#-VHDcnmy=|6xRPAT9SP9@+QP9YE&4z7Z?SGPkvc&h*a002ovPDHLkV1j;z BjTis` literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_search.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__ic_search.png new file mode 100644 index 0000000000000000000000000000000000000000..4be72f108ba1a4f36da5c3a59b1ed08ddcf7cb8b GIT binary patch literal 2280 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 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_activated_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_activated_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..3bf8e03623c94b68d31963ffe7e59c72c3dcc059 GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqEX7WqAsj$Z!;#Vf4nJ zaCd?*qxs3xYk`86o-U3d5>t~CW>mH@a{g&g;s7!l1y4Byva-KaJLVIiI)OpBYodjS ofJx&-C1HsL_x|*Yp0_#7zz}{&aC*>dO_0?Lp00i_>zopr00f~Zw*UYD literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_divider_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_divider_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..986ab0b9746301f2dd9401829da09e00995621b3 GIT binary patch literal 78 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1|-8Yw(bW~qMj~}Asp9}6B-)+^BAxRtXRm= az`@Yw&#rLZUbzUUfWgz%&t;ucLK6T(%Mo}0 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_divider_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_divider_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0279e17a123f8cbb3c7e3a9ce5c5af8e693b6977 GIT binary patch literal 76 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1|-8Yw(bW~!k#XUAsp9}6B-)+^LX%RmN2q0 Ycy4A9FVZ~13zTN?boFyt=akR{01+Y(GXMYp literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_focused_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_focused_holo.9.png index e2449ddd5d21777baf6aee837281b21f41994353..7c0599e3a6fcce1d9b22e47bfdb63afb1d3d9c02 100644 GIT binary patch delta 143 zcmX@YF^_SAcs&OP8v_Hw5&nJMK#HZ<$uool2x>S|I)Hr60*}aI1_tg<5N0$#d3r5S z(81HiF+^f&vcbJyQy4k_v?sBFz~i<4k`fDf;@NZ_tl9oWO)W?0L<8qdj~FhFSqD5O na`FV^|2y8+yWK98f#G|ii1|6omK8v=7&ts#{an^LB{Ts5FJmk# literal 1092 zcmbVLO=#0#7|xuGIT;8WX!Q~^*lA7jCFxJXYDt^M71vq1f;)IvntWZunx7@#Y*s~P z=RrLxs6!DC9z~`@5EQ1U;I1AN^y1xvcMKr(M>3$O$=V`XU@P7*|a)hy4U zxx%!hI~J{lHgsUQ7)=n9>A=Trlkv_2cChMVdy6Iu|Rj1vd+8=2X*zv(1^Z z-dxm0gG!$wCj$u+SP*GsVAXA33Q|;uSHk=7nxV*!30h21J5J3Nie%RDAQ_|CsLsY& zG7f0K3yDNxg5+4hGAzdcE(#J7&q*vxb{`6>c}7(#DQZ^>pHfr}Ay;CUMx#MDc-rw6 z7$Ayb$iZ<@Y!UTWY@`KI+aK#ODA3nE(?zCZlOdy4ah6ev!k+GgV7Z0DF0t)*6NOX8 z1e(hLnq@32jH_eqqZ0h<#-7%GdBufH3Hr{mr{j85$9iC#yZwbiL+p)o)-!QYw7TNx z%NDdzUP)2-4{ex+lu^_i4@6GRaBMsYKvIo!N?eF#Vq9Dl)MSriFRaXS8Bs|BmF05) zD5@yR2}K3GnvLZ$e1hv?^R|yPTZcVe6YF-d?7mnj>p=}UUfFT#y$&eW9OU>l$0f6~ zF|wfPrX8Nc^6W&bK+n7Y4b^ijvXfuQ+(Tc;CB?X`%3L>YQ53SWEQ)MW1!6(~R2OUf zPtF+Z3==lTKh4s+!W|fHcUvDHc83Srcw#&}8WSMehsO$6N-hUqDnHxpbU!!HYJa#i zJ|GaI#?_~hNTj{FdhCq-{mS#p7svZ(#Bp^pkTbYrEU~2uu?~!M%rGxL@Zxmm*?jO~}8;@RXUt@A_Hq#H3w}VIKi47{D3on@S O;aul)Gs=_9eCrR$d|CVe diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_longpressed_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_longpressed_holo.9.png index 3483891c57f8d3c34c194b89f4e370e96795896b..3bf8e03623c94b68d31963ffe7e59c72c3dcc059 100644 GIT binary patch delta 136 zcmbQqF`aROcs&OP8v_Hw5&nJMK#HZ<$uool2x>S|I)Hr60*}aI1_tg<5N0$#d3r5S z(9+YzF+^f&a>9(tHb%}r?MWO!Mx)>amO0z(T4~f&dW*q`^j*XsON)cs07uu6Y&=Ovt*<9y`^luYf9!5h!s&!4+fy$dH3l zQBjn6APP|61(Anh0V8(s;h#?{j^L!*Q2~s;Xuj zqFA67g=9M!i6IA-;hUycN5&9-WySOmla(P-aNI(Qd~+EsC>YVs|S*A*q=< zOaE}5?`aj&wj`*EMnx3lGK6JY7EQTWs+2@oE!yRr<20-xiDji|Rc%4CAT(`NH5Ai^ zl3guX6-g0uY%NTP6S^qZ^{MU-jLts1^7Zlj>n}fEKAGHm^R(2sc;Ut2=Ipe+%ZxDovrE>m RvCDU}VXaxq=G)5J{Xg>S|I)Hr60*}aI1_tg<5N0$#d3r5S z(81HiF+^f&vcbJyQy4k_v?sBFz~i<4k`fDhX7WTFh|GU!qLw3cqJi_KM+_IotOFhs mIe7x|{~d4Z-ENo4!0@k8#5^={&vc+!3>==WelF{r5}E)iWGp!V literal 1057 zcmbVLJ#W)M7`9pzRfS3n420?AA`lX>eYW#qt8Qe+F^yE0HVu%mj(usY);`z1Hg1Ik zsu*DD%*5OY33X(ks0#?OGQh$=Kr9R_;hZLgq3VDo`#$_W&+~r1SYEm}Gks&4VVIf5 zg4v|&6n)vL9Q}4GFTc?xPwH*5io2xm#E8*7+(DobIP0j19B+5)BbsBF$*$jOleWF6 zx;WsR%!W&Yh@u&0u9`-UyMYMkpmjgg*dK4-vB38<_EFIm?5Ku%{=#02R`-@#?%sy0 zcx-hZ%%v(N2oP~V8f=D%nriHjSEc*xnrFe#gluT+sZ(ux8Psr$K#>y)u22#{335=9 z%jNQ2APP|61(Anh0hU!sR0RQy9+s-bURQ0J)<}zt^%F*+T*O*EEzdKy9y+4dQ6n2ZudQ^u!G#6wQt zgCL7*Xq}KI`s>EI)=6tOLVOb?csq7!J-V}FFwNb?LYX1;M!g^Vv?$J|iQVl0g`{C> zEd9fIzNZ?dRhOV5>V_zkDiBtzl4zFXqEQq}ifmQJ9Oq$mNt6vkF)cx=LuguxqL)nz zN>;5{H>9#S#x}x)IH8Nix<1t%VQUv+)mn@kg5ws(o8t~x?qPzH9*#h5wFqp-^~3C( zmFF~C6UF`x@~jvKV3=RkKSy7#SCo=&>EbAEMUiW|t|&sqf=XG2>Xr z`FwtG^z{0tKD;S@XBMwqIzF5@oLGyRy$LyYCpmdyJQNPBFAFQj&-wcMqv|X3Wa{b~ X^LhUEudSVfpV`nh>PzNpV{QKrp!-O1 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_pressed_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__list_pressed_holo_light.9.png index 236597868257bde1d4aecbe1ff474630a05d9089..6e77525d2dbbc1673145d60d775602c85264330d 100644 GIT binary patch delta 143 zcmbQsF^_SAcs&OP8v_Hw5&nJMK#HZ<$uool2x>S|I)Hr60*}aI1_tg<5N0$#d3r5S z(81HiF+^f&vcbJyQy4k_v?sBFz~i<4k`fDhX7WTFh|GU!qLw3cqJi_KM+_IotOFhs mIe7x|{~d4Z-ENo4!0@k8#5^={&vc+!3>==WelF{r5}E)gC@eJq literal 1053 zcmbVLJ!sTW98axEE$yU2>-0$7^pcn4?(#v;n!8-Q15@kuu-8SJOWxguHhD35?WG;G zh>K91MG$oD;NU9i;2@47IOy)`AQS|pzFaTWp>!~iypQ~Uzu*7!;llj2$?*&048u&; zYes{vWAtUmPSbB&dHj_w)1=xWi?~Djc7zz+#cc%YzTHI)WV@SpKA>5K8SQw@7HL`6 zH3$2go!W4TA5t{K%+4jD?W`gK+NkRVCHDKPw=D4761!BepcPh7&#P@kXmM-4>1?e! zs>{w@0kerl34BCskoapstR*FOz^l=Hdd;(7U_w?)?157)YXMYngg}9VIR_RYC<>e) ze1 zLlkq=A{TE4#7=TSJd-gPD0U(*Bpwbx%4oOoIw`T#(}NKF(6SDRgLs%Inle7ILtfw@ z@B3+71M8SH&|f!>w2qsbA>tb-#_N$o>(QCXz%+Nq3#EqC8|_Bq(W2OE26onc6p*@6 zV(A~w^<1rNm{mzoMZGM-q9O>2Srm<8zECcRMKy0K8OKprT@n>JUsX&fRRzH?RaKV_ zQ;^I`p<0$?F~in_nAm}XGF^}A4zcpFSgjHvo8YL4@mkga3q4G5+`}QLEEa%eJ6@2U z)AAfdYoN&6K&}~K9}M!Vc}M6|x7DI<>f$hNRn1p)T~(oC3aXqJ*df;apPcd389r@} zf0`w`q8*rS4_lue4u=N?bYdbp8h39meWPP#)eXIwd};sM-=7;5S6uhx`0wt6A0N+e zpZfHCXL)CT`Pqp#6AE*7bOi1)yUf(yxhLDXm$i*|_sX~6BlC0Z=2ds^{nOsm$cYJN X`{MM^Gt;jxr2|{9&KobvEBF5Z1$0Mr diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__menu_dropdown_panel_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__menu_dropdown_panel_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..460ec46eb0786706610e21ac9097de489cedfc33 GIT binary patch literal 651 zcmV;60(AX}P)!1&^00004b3#c}2nYxW zdZ_-Wf*5)VugS&t+23J}V*z%DOHb#W|`Z#l>;cJ*L_P;jGoKD8nX4Z`xH*Q>s zTvTl`b;%gqS1znaOc|u@tz3t7=|UK<9Hr>BJ|D1%4AOYzE>c>YASL1(e+Y^`_iG?7 z1UL~EK(|`0e*W#*UXt~C{TfUweyI5sSBLVgO?u)p&e9+4(C=i^T1GuQJ|j^LdEE0 zfZFjzm@Nd117_`XxKDqSoJXh_wG-}tW_yHE!!B|TSvyio<6k9eTgoG9O0aTdZJ81x zmbul8Z%fpkT#Wc{ND1L@No&VX#iPVF7hx`c0JdkE;3e2%ZBQYi%Oe#dj=&z+_I>|? zOJi$dCv)FoZJG3n&>Qp|;vSo*JOkf=A5uR{`;uV-QwsX>Ho!a31HXV*se5TxFFA=4 zo=3!%#5;D2+DO|6R;c8b^-B2j{s4XhZw!t1m&l3O!HmBwHn=!)kb6yF?kI1MVX*Vu z<6hz)DH{^YBPWDzO$|0isCW3@P>L98oO;C$E5=4jGEPjLS?XZ=13IvJLaC?O;nLn? z=e?6_T^b`&$N3sK+o1N3^-DyB&=+_N>geY)_rHdJwBJ%s{^4(_WBZ5MLQM53U4RfX laXn(LVYMe-Njr@(d;;;gyUim^Wn%yU002ovPDHLkV1m`SB-{W1 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__menu_dropdown_panel_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__menu_dropdown_panel_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e84adf2d41604323cdad8b15e7034b6137e02425 GIT binary patch literal 720 zcmV;>0x$iEP)!1&^00004b3#c}2nYxW zd09!jyup9SJyH%;E_KZI5Ed^B*iNJmRSj zBG=jNc2B+cMg+dzb=~X>SwfDye{PH^oqQ4$1^~*55|NVv2=ckIR8XoEqC|oOgc2g; zEPA&fNb-^8#Mr1#v(VQn5UdVR@QAWs>EP1 zTHM9Zaim5tPqqk+y4R~ii**RWgPIHWkr2Q-rv~$oD_;OFg!*vQOJ?oR%RhjSvm}}N zU}~@)A@q_TOphE%y@J$^Y;2GXG*T-_?U?-%UNYKi5n>WcgjmBq)+~pV5UB*Fc4!_E zr<_OV^tE=(@|l_%K9#lBPBbeU!!Q72CYl{ozqWE(s>}kg*Xy-fB`%jskbX;(+jyxw zA`k(lb8|^3?6_RfL_?Is~gyeh`O%xX?U(f4nJ zaCd?*qxs3xYk`99o-U3d5>wYsbmTgqz{8?`Dg4L(`abqnuZs;wTVv8ZBg|GX^f4xE z5ck=nld$UVv7H|oR+P30etdkz&;0SSW2^3}yn7y4rozh{Dy3k((DE(NNCr<=KbLh* G2~7afj5MhL literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__progress_bg_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__progress_bg_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..4bb22f0e10e621ef31f16100b3f682a09565c65d GIT binary patch literal 159 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 RY6Dcn;OXk;vd$@?2>^cl_{IPL literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_default_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..29aff4d43f71a025f464587ead52aff2ecae6a58 GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^59s(?1)eUBAs(G?r*GssWFX)$e`(35Y8e@;SI4XCdOETn3puLX+U@Np z`{}{9$F@!!Tb4}GnD8m&^|D{1rP|_tuSV&+Z=MCoD&l+{? zpGeMToA<;$LF?@fW~rUl3#RU765DB+Fm*PQ+)k?pQ&%&Ye!A+gR)$OeeXHaR#_cxq xcQACD7BHRDw&oXmu9s(?g`O^sAs(G?r*GssWFX)$e`(35d_EZ~i&w|H<&_`ZD(+MedV5zj zu-#_I+lqbxCf!wDY`(!qq|2YPZ`s2sD|KqW({JG~4*WL+Cpx;A`7$XPF&b}JE9dda zdDh0P2cC5-%kKDDBus2)4y)97FmX3?+)izQiL;plcWMSG#q&-%rTF<%+zn>y2h*Mj yizj?!^E*(P`ureMOz-ZiFXWg1cX%y7!FpSm=AYI1UI{?QGI+ZBxvX9s(?*`6+rAs(G?r#o^TG7xZ`zf?Wo$i4qI|8=SuS_>z)W_YPj?%Q>u zIp@ANM{x}Zqe@#*i-Jc_;!9;KcT)!P=e8Z65pgErb%iKSkCNb@A?yTt$n@r z2c`IHF%KKu<@hR|E_CSLV|hUMOZy3b87rAYm)KaVUb9s(?*`6+rAs(G?r#o^TG7xZ`zf?Wo$i2t+|9e$2v=&Zo&G1s6+_&pQ zbIyHljz-QjH&*S{-J;(gu&3N>@$LMyenNedpai4+B)&;SOq0|eu$bkReVyxuhm-Z9>GFCF_99MaBsxVXw=u8GrS3j3^P6KmrqN>Fc^oQq;b>Mt0(a$ z!tgX@A7RK4{kGy^A3#w21maN-UfpV|U0)B)Mu)Zk(%$xiP)OBD#retJ&sicWsshEL!WHUI0Z}S=i2Rqw=-{<_oUlU4$I1(Vt^KG}@Sd2k4!kUV zp9d;G14UN$xn@Z2Tv!X1WCiPlZi?T5Wo`s>dMMw4?2=HB&MqLoAdzh3Gg0e200000 LNkvXXu0mjf#CNP@ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_focused_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_focused_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..6536ee63329bb47bec2bf2384aa494923cc2773a GIT binary patch literal 424 zcmV;Z0ayNsP)Km%mHHKmbPH_0G1~QE(|Z z3L*$mIy*=P@!u2&!BHHFf;fuc0uio1*2@YRBct9{0AyU2}iGVkcWw7UUPW(q{Hz&m;6;CQrhm;h30w)z2(`W_Vv zws(S3@Pah`KM=_o2%_3&n+}O86bq(Ag>`_N^4m7drC>+{^&N;72|01L0Qm!AONf3s S@;8qF0000Km%VDkFce0=d)+vOWKIG} zhpvGvb*AhYN}o4m@H1o!d4o*tRBGZMkUCTWmkL{wB~SUlAntIEgw4Gc(!&*+NcHqe zdbonr;tjwaz@#r!B?pk5-j_#K1)p#z)*b-3QShBfQxGf+4==MNa*z{HXhG0C1P_4~ zh;-k(7eP#tUz1`!Wij$Dh)MD;xve&Fv5GXEp_kweUysY@i1cm8S?~wm($ky-rf?^L z4cuB_3%3%uz>Nj2a3et6#z@uGqTe`wK1>2-pyo{<@B~f=x)vOqS_S8F z{BbGcPm`Srko*>0TM51dS0?bbgq{a9*ucpHu=A!M^DM~~^Y@aViMI>L4{MrZFUa%^ Q4*&oF07*qoM6N<$f+pdR_W%F@ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_pressed_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_ab_pressed_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..6de0ba8841d25f20f12e14002ecc4c9ec6a7b2f8 GIT binary patch literal 370 zcmV-&0ge8NP)Kmp@CxKpa3{epU;uAYD{w zoy1-2XXsG+d5c4J(@pInLg`pK=_I6J(k2d`5V?BE{Yj@j2pl)OcgK;0qd#7akgCKEJ@PeExDlrpx^Tf8?8gJ#K-Da<_nm z+&*9_w+lGPs|OtA)dC)JfQDKAb-?t#>nbk~ygr<>n4NOeOiNA8R)UE3F)|0PZr-`P z{wS3Lh~%_Rw1t=h$DO2-+|>0Ilo0LghZEP}j*Edw;7F{TKbM3p1iOHI0}cLp61dt? QIsgCw07*qoM6N<$f;wQ9<^TWy literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_default_holo_dark.9.png deleted file mode 100644 index 99b16056b13960eb95ff81b97f4084763404f1ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 302 zcmeAS@N?(olHy`uVBq!ia0vp^-axF)!3HD^c9m`bQY^(zo*^7SP{WbZ0pxQQctjR6 zFmQK*Fr)d&(`$i(7d%}YLoyoQ-g4w?G7xaMs2~0Qf$9^UV|&FvE_gh%;BZrhu;hY8 zFY8a6WvbOXE?|5mp*2_A^U|}ny!V{{IyVaSOiftBlB_DBeK3Mkw(iR+rg$%7kXTcP z#k6a^Uz2!B_1{WnCked@xn+LsMX-i}n1Q~CM0S}*hE157h>480G?!HGRuvHwiR?^` z44rGU0xm@8JUDeI;6lKfjvb8C_dd^P{T?ZK%*!CG32d9r)j|zjwMW7E=e~$M2n70#!PC{xWt~$(69Bh6a`ylL diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_default_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_default_holo_light.9.png deleted file mode 100644 index c820e40a1fa53a02e063689af1b0b22cbb71d822..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 301 zcmeAS@N?(olHy`uVBq!ia0vp^-axF)!3HD^c9m`bQY^(zo*^7SP{WbZ0pxQQctjR6 zFmQK*Fr)d&(`$i(=RI8=S(s69?(!#l@=~!ntl!6G)o`&MW17~=l&s6gI`{agmZrYsRA{(5`9EcQX+C`+ osj_#a-R80lU(+Xt73Y3pk(w;wRWoZtAkb?Jp00i_>zopr08EN*F8}}l diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_disabled_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_disabled_holo_dark.9.png deleted file mode 100644 index 95d7c86e5b4f6bc9e5bb4351ec954efa8165e71b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^UO=qH!3HEnRL*JxDVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9s(?x1KJJAsLNtZ#i-`IY_iUT(7~j&^5ecSL1j4gY^^2WDlBco*?mB z`m)aR+G$otzD)Y0?fLmd+OHS}2DjJSyx%{F7dYjjA-vG1#YhmyxEyA4Ajyemj-Jy@ zj;|_8Wji0Yyz-p5Zf9|eSJlK>cYeM(zs5}PqKB2Y70=q0b|Ee@stK+Nq8B}=hELQvQ^1tM>Th}xA YnG-a>&UD)?3-maHr>mdKI;Vst0M@RAKmY&$ diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_disabled_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_disabled_holo_light.9.png deleted file mode 100644 index 2dba2704f493419c5b3171a3f03a194900fcb497..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 331 zcmeAS@N?(olHy`uVBq!ia0vp^UO=qH!3HEnRL*JxDVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9s(?x1KJJAsLNtZ#i-`IY_iUT(7~j&^5fn>R|nU<%<3?*@I@ACrG@O zzO3`ScAC|ZFOxoLdwzbA_A7>g!R_@n@AnVl1x~qW2ru+$F%kqaE{EA1NOIztqvte} z7`L0ct=SQi8;t1{K~ri`727{4e?J*7Xej YZZ(m@*Zsx7P+(y2boFyt=akR{08E~Q00000 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_focused_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_focused_holo_dark.9.png deleted file mode 100644 index 2e2fadd83cf9209b1f6902b9fceaa9e08650af94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^UO=qH!3HEnRL*JxDVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9q_Dj7**`jv*P1Z*Lh29dr0>e#5X;Yl_m^QtFL3~ z7p<9ipm2rR!~>ZtwoN>cxZ=^VyIMjP+@U=T?on<`?hCz&FKs&gQ_pFyw3_aoGlAUm zn3t+7`@eXN$SIG7JtC(xeytTZ`c|8t;=vc4cXjKsj}K;5=sTOQ(sOY>d-H17ucGyO pR}OW0=m*7C&$l~ou%r4AbI&E!#ml;*Ujl=O!PC{xWt~$(697(_i@yK> diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_focused_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_focused_holo_light.9.png deleted file mode 100644 index 5bbbf63953db1f406e16fbff34505f1bc5def9b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 499 zcmV2V*7i{gUsf_UxO!xyUN`FCXOKTH@g`u<4L=uRJg~WvDWhgw8<2Z0nJvndZb?nZP z$qPF>3?zdj^u3CrD2noJBscF2{tGI~5*1~Min2sSS)!sWQBjuU&_A%sFCv9`XOJdD zBnOm%cVo;;aL>#qrSu^p1z;Ok^_T9AF%O^HTFe=j^z?eO>@U}XG0uw$OS-t*J@U8m z!8oTyMM)ZZ&$XynXN$RrtN?YO*y*>b?QXO2<_*@S#XBiVM9RPxkiULB-n{Ld9Ef;} zv(7ko_55E_EJ@&)D8DAvi75#j5)~-i#ki8d5mCX{tD8mok*HE+~GXDHmyB4OE{ObGx5kx6E$Jf paWdZ>C`w96>hArtlTBSs7y($Dq5N)-%j5t6002ovPDHLkV1j6N)%5@X diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_pressed_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_pressed_holo_dark.9.png deleted file mode 100644 index 083194a6fa111f065ef61e9ad9246a70ec53618d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 420 zcmeAS@N?(olHy`uVBq!ia0vp^-axF)!3HD^c9m`bQY^(zo*^7SP{WbZ0pxQQctjR6 zFmQK*Fr)d&(`y+R7~MQw978f1-`?8qbvQtx?W6j}D-SL?3U0c&(&Bfz$dT+1Vqa!` ziHq4~?Y(?gYSGjntwIm4C2}u+3MD6<|J|ehu;9l;2PXL~!S^ohn=8h6$M#A40ZoG! z-z@g#uJiZfC;qvfd%tG0$?QL0J%3#*o_5ac`kaV$(xG3a^sH@N y|3^Eunl7I4J?wsT;Eye4&o7kRSTg;y`236Eu6ccNCTD=b%;4$j=d#Wzp$Pz=7`crA diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_pressed_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__spinner_pressed_holo_light.9.png deleted file mode 100644 index 29cbc4621542f2e2d058f0440980872d510c2849..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 457 zcmeAS@N?(olHy`uVBq!ia0vp^UO=qH!3HEnRL*JxDVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9q_DjM<(pjv*P1Z*T4OIvgNz?BjC92}chu^z({sY7XG`yXPp#@=$97vck(#_ELt$lCQjmCO_={>z;flP*?Ea3A4tsOvleg z-~3mp@cW&AXU=ei@y6+$b1#`NUa+^jRoCSoag0I9^=608KI4TQUxF_sWjSrM6!el< z*n%J;A26@c;69ejdaUoY&Adw(}hrX_L51*flGgf)f9~6BN;g^-)UN@?1%s!npUXO@geCw<2)@$* diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_selected_focused_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_selected_focused_holo.9.png index 9a33cd2d92874dd09f4eb5d3f924eebe97b25c40..c9972e74bb4fc7416960e238afd47b1ac363e316 100644 GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^EI`b~!3HEJ|NhSh5-4`^4B-HR8jh3>AfL0qBeIx* zfx8og8O=|gUJDd7^K@|x;h4Gh+(zC520Y9MizoD2>~^~(JZa^V pUoEkkaeSh9w)TUlKa6vZ+qJ0**((%Vy8umK@O1TaS?83{1OR&wE2RJc literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^>_BY9!3HEJJUw_8NJ*BsMwA5Sr8n0M1DW`tbSwb=FK+^Rf3lPOJU(KVDPR|J0bAe<1Nr)22WQ%mvv4FO#pfqOKt!F diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_selected_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_selected_holo.9.png index e029e577a711e01450d8924bb7cd8bcb6867db82..587337caf74f9ba3d32ba1c7cc8fb8b0b5ba245b 100644 GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^EI`b~!3HEJ|NhSh5-4`^4B-HR8jh3>AfL0qBeIx* zfx8og8O=|gUJDeo^mK6y;h4Gh+(zC53JlB#xw8$}k`45e4cLk;e3y7!_%!uv(Z^d6 t0#9x~Qa^f(Id{#0H&;LIP<)f9-+fKc+F|3Yl|VxnJYD@<);T3K0RZ_tFJ}M% literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^%s|Y|!3HFERhwS|Qj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>Jii|v6978H@CH?sS-=0~ZfivY;J=+AIS6Aj=Q{WS37HTN$ qQz(|;D3Fkp+<4kRVK;-q0S2o8fp2Rs`~3szX7F_Nb6Mw<&;$SgLM&YX diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_selected_pressed_focused_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_selected_pressed_focused_holo.9.png deleted file mode 100644 index 285116e31e1c3fb26567af209b73718f07bc1355..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 454 zcmV;%0XhDOP)DF0XHC5fCg&1oFoM^V6d>XlD+HCBt>?{(e6rmdU}?_B0{m4Sq~g{wt4!r zOWN(uURJA*E8X9o5`pq1%=xiasQb6`jUKk!*Ufr;;jZ^fbg&jJ#D&#`!qIK=b6In= z4s{w7)41lI%r07#2$`jVkT}Ec$L&ljwAe}zSti7@ggO;j6%rHwP=!Q#LdChy6oR*c z@mo=c%?Ogk{+e}+hZtjm#F&LMNtVI#OlD|XWTvJq05qMU)SFOJNG9*oVf%flkP~v9 z=Y+3jgm<=-`V42?!wN%1FiVM3j0wDEHMGV=kqm5;4Rvd0k?m~ wAfL0qBeIx* zfx8og8O=|gUJDeo@N{tu;h33haPQZY#>U2n_RP$O>mRT6my}r88U}fi7AzZCsS>JiaI@A978H@^#nQcH7M}hZY%G%JHuabG5!aqaP2Bixj6GbE&Os5bkw9sMq-sUhLgvwDil6_u$Ij+-sD=}ZmKxYhgcu#~pn0rP!P zlW+2eN-A94>Tv7U%K#(ixsEr27ML73#$j6gN!I7~MEh2azKZipvd`~)x3!+5XZ7?s c9n*oXua>h?X*ygK2XqvJr>mdKI;Vst06dpdnE(I) diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_unselected_focused_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_unselected_focused_holo.9.png deleted file mode 100644 index 032a9921c54ebd6d8bb71aea1552758efb1efd19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^>_BY9!3HEJJUw_8NJ*BsMwA5Sr?ic(Aw2{Hn)z4*}Q$iB};WR^U diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_unselected_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_unselected_holo.9.png deleted file mode 100644 index 848f3f13363cb940353382afd94e8fdcbb13bf34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128 zcmeAS@N?(olHy`uVBq!ia0vp^%s|Y_!3HE73d0rwDajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9MM|D7jv*Ddl79UEZ_g~yz?s6<;y3q~@R1+qk2LU1_{zW{ a!SH4(?<>94hd6<%89ZJ6T-G@yGywo*Iw!3F diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_unselected_pressed_focused_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_unselected_pressed_focused_holo.9.png deleted file mode 100644 index 3845135847312f61d9874eb4e4e9c703dcc168d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 459 zcmV;+0W|)JP)>s>b==;?%5h#oym!sb@v)nwLuGD#ddt4nJoq6c_90P317A`GSu=PO9R)W#5 zDoaABnMTGa0uGz~EeLH68Wa=l)Td^P5+Sox5E5soyX1+}R%o%6Ok|l5&k`DTj?>9t zrmYnc83`4B*cEsysCPvJ%vNa@o7Zgfu@GZSP|Fg6NwNUTGnHA}qB1pY383j2O1-J@ zZma!t*zvto$O*a5bHX<>!aG|^edb_0!U{u0FiVM3J|^%rn{`X!mWcowRGV*^%Lll& zO`wIX7002ovPDHLkV1hC_ Bz{LOn diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_unselected_pressed_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__tab_unselected_pressed_holo.9.png index 23fd8c9b351c7dc4ca7d61bdf8b0fa0b3357afc0..b1223fe3c407e072bb22d6f534397bf3254939fa 100644 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c0!3HFsSlX9@1d5$JLpXq-h9ji|$mcBZh%9Dc z;O+!rM)Q-W*8&A?JzX3_IA$gr-1{}9v9a-?Ju~y+`p0YiB_$U2xUsRZwQat4>8lS< uMnfl1c4A|rBX^f%!~&s(1*$LFm>5oL2|PB@cz*+E5QC?ypUXO@geCw>u`ROz literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^%s_0!!3HE}@+EEuQj#UE5hcO-X(i=}MX3yqDfvmM z3ZA)%>8U}fi7AzZCsS>JiW)s#978H@^#nQcH7M}h?kex!cUt|2fc?W{-#r$B;+r&$ zCmhJwwN<*&rR9^B`%azPhW7=3CfsE?TiI|eAXVmsigepfZQY<^*$T$v9;+|bZ{5Ls z@x~N43;ta!61B<)ywtP1E|{=7D7Ecj;BU-)@wqN;rGn!(u4Nx%>`hbb@2ehQSYT@5 Uszopr0E4hlYXATM diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_default_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..081657ee7b828a74287d65d2f4644af9c7b55816 GIT binary patch literal 106 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!3HF4Hmy+sQih%`jv*44lYjjGZ_jMS*7QH1 z$Cu9~IqOiSz?8?{Eo||(vKg$oJDqvb4v1Q5NJR27d@z6V;avVV1E6LGPgg&ebxsLQ E0ED?8Qvd(} literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_default_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_default_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..3f312b465189caa47a7f8e4bc53c3222521e0bb1 GIT binary patch literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!3HF4Hmy+sQrey_jv*44lYjjGZ_jMS*7QH1 y$CppZQKez^S5>Et`mrVp3OWu(*tYT>W@HfhtG!C@Uj!>q8-u5-pUXO@geCyVL>!s` literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_default_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..b086fae8738227fc0b4f05171ded25ec1503e49d GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!3HF4Hmy+sQU;zbjv*44lYjjGZ_jMS*7QH1 z$Cu9~IqOiSz{ak|8`Hl@9XRLoNT6Brf-|eO+cr*y`8p4HWnZ4T3DnEr>FVdQ&MBb@ E0JhyB4*&oF literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_default_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_default_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..73c336a77a9c908532b5b39098c22a878e0e87bf GIT binary patch literal 98 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!3HF4Hmy+sQktGFjv*44lYjjGZ_jMS*7QH1 w$CppZQANR3w^={dWI;j4L5+C_+aEG8Z2O~g(C$e@C{PoFr>mdKI;Vst0EP1$iU0rr literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_selected_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_selected_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..726e0ff427cd175c9c3607e25352bd696a3152c1 GIT binary patch literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!3HF4Hmy+sQbwLGjv*44lYjjGZ_jMS*7QH1 z$CppT@G}o{phONwVb}j=LshAN!kv;Qt~79nzL7Xt$zT{YC1>l7eH(zf89ZJ6T-G@y GGywpjU?4sK literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_selected_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_right_selected_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..726e0ff427cd175c9c3607e25352bd696a3152c1 GIT binary patch literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!3HF4Hmy+sQbwLGjv*44lYjjGZ_jMS*7QH1 z$CppT@G}o{phONwVb}j=LshAN!kv;Qt~79nzL7Xt$zT{YC1>l7eH(zf89ZJ6T-G@y GGywpjU?4sK literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_selected_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_selected_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1767c169eef03f3370b0f8e40f531dd481a9b82d GIT binary patch literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!3HF4Hmy+sQYM}*jv*44lYjjGZ_jMS*7QH1 z$CppT@G}o{phONw%V+tnLd~`l!OqNzXB@V%srV-z^vGhE?K{(iZ(fQrP(OpGtDnm{ Hr-UW|vZo$& literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_selected_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-mdpi/abs__textfield_search_selected_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1767c169eef03f3370b0f8e40f531dd481a9b82d GIT binary patch literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CO!3HF4Hmy+sQYM}*jv*44lYjjGZ_jMS*7QH1 z$CppT@G}o{phONw%V+tnLd~`l!OqNzXB@V%srV-z^vGhE?K{(iZ(fQrP(OpGtDnm{ Hr-UW|vZo$& literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-nodpi-v11/abs__action_item_divider.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-nodpi-v11/abs__action_item_divider.9.png deleted file mode 100644 index c30f607d0aa66ce47fe22159249f7925512dd28a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1|-8Yw(bW~;+`&!Ar-fh6B-)+^B5f4SNpps cki~(8q5LmfmduLwJwPQ4p00i_>zopr0KdZ(YXATM diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-nodpi/abs__action_item_divider.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-nodpi/abs__action_item_divider.9.png deleted file mode 100644 index 62332880b099b84b08d0d320452ae55f252599bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1|-8Yw(bW~jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-progZV+hCf + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_bottom_solid_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_bottom_solid_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..575334699663b221b5a2b3251572a7c7a23ddb4a GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nET98VX=kc@k8Z|>$jV8FrZ@U7ta z-*T0WQ@><>I%v71J%hiqt0P@2{q!E)%~9Ermd_VC*s;IdoBnhS>rHk6>|lcSgpVF9 tjEp}SQ%vGx1w)$%c)I$ztaD0e0sua~Gttc^?peW`&R>iA3bc>G)78&qol`;+04`QPF8}}l literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_bottom_solid_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_bottom_solid_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..8155fe840532e1d0fc25450729892ea73c4e007a GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETTu&Frkc@k8Z|>$jV8FrZ@J;?q zbcL8uwC8*^`8m#29p5Ib=%`p$wC&7oqt#odO)b{rdQv>$UUk^Hs0pFVdQ&MBb@0G6aYR{#J2 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_bottom_transparent_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_bottom_transparent_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..fa4d76af93de31de153c6a7d41c05496bb14d2c0 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETcuyC{kc@k8Z*AmdP~c#3C@cDZ z^MXtGfey<_%m2nWx~HUtq@RtOD!V+x#J|ag^QD{sZZM%<(R`m!o+Hzd-iC%RO>bP0l+XkKAqp+G literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..9a70a5d1e3ad43f632287aff78d86289259099db GIT binary patch literal 2878 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 Xx&sG-cNbs*00000NkvXXu0mjfHD**$ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_solid_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_solid_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..6622cbad34409b2e09f69e305455482ee107baa6 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETEKe85kc@k8FK-lVFc4sN{QB_B z&fog}EEk$2&*T)$|Ch61%h`96?xa8O-xitu^~t0=vn)PNZ(|U lO#br3!H&B!tiEU`L+e4N?emv^?*rP(;OXk;vd$@?2>`X4Gjad` literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_solid_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_solid_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..c4272978338a232aa445ed5190abab61afcedb16 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETEKe85kc@k8FK^^+Fc4rl_yt@$W?82D^ReIqPjo#d{bLmpkiN+x lnf&F6gB^EeSbfn>hW*nwPPt#_849$O!PC{xWt~$(697sdG9dr} literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_solid_shadow_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_solid_shadow_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d0df29d8b3fef9f71cda9b7a0975c68dcfb05685 GIT binary patch literal 290 zcmV+-0p0$IP)(^RAa&-b-qmfdL= zKY^DZ_=R_1v^+>Y{!mW=MF!v|2#Q>Q>z_&4i6T94j-Y4q`P>I~g?cE`S~^QhBCU5$ z-8a`dJ38hrt)qwm8XJx0+%VAuW=z7Jg@`1pBAUrf#Ef=wZl|UqH7RO)u1OwK(@xK~ zuV&5*5lN0GQV~igR!o15*n1TfDTP6ilQ72>QBJOyK^2jQYHlAzlrUMuFCtAA$s$=K oi)4{qME3aCu~lSF#Q4a(0o}otDK%H_Q2+n{07*qoM6N<$f*T@rc>n+a literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_solid_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_solid_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..a0d9c1b957ea4a6ce62abd120668610d0cb2bd96 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETEKe85kc@k8FK^^+Fc4rlxca~( z?t=fRa*SINS}wBuewp3mefy2x$=b4i8MC*B`RkorJG1!P69>HDUX#kpcm>9d6MZKb ky7}`x**qcrtNL{AY0h>p*ZiBQ0JN3C)78&qol`;+0O3wK)&Kwi literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_solid_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_solid_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d36f99fecf223779432fb843b823c04d739f05cb GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETEKe85kc@k8FK-lVFc4sN{Ca;{ zvU;8e%Y`P%GdTtG|K%*$a`xS%JL%8+w?$@ueKP6JEX#C%J{El7iLS?_f2=|R(l=Qo klfOK1u;Z=_t1sHgP`H~Vw5GX>6KE@gr>mdKI;Vst03NU~l>h($ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_transparent_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_transparent_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..5ad475dc3f478734be31bc5763ff494e5f120914 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETR8JSjkc@k8Z!P3yFyvu&IDfHo z*MFzV3!h#&I<8{wJG6*7%`^0A*`zgvpO3}4Jy+2bzzZhGPxw0F1DlG16;n~mnRAu= eo1*Vq{$#i=98+;OAz%&ALIzJ)KbLh*2~7aXVK40f literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_transparent_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_stacked_transparent_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..6ade5eeb37d8388813cee512f8adaad0f6c15397 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETcuyC{kc@k8FE8XhU?9M9Fk3-& z>Hkf73eN%?4n{M7dy#!$d2ZSCCv)eTUt5@6!ODmi{A7$QW>Hb7V|gN6#Q)yLqkTHN Y-hRf#&+ODnfL1Yhy85}Sb4q9e0PNo==Kufz literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_transparent_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_transparent_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..719b9234df6fefc32c628a212141681df3414d85 GIT binary patch literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETB2O2`kc@k8Z(Za)puoZEAojv! z?q20mzFS+?F-&~oGw)ovvN+_p>pJvXn6S<7W@Fox#)9&t;ucLK6T;ku_WZ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_transparent_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ab_transparent_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..6da264db26b5debc433e570e454f7ad596d3609c GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETbWaz@kc@k8Z*Aml2;gwNxP9_w z>q*543$-17oYd6QwPclDxvFIP6Y06uZ3-`2R5T~}Ha6e^YubHkRDB$o9=Xj@xc>Lb i$;LIUf5PjFDj6>?G+3v-_OK(+N(N6?KbLh*2~7a3Fg*4E literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_default_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..7ef2db75e273c3a4fa34a867d43714d47b67dfd9 GIT binary patch literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^tUzqR!3HEvyN#v+DHBf@#}JFt$r%|L2@FmD6{OlE zCs-P=E^ay;FECBu-~a#X*$!!Fy;QT1l2!H>nDyu1;UEQuS2t(=%(&d{0o2dn>FVdQ I&MBb@0Ph$gIRF3v literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_default_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_default_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..2283b4c01f31c24c241101989a028a28e662ff2d GIT binary patch literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^tUzqR!3HEvyN#v+DPvC;#}JFt$r%|L2@FmD6{OlE zCs-P=E^ay;FECA@!GWvmzw+t@{SPuqdTbmsKKbP0l+XkKVJ9JJ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..3c909b51306d684dc9fc4deb674ab1e1feb7004e GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^tUzqR!3HEvyN#xSIG!$!Ar_~TGcqy~7@GboNVOeo z`FL&lz5>PtO@Rj=>T@VLG&w|ZbqQ*{RI`whRrVK{_2=K=E+vL!&S{*=@1z8QW-xfV L`njxgN@xNAaNr>U literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..131d1030c9d5b447ef62fc8e336d9d3950ff7519 GIT binary patch literal 115 zcmeAS@N?(olHy`uVBq!ia0vp^tUzqR!3HEvyN#v+DJxGG#}JFt$r%|L2@FmD6{Ok@ zwtT#{-1s4r1MA|Z!|?(x4J`lv|6k8`NJHzTnuV0CvcJHrKmQJQDKT8Re5&^Sxg#LM O7(8A5T-G@yGywoD=q9NE literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..3e7dcdfdbaf66d51a90633e6f601bfe71b0c5069 GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^tUzqR!3HEvyN#xSIG!$!Ar_~TGcqy~7@GboNVOeo z`FL%)@k1sD*2PVS;{{wASQ@v8h$x3#@+~m2a+{}M^7C)Is4GMKie-X3Pa7xz&0z3! L^>bP0l+XkKapWP} literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__cab_background_bottom_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__cab_background_bottom_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0bd09806f5c85ad3a33ec80c2a526e9dba34d1f3 GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETTu&Frkc@k8uN>rTFyLXm;P>R{ z?#-o|?nQl9Ua&YVWQl+9{Kh9CkJo#*NAA>4+xPwD`<&mEu1}vZI664|W68WNxRjX* q7uY2C$wZnF2qKv(-xu6mlE@I5@4DcHNa}B(#SEUVelF{r5}E+w(lnv~ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__cab_background_bottom_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__cab_background_bottom_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..43ed26d4784aa508b93551bdb0359b959bd2c91b GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nET3{Mxwkc@k8uUzCjV8Fq8;LR1* z*j37dP53cYgnN@8iE~W|ez(m3TTj;06C0 vR9@;$usQD^o~Q2-Eg&#Ke!|DE+S9qyz8u@<_Da1C=l}*!S3j3^P6YLYC-!V(AVEFG+v!>way|q9)89ZJ6T-G@yGywpFG&bP? literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..f4970ad1c3278235157ac72f71fc98f159fdc439 GIT binary patch literal 2159 zcmV-#2$1)QP)7pj*K04R=GS>IExgb+dqA%qY@2qDDdSi?}MdX75WMJ|ri_~yampZf~b zyDwJPzURp0aERFLx!K0Z6`{S(+b^7Rq0fZm(kDLm@P!|`&m~8kF)y`OQ+*6SLgj(n*c6WFZ`T<6tC6A%w8 z+L+Kg_>sWYRhaz=AtQLA^@LuUvKr4zS(=h&ATdHMd1uOv+V9M9YYe+zz%fKlM3B!~ zyq*EP{ZyC9dltDoQc<8ZrM^eE_Hte#g^dKR2>{;+o?xX#_XJ<6fcSW3 z(2+n3e1qrFpfvl1x~?#Fy4|E$M6lRgKuT?d8dD>b&VB465lv_ms575+OWy%#u@k+N zI%?Q+K~hGrT_7#|a=gF%@ZrOc@87@w`1bAFU(2$bW3Gd+|4`xmgT=9~$+>Rd`_AEe z?tAPdzh~^4zVA1WkB@)c-QE59<;$19v5OvFA}vv41E1cCHa5&@4N;9-`R?7jpWeKA z^Yg>QL%m+FvDt*4cRX_bt0?zBkB(K>DX%%#=N+5R(_-8y- zVb>j!?$Wbc5y%%}IfCs9*+@_USOKV3tJQDczI|KW-rgqvI6{s^UDwxjUH<~$ckEhw z$wzfwA%@V6dv=Zxn=8;sa(#b)ziOIh-@k{Dz1VCvD9chBW?(0HZ$3-*gQG?|lNRhy zsce!AuP~V46@dEg?(QVrAwo2L-=l3?V9=qSyONQk&Kv_~&Lf1nMm8E$0BV|mEX9~d zNP}Lf5}1xu21h4T$+9&-HQuut%PRmY8i6duXoOerBY}OxLGlJ5BU$zc%^yh8OvsW{ z7(^}+!OmYLNsSuWi7|-^5)oDyq5>gHA{u-eOKk`#f#=$OmM4_(@m{kC%_W5DAmmhR z=d>`52C;YCwuB;r{%j}Ebe_P7K+b^`h8A8*tydWpwYtuV2y(IKDEl%UBLZ0(i3V1m zfUn~Tp;05RlF3Ax+6Y;a8pF(Tjoo`iqE#Ca+!sAl5kbmO&cKL3&H*nkK%{gluy`-t zg(lV{G7z#PI)C*NX293=me{C~cPz9KvLxQ9W=NZ^Ugspsp|?>vp+=TQM}wGdXLXG{ zVi`Ci0$G}v=(F^hV}w+)Oe2t`iJ2g)`#yKX$5zN3ft&-L4rl3d-=WWF22RL{IarUJ z10V#?jlh->hk8-+(B={{f_KC0$_Y6UbF}H| z)iXk95=}<}9Szz&zBnPrq{TEU=*R&0y55rN8c7*TmhI~1gq#|$ON79_OO5CMyD7gV z9}@irgLxzpwBV#1S)NvH5*4HjnIZdKqfiE}-PZx=`o6zC@DCwmFGlT6G>P~~(uABG zK}Q3f7d(yIx@nqEUDtg*;O`-1HeJ_!ZJOp2fHih{)cJyq3PN^{5b9^?iHmLcxw*Od zt7)3gecv~S{b_{c(f57RG|lImo14Ed?FxBAs6Zqt*x!B;W5{pK*JF7#9(y&G-;L+K zAIl#wtZ4Xp+<&dElXaOZRbPeOuW5VVgIpFOP7$z(T3Yv~vHW)|AI5VJTZ64^6BEBSg#y zGM}I)%~}j17KiFDEnOcuUt#E@>0HCEcF3*~0j6Ce`xZm1O5Ih`IeuTN+ty1RWW4eh`~TOU@&BM)3MkQgMM@bdYm8B8c#1 z#@ViWE78D40!D<(#Tx`hXJ-KSDrqoae31hLi8 z$z>DjeP}^jBk1AK*j$2rhW(rzJ{2JYJMmiAitr^tE-^SXloO=ZTOgN*_a2ZHvyBd7 z1l@JghOv{s(P7lwc?A9CfSo}^z#H{B))n$biD&`>gkS9e;$0Z5~J8tXRDNuF002ovPDHLkV1mNB_TK;i literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..172fc3b5e3caf3357e706be2a1f0d91f357c8e5f GIT binary patch literal 2302 zcmV2ok^m97efLZMJ76bgmHN3TVPgynL1iZF^o zv0AMLkI|bD5@Z+S7;_RWD$X2Q#-Gi>; z=tN2`078B~PH0>efZ`B@1i||(&~g>qMGRTwTrQXXbnj39hPAQB*)bIg_=HbA_WGzO zR;yL=j9HSDjSEl*;KYv!A@o|O_=;IUA}l9+ObGitX|Dzg#M7mV*iktr2nZlVbl%^^ zH53Ym36TIhGR!|u7{3PC~!L=Y2z z32ZT8B;zY)i(nCqF!62X25hwu6@!!-aVKznAwf{$S4ay%(<6lhDJ|l}=KVE%xD;tO zjxokGV%Vil6ww-?fi&aiwtz1TI;KLw!36;9iSC?$w}w5ZTIo^H5hBZ^Apum+pFjWp*|TRqUSD7TX^iIhX;RaeQQ zE(9uq^MWzvYwRam(2Co38gn;jAmP?U& z&MGvUhjxmcRMYbSg3kR zZt4g}LPgLEq&hYm(J$si0u;4;IwvxY6?fp6l#|X8fH;pmq-q5ISi1H|(Ge;Lg>w@fkyi)P5d7;2~0$MDQ@!DE$`cg61AQt41xJiqTo9Dlsio7bTA}sD9BZvH#!%wZ zmJ%ND@1^DnZ%X(Ld?$$A6k0J~NE59ixD&!XX{j@~=b>7mwKZvxCyp*B)cAo?C*Y0% z?1kZeY?X^e-9W)XxdpU^5OahW`IAUpYa}@W?W5#&t4q8l2swcYLBS!VH7P;dBP@_? zQAk2?GdMjs_n0oBI`TV#(4X2ifxe2hDg*@upKxQ&K(mtAk|`HJPz)_1HaAZ&&GHf7 zsz6IO?f{EsSe^=LZJ-DtRGZRNi3)(P24xANDG)6Gj(#dNGOP_9D0K*+?F8HR`Nj#&1(CYoj<+oYNw{1t4Y0L^ri-RBp`1VD6hPVuR0IkNiMUb`EeV02O|F6c zauGd$;Lv5&C{!~b&}Udb7lOKhLPE$D=wt2>b>Q`^nt&r(EH@_=La)06a5Fwnfw+Sp z&{C)%=8X_pC077s0o1}imRwSiS1dcYq8ac~BtElCsZ+`Ul=zAmLOFfPAwvBY@Kn$$ zk{zOiq+$R>LAX{rQ>;#)$VHAb@IJ99w*HlMq6mNtA~I*7`@~Y7+@e^8prDZQ`Pk}@ zSYXq1DD{)3Sw!SFBRAo~AvKngUU3Lg#cu0$<^+@bU0;P_H1st~XDv}F6a(QX9$Rbi YKbh+rFQXz7g8%>k07*qoM6N<$g2q=E^8f$< literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_ab_back_holo_dark.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_ab_back_holo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..8ded62fb7b6a27a86f7b532c9a2b5a4ae999d34c GIT binary patch literal 741 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(epwmK8Xr18D^?ZvQoBE&~JOTTd6q5Rc^#N8xy%NgI}`eR{7o3SVw~oLF?DlhO#(rS&-V`^Q!s%)gPgzJD$(6 zlPX(2b^RHIj&o60rR$>g!|G>TRxtl*e|^4a{T&6ax|r;1#_KA};b_owfAXfrk8RFR$o&QDy{Vn>#x#sulW#~7Jq)- z)TH!~FS$Xsf0AE4joN$h`JQ|K8Rwjx@86b-rgDVb@NxHUL6S>yvXNP=t#&QB{TPb^Ah ka7@WhN>%X8O-xS>N=;0uEIgTN160J|>FVdQ&MBb@0GkggF#rGn literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_ab_back_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_ab_back_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..517e9f72d0c8d28a22360ad5d73476c25fd4db33 GIT binary patch literal 661 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(epwmK8Xr18D^?ZvQoBE&~JOTu&Fr5Rcj%_$5Ae=jmr`i z3DvOQxBn=~BCIDR#iS^(^w0Zu6&JUPm!vIx7~`u}yzledo5s8M7#uS86ZssvI8sdD z&xg3?2M7HpA7}46mr}+fqP5gidGgVwQ1_}WN$aob&9(OVStj}6Xj_!ShugM~J~IZM zU$@KD($sJ1b4JGMs?Xp43SH*aH+p$-+40a@k*+<>G~DD-|-{tS&vG^x*%GGq=j0Y+3zJN#Vil?OA~@ zukBM`R53;FYi;h*X6Nv`Uq9z3iuI~5j`7&H`BAcUqjcZh^7x-d8^2$_pe40Fq;EPa z%hqE7x*0h;3a++#0KFc4?e_Zv*^k$mEo1DpzWsL9`(v*67M^+IpR-MVa>nHwC6*2c zw&pTkoOQ_aoMO7bofkh1@}JI}ZKA~9;BBq7`S!))DS4@K0yY}FSDK>kZ?)HK*JGG& z7n!~MQ}4z!!HZux9M^8s)pB{g?A$cwGrvCg`RlIwI(LVEXW4OK`|IMz?e(5Emfz@% z$^^!kYKdz^NlIc#s#S7PDv)9@GB7mMH89sTFbpv?wlXxZGBO2ntqcr|?>AgV(U6;; zl9^VCTZ2=RMLtl2B*=!~{Irtt#G+IN$CUh}R0Yr6#Prml)Wnp^!jq{sKt&9mu6{1- HoD!MOjfK$EgnR$;T z=N`Kp(hSrM@CU%evd=bf=-4w^bQmnuhmUH-jd<6WZ; zHl4_>Rk2U@t}L_t|AiwlQ891B3C|YS1B^O3M@oxo5*z)LB91b?+QOQX_r0yH)YX2= zvK_aW4}ZVF|MIp0)1X?{@CS{e_APBtKk;H~nV$PVB{N8HV+L1tOj6 z``KDz%d4l`HAyHPxAByb%b6xG^S8m<-YfXS7v>b+zlZNGcwheZcvv-P0dQ7=MviH9v^t)=yc559VF`j43j z_pMt2oAX|`goy_Fm~UMa9d%t_^^2qU)cXl;U0e%IRZSM> z>7Ksk_VioOmKv*1mN|c~ELg&~mMikt+LpAdYoES)QG3#uo404uV`0ytJ&!XS^rKz< zU6j9{ob*(;{k73gyQmwdmG2d+82l2_J(5-Z=Epp_^THpe+eb5HIvzUo?fW(va5{7P zd0GD0trC|9zjsRjleub%YeY#(Vo9o1a#1RfVlXl=G}JY)&^0g*F*LI>FtRc>2C}UT z3_|{Y+l-q7HAsSN2+mI{DNig)WpGT%PfAtr%uP&B Z4N6T+sVqF1Y6Dcn;OXk;vd$@?2>?&0tquSH literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_cab_done_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_cab_done_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..bb19810bc2062509e4e4968099a359ad73818728 GIT binary patch literal 915 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;rX+877l!}s{b%+Ad7K3vk;OpT z1B~5HX4`=T%L*LRfwTh{zxw0jNgl<&3j(^ zeD(x}!be9sh1LD$__>xwFX-mty1-MRJ?GVgBPRYo&#phmts!D?ltV3&FI%+a$=z1Z zV;YHl1iMSDgJ+|>#46F---v^ z=n46F|IdfFb=)S0I4Coo@!g}n4Nex)S*)#RZPN@k9D49tzo1o|L;8h-cSg(aGrNAg7qQ^lmAJNnY2BwD zmg$yB$_Kc(9`bFT@$ln4rdg7D8~IZ-f3I60`0mq%qw5167@Xn!BqR{_Lfuy~aYE2x zQ4_Q6{SU<2c z;lT8&TH+c}l9E`GYL#4+3Zxi}3=9o*4J>pG%tH*#tPG5-jE#Y8D+7a&|KB#FXvob^ z$xN$6(O_z2Y7RsY4Yp<(!9Wd?ARB`7(@M${i&7aJQ}UBi6+Ckj(^G>|6H_V+Po~-c P6)||a`njxgN@xNAiwS~- literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_clear_disabled.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_clear_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..e35c5f05efdaecd358f87fbaae543f8e5d5d0331 GIT binary patch literal 2531 zcmZ`(XH=8f7X2UrgEU7FLQ_zh)KH|OfFK}4%YY;l3BgE$bfgPHm>57oiVlR{r3na1 z5s*k31wv6NLqHIXlu$zN<;7X=&-?MtTKn#O&)WO^xNF@LZ)0W3eOmZ5007+PX2x(P z8~g$U%sc^9vpoQSAh_$-ZE)`H01!%bN1<}R&3~u$N|MPoHg<5@c^XvcH=z=8RBlXS z3@PSUNvJe8kyXUW#9vzZn(}j&b1+rdgO(`5gilr zURLUj7BfA=2?AXY4>LF90D;`OK%iJNc<{fP<(CdNOIBm{nI1lCb59ed2NW9^Wr(r8 z8-61mUr+zyDcHH@-Fn|q#SnumGVnRPq;@GRR-7e$Zl z63G7SSIaZT#y2h-AmUaH<0K3MaJE8vvO-WWlpo3k6@{`w&kE6n1Yn|=&`#Nb`3^*H z6MpS{8uX7dU%;iDlnzP?g_AU0i>SL_JBc1~_r|n+xZ9(VxGWN(b>PDzm86uUoE@Jn z*d*HA;CC-T`CH0&Qm=fMZoGAduW&op37SPLMhst#clZ-dh=S}Sl*KKb;}$%+s9`>7 zc9>vHD9)y-ls~}X7Wh;#b@aMM+CI&Nb|UL#uVDB2kMPRYTO|e~##=9_hFeOBHkMNT zypE?{%PbVr9Tzz0ZJ)29Yss~vvVZ?GYCQF9e6wVnZ6im(LO}*Gf}Epvjk8mmsZP33 zUAk7ewtTZ}Q*X=VCi#f62zodvbYi#Zfc-#fcka~iDJw2V;Z}JXdcM!E6w+)~Sr#{+ zkU@GC@%_AHtrT6FAf;JcW!^>_NO4Ock*;VSpp_zWBcn{-mv)47Q>Bn4mAzAT^A3O6 zEmyczZB=ABp48gbl$Y*#RXRJl9elD{s4iUj(pC|fcoZT-{XJ8Ek1@Q9BYI#dOL<$7 zRvnXHHu?n>TqNt7f_fS;q&~(=E@V)6VjnefQBl)t;!a&y->o$7i4er{Wcx(W;CQ6l z!39x@_U4A!fy&wsc`L^}oe=50rJ9X2B~MqKaH%zV`(mIEb@FY*i{sq&BR<}Z^N;n% zPZTx?ANyi!Hl};qTUHAe(iY|%Tm>KSo?KpC9L^hkm~?Ui0=NNQ^?wdS)R{j++}#Xr z2>{_z01zDu0DC7)UI2g~7y!^w0HBir0D``$uH847URJb)sWEUud`f9&-Z=cskbwZe z$@dE^KxQ`dS2Nhp(1Xba|AM};ivj?)A#-CxJM7dl!pVyt!+(6dNV)Gs{Te)0XjWe6 zZQd##cOza!>Y39JRI0Ng)JZmIAUi`cv9!JSx_;AgLZ7EyYooR zTahf;!@{qv_L6J@KOW&-XNryEyJqR4@~arDq&at2kCY_HPqBd_3m^ z6W44o80 zd#3>_So4<%m=b18pV8hGV8l?a2$^=US5)Dl{e@}<9;@L&YK#;-?60l;d2G-=BmE1+ z`lsBUk&k8LCE%K#YRE)aC?NJcrp(30Rqm*+0lw3y(t${?e}7b==Vmy7JV8?1$8?i} zC970B(cFv{gl@Ji^K8p%fvkdHkTDGLWx1Xlh6IemS(AUeaHt9YN_-99X>k}R#GnSjD z6mp~4qV>Y+>quK>hC=;ek((`aN^32cE4xQx4;>uTcnNj1>Nm69!$CMBr*mYkhGIcn z-#L)CZ2thkxC9gh<_C1(S@X}JVgq~`s2B3lHjFH)MhINO?CjM7aM0;6-J+I}^>D?H zTSja|BR{|7h_)R4*qmzcOG2LI^3^MFi-vs~SlCEZt;kc%QjMsV8JuoNXQ!~8^Yqp%T{J~z9iRV@_1)_fL@#~gP%vH zxOCgH9WK05fMJ7bW|TeXQmU=jKd*xky@ z%E<}ebd?jW7w>2Hy$ae8d&)D^SeO1H^hfN{YSzyfH5slUJ;Ggx!ghqO!;S$_9`Jr5 z@lBz7Y~!YuK<-%Su?g!&r66yZQ;W}h0Qlp=x3SMXo(auQ>YvneIbRr#Ke|HZdp8Cd zq}ijL_TO6dxJ3rNevR9HE!J?aTpsL{=D(o155rNCq>)Og7*xSDZ*SXp0goxryOQK4HXpc!Ex?()L;Z?73vmql`ZFY7olc_Qvw6+AKsBI-+Kk=H#6^OJnb7=HrmdnVB zpTYRkxm<jpD>fgSzn<}E~!UN}tlGV3AoQU#eK}|lW9R2Jw z3$u#IF3F!wW>*T9mJ~<9Z!6{vRyo1Pj)|XV$JaRf!vz4Vl*S`nM3Mz;baDGr>~Z$U z2@R`3dzU8S8KRv}A@03+{KK|Bmkp(ObP?g^@K*E*hIV7FzSoZSN#U&swSokxVtZN6 zyB=Y6Vf#|26IK@dAy(gGYB2peVjegBbev1&L*SYGJfV%ipCoi4vc{H^ILvML{V9E- zJH=CK9cy$k&juE^e3{rLcqky98BEtD8s6#d^vMrN|BY;X1$Xwx6Z|IR=DH&ZYdVLp zHLB+d*7-BBAwjx!x6$J`Fl|ZZ9J0x&>rm>VO0~czTK?KoFQ@-**7mNvh>0>9PHu~r zx#Xqpn;`Dral4PvaSy;S2~dTps3^iT6jinDR5W#9sygawiZG^t{qVgt@;?D@-#fUw WVgEmns=9(>1^{ytE8}V-6#hTCp0D=+ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_clear_search_api_disabled_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_clear_search_api_disabled_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..7fd7aeb2a63980f5c7459b96ae175b875f27add3 GIT binary patch literal 1315 zcmeAS@N?(olHy`uVBq!ia0vp^+91rq0wlddc6tLTrX+877l!}s{b%+Ad7K3vk;OpT z1B~5HX4`=T%L*LRfizez1K-K5QyCaov^`xMLp+YZo#ve{ohs5cKmXZmZ>G$w-JO@O z_$Dncy|l#DX=;KaYmSzf&V&g+I5)gx(wb5qs1h)7!mfsR25uDCBNMaEYi!b%Lx%#0Z>6%}_Ke;bM=$-hufo^&&725YD$vGBuUKV?<1 zW5r*8XXtLO5$#WZeo|;mb85TEyq_Keb3$U;>HYFK{YX}hy1N)ld|`iZ8c+f zaW}0jS<%V*aZgCBwd%4 z`mTTDHix9d^392b?Js?F`)aOklAwYhQ$?F@yb$ytH>J_Jb{Z~vrG;$w0s zy7gpFZTnjBVEMK z?u*UK{&)=cU7rs=ddas!yNA5%MN;fAeO3GpiZ3y(^OR`LtKE&RYG` z%T6M0Q((r64h>88-;=&fKXORn&)Y9<7j0ADM4op#Evb9DEVE3OxuAOMwTp8T79Bpj z^46Bw7ia(6t$e=h^6Gq+^)tU-Y>!_fu&_#YcJ0QCjvJ3m`|4emd(8LrvxuLIduy^w zKRn;Ob&-9_RrP6hYo5j|+EK9n+eN__H(s3nbj~C7+}RUuX{m{weGosZ*S#`Yezasg(E; z?-{fhY+_DS&eu;5`_fikR9#fupz-tEU2!F+6F=1F&8oh6DP7e>i}j<0lm5=$VtqvCS7PaJ&waLQ0xVeA<2r9FV_>h2sIGsVSbJsf1ID=TJ5=|I z&X8~@c`+{`NhyHi(Rj}}j=t-itc?USbMMp?m=EB?(?e-29Zxv`X9>CKeyCDB6UQN6rr@v)_sLiS3~Qp ztEzq2)O|!<>xiRNElR1gi&m6P`)xn$hne5Zy#N2rd-GvpEU{+CMPx+)0Kjn+5^l}o zg&!d#$jfNkdNdFGu4pqj;P63GZxgQ*_CY#Oc|`sUQ?}=CKZgE3#v~qpdI6&Bx^w_Q zunGk?wncWWW;l7-UI#@tQM0)~HL81;)HPu;pVQ0pgJQPrfpMpp=aU0}M<~a{2nw%n zU`-fLR8Od%K$J#9U{=UTI40i8@}fD@+Oa6N|E1RI6sbQ)pL!RfOePt0E*?-w>vc`F zFLoR~H8O{D0Fhbf&d=`-+1DWWi~EgA3{w%CBurf@x&z#)AS%CTjBJ;NXfEz(-q*!r&D zRZs9Vt%N#~h`fZ2dF&WAUxzdNEE zLcQ7z)<&U)d{TxG*7ZfZU%dui_e8AOG#Zu1*(e!@&OEmtgjVAmsh>Px!}hna+U*4u z-(P@*kBOd~_&ckM8!+$m47a*D-IZ(wJ}aDF{e;O>YW!u636JA2%GNI#9Kc(nk+Ttf zZ5oR_VO!WXDMZ#m`6;XjkCv`_D6eahzuUOoqFaafSiYTac<;TmC>LuaHD30rCoEXh zD5R1Oih#JsO2+Mq%9NFu7{5RCprvtcFS~~}?Jc*n#%9=R+B~=%4@*03!EPJP0MrnJ8N%7FfRW&1jKLlO`E6 z2Nzeo&ri0;XG#nsf-QzGDH@1K!SO+oQz;nwgfHIg%HhTbyKTOO$NB{~co(lFCB3>E zA&~-M`}RVuy48f;Y-C?8l|c;|{QHGA&~=s7pAt2h>u zaS=yuntEie>)yAC_-npL!3zTFzOgLKZ}$=3sW+~_Ul7!!J>-L1jXDCh?L;zNtpzrIp_ZRL}JEMXYA5@jiafE19#aIkmj zpOVnI=5TB*VZwzSHn(G2*x&nZOKW`I9?Av!cNOvbi#$Fwg7v#&)Ar=Xmc9st_ZL_3 z{@58B!k$KOp%D%6encJsnot-_4XUH2sc#F@HGpawXltoKc?EQiVmJC91DQf_cccHm zAysqDoo4|5*kD6(qXoG55dp>oiYrkGMRp+(t%)uKx-Xk($P)oj2rRtP1Q-4<4m6z) literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_go.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_go.png new file mode 100644 index 0000000000000000000000000000000000000000..1e2dcfa02057f16f9f89e31fada93991c4eb9ab6 GIT binary patch literal 1983 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 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..a92fb1d4af622cfad770d7c494121719a7896e61 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=d7dtgAr-gYUQ-leFyLX@@b&p` z%gbN)&SLHDYV<0q^J4_6fq?|&@*V6j4#NRakTDF}Z~@#RP$drMna{J{ZM0wU(H|t@ M>FVdQ&MBb@0L8N*<^TWy literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..930ca8d95e8bee5a1240fba645d9dab919abd734 GIT binary patch literal 184 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=^`0({Ar-gYUf;;epuoZ6aJO@& z%&D0-IKvGL&8p&qV;O7KuliPO1yl(K>(rHwor_8Hg9|Y9Gj8!^hz0Vk4~QZ}ABcvv nF)(akj$uTI?LshtEWgbR4Rf6*RPme*0Ev6L`njxgN@xNAEX^ml literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..45a0f1da0d01b7c0ba53830285c67d629bd0774a GIT binary patch literal 699 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEU~2MoaSW-r^>)^McjrWjeSoS8SCOEBs|%|?VJ7D=T9Yz_dLJ8 zJ9zK=&-=vhubx}{vF6<8-!m`2Et8%6G=f2_fi-~)r;kY>>MAgRkm@i7CT&PKJ^T(I*&Av>d6O5U0r~;hkX|;LrY6t%e!5sze0;lgN zzhmA1v9d1mdTWRDgJXqP4j5dhQr@DSSRpJN-*(9Bjp4$N@%tt%vt{r<#9TCmVT&q5 zPY_dpf5x8W&TrHi1EzgwuzL61gP~v}`*h7_ev9YX^%66WzmeOz)Rwd1sPzfWyZX+; ziqW^(w(Z~haJj|{8OsISSA~|G@%CQ8Y_d#7=yl$KAFm&t%#H|W$kcQ2;yBguIO76W zkG?He)AQ@KipLqRU6Nb%FPk$;xS@jW=|$x{C80dl?QT)`*~FQi^@N=fie6YGbN2D| z=`W4NG-chmgqp9bsxquQQuyVroI59@gwb7QnV5NMi~&p85J-Uv+l!N+#T%5W;<7yr4}f9Ow$JGA?da_{7}kE@t}@ET5LG{B2CIDTQC8`Twj U_qmZcFi|piy85}Sb4q9e0Mf@O?f?J) literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..528e554abe239137182dd9069d1fa4ba02a109a1 GIT binary patch literal 935 zcmV;Y16cftP)=+L@6RIMT%_@p^A^X5UDRjLANf13Pq%);A`Pd+=!;23pXx; zAif`nPef)@LW&ftmV!!=U?`shr5Kn0)zPywg_Q~)Xf6@UsrA5Be7{a=6EByPs``206cpncnr4<@!q@mA~gUzaA3%HTX+%kDFHYT5Qf!vm`Me|1djAs_x*GR z&!z%kGhWI$<|3X<1;9qUl5@-=4yFR&S{y_@$C%@oE<1op+>aXzjC~!)$_ii$_F+%K z@y9V;#ya3q+!Mu4ce-D|$M^yJarJ;X=I|E&DieT9a7UE58@rw_;mfG%mg3n4+>X7G zDINV8W$>{wd4UPs8tHyn<_K%Vx4t-F{HB0#CbHyT8aIH=*w&T4zhI%?@Yvw4$UHw9 zfiH|AwZ;Wt3m(R<9MXfe~y?7+&yyx)=z7N}~%m5B!YmPaWaH#7@Q+5E; zIqP##(=Vn1;7AlEd2}e2K@tF-TcIq?su`V~Rw@AYX?JP!=ya5wR`qE`V>4fQR+^F$GWKC7sT4IxUFgD9>&BxJs0#D$E0dq8B&$(De03B_O{zBGgT!>|}k{a55 z!O~xj?u?9>EHL(EoJ!?lWDg$AX}pf&%~Sx?@v3~6qvvqAx*Saezy`dwo-+WR!8JMF zpTip|0k{c|kLwhu)oQ!f;y+34?@=W6(zkfKXdO_i)poDN4CtH&58$o=8{em4rdmY+ zbb?>20J>f0o#8w;#fEn(4AdV*y+C*HYaPJI-C#EObp@bT@IwJeLH&YX7XStYpFDt- zf=?R2Fu^AaVA$Z31du2AoO(cqH+@Lz(5e*i5O+3-*HCUO7(002ov JPDHLkV1h8vxv&5L literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_search.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_search.png new file mode 100644 index 0000000000000000000000000000000000000000..998f91be9c4dff50a3ac354a3810a2afe39fe32b GIT binary patch literal 3784 zcmZ`+X*ASfAN>!5F~npWB!(z!wjoQ_#+EQd_B|Q0CHp!v_OkC|DY9hA5?O|1ENw`# zX35srrbG=P#lJI9!jYNQ=^Gdx?pb z_F7n|ffgeztt&GvZH&HI(0?`PpAOPbmp}DSGwdb?o;s%)+L-%MT5hIy!gQ1Hr4pS4}d>_vP(oK5+q^$DPO5<1J&&;-VmX52_NsbDn`83n?1R=^s5n#g!M4 zWve4RJT}d-92>mxZMH=*_U&m$xc3Cs4ajXS8-Nr=X2QKCs#_ytuSc zPO;fwq;!pHxHOU)Cq>_Uox$ZedGmG4T=UHu=V!Y$ zg*GRRrVZ7V2VS*yw$6v2j5q3^{21%1iA*^TzBF^AK-%?C^#nNC(zcmzj(BRd-RT2BAP~$i zxHJf)iH*62y<|BhHmXp17LAtCcS_gH;;c>0lg%(vLLs&t z1S|*Vm1ydSKi)7@8wpx?vstL3c&C#$htNReFuy*|{ z9T?2ahRh#%u`{M-!uQ#)xj?Wa8;u5pZy^w1J+eK2*x^@47URiJ*fVhTCoOa zGx_MKSDS^MKJx|MmZRzHZLxkddDZ3#MOBNX_6;|Z`FQrH8Ig-U*AXw6HEk*#;&JAe zPj+(k_I@u^1`2`O-7H_myN0)JPS;mb3Tk-c?@&C%q<9XrD>0RX2+Ve$1dLR~ImwLp z-4!1Y{#P&3wL8`oiZ>5`M>Jsg zUtN`v{6Ht$VPwrFmOAK+Je^+Dwr|(BhxW}+$6su#!4t*mf!}vc9QoDNE$Tl9 ze!|ki`6EKM?Vq}&O~2jrQ}lM{lro7e7_L(N(pFnqXdb5kLX@OCuTL|mMn#lF!*2>I zTz;(lvoI}MRn8*jp%sx;07L_RAN@mDAZKtl9hUbBntBP3baod8X=W>MoT9 ze`|2`B^}55NGtrYa{iW3GQ(PGx61a^^F|gXmLs<`cG!J2ts4m!=0R$OIRS~o+Qc0P zG2FBqK*I<%+Y9`A`|wp)CTMB=@Ai*xYwncB#a_oH(+~BcLUQyDv)zLB!Wl*EV`F16 z4m4pFrA%^~(-Tp9w+ukkb9wO&yaIK-xQC0pzN21xmwCGd&UGvrpFV##w`e2Lf-$YV ziUk1o?M5kLy}CBZQ{Fdnl>xG3cQcY1cLB?EE+iP^#m(VR>bm!)JgyCbs6T;{9popB zA&C~zOA*ufG#QU3D>`im>%7EQxO5CcpYuupRx>{P<$MjWJSwD-z4iVql#-Mz$W z&(s3Law;i;!GayA!dCB3G~igK9uO9-J2h~3`8XTKCeNv{EH%pZ;En~m54R2smRV%B zDjHI&tqJ6a%K<%Q1@Kn=DG&VPm^`&9TD|fbYwsU?BOPJ%PYes_L8zrz_80FS769NU z>@78Ph|v$NNC>ypU1y};Qii2G-E~d;;_-u(Hm++%aMX6%$5cz0Ao_l>Hv(Py0u$Gs z>d8~~(cBE-SNF$50+W%iAO#Z?RW4I_Dx_V*@yjIW8+~>zB{ZvFVu3O@qs5(XNqFQ9 zX1ru`jTuaO{ik2#Y>%OPboHHwLZ?2BS)UX)EOuwwYZcQ9Bxwl4S@4kCzm zm4BS-$Kq(RHP>R8_FlRCt`c6DaueCv_jx*RlZHVx_~&cEkh;lF7X<)OtMg}%J<}@9 z2x6+`{s)7+<*`AD_aaUoyh)%y`A?S+EqpuwI_GwXDOQt0x?HbIUz>5L6MOv9Y*SAL+Q z`(=~%Y)^UB{}1=v8bi*<6FkL5deS4 za=8UQU#jbDMw6|kqwW>Pj0&%%bDIo1H5$v>arB(x$aR^LYYB5%;jd0C4}*L^a)`zO zkgV}z8)8HU3nx(AY&#ZM2Vl9G-0_#^D>2X# zLudCFYJcuwn|GJaV0ya^MBA;d?lU_yoMbpmkSiCC@1GEqe8qDqCyAp;dRL>Vp)3I; zXHIIXPc|{O&nKeYQHf7li6ge(zmLl!7Gb6wblI{=XxO^LS2F3QfS)Hiu}R+ip=aaL zh4w$-I7#C50q9Wbk*j^0Z+GNV7c4f$57MKo1PNKTyDkdBkeOLth5o_Kcc~@|MaYPz zD%j&iU+5hTEwZX}i}&dUia-YKu_3=FwmUWS7!H zc6Smjp)B+v!cI!2VACR={tUgaC~HOc!dRYyg3AWGA7;ZoyV z0TW!1230bWk(2!Pp|rZoZ8(5%LeIS!A-+v5lIqiS^N@UotV;gCDHzL2|31fXLb##O z_(4K8NC*Wh0bUrb4kKM3(imxCF<~c@Q%8=`f8L0Y(Q%rPdA=aoXOh%Qi!cy=6+`3G zwA^ENpIZyDka;i@Uu;_yi@~|kDJ7P3&34dny`{ND+c?5?HS{YC)O%ZpNks${cN=p| zi0sO|k$Wc`e0jtEHGfb*%?&z7eT!QRjWY6F^%YVD*m1N_xRsu+Vy=P^F44oA$RMwG zvGPJX`JJ>4Lt_C9hRqTi|B`|ko7nkxVL}?up|$Y{o-=9iYmlI ze+MjW)68V$%nGG(tf=gZC_ugbnQ^aaHm#m7D{mzPEJ(27u-+Q#)$#iZ>i?dZoIsm$ z-X+eeQeewAjyLM}j$Px( zQa)yQRqFw-Ts{EY@5^k={|Fyk*6bw93}OizEe<&Rl;dt@28Zacr#T!^r=wHKKJj@p zFkmaC^u_ov-(kf(%5*H)d(mD;L|5P3tLK95AGN3hT>aV;VkjPiDZ90SoR9G=#Zhjf z)xG$sfXP4Bi0WeZ;+k6GBQ@kbubs5M273-gUcc3~s=749q`0uhn)r=%Cs^X*6WP5S zBV=3MW2DBBK{^RbcgAigICB?_B{p+_bb1x?TA%OIjf{_s|I&yg+h016{tYq}+&yYN z{Vf6_0XkLzx19srR9yYtP6?2ck(HH_QIwKXHkZAkA|t1Ql$Vk@6*6CaZ%zD9!Q1z? Z$DPpsU&xgE;c;3340Mc9_1aGO{{Rgi%2xmY literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_search_api_holo_light.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__ic_search_api_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..a4cdf1c7927896d70e6b9f6af2eaa64b1bb41707 GIT binary patch literal 3037 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 S!l#~*4goMWSah`&G3sAAl9aOm literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_activated_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_activated_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..eda10e6123e1e1383c4617228ec0c96680d60dc7 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xamSQK*5Dp-y;YjHK@;M7UB8wRq zxI00Z(fs7;wLn1!PZ!4!jfu$#Gb-B{xqtMx1s*(O%+nLV7IxRdaaX6Iu&3070|zpW ye6d-ZyJWwc+pgOl@x443T>9p%`1p8cx&%YrImy|zOvgZGF?hQAxvX30u5yFboFyt=akR{ E00Z(eO#lD@ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_longpressed_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_longpressed_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..eda10e6123e1e1383c4617228ec0c96680d60dc7 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xamSQK*5Dp-y;YjHK@;M7UB8wRq zxI00Z(fs7;wLn1!PZ!4!jfu$#Gb-B{xqtMx1s*(O%+nLV7IxRdaaX6Iu&3070|zpW ye6d-ZyJWwc+pgOl@x443T>9p%`1p8cx&%YrImy|zOvgZGF?hQAxvX literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_pressed_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_pressed_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e4b33935a3aa4f1af3fa9e9e199b5c47d43f4b74 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xamSQK*5Dp-y;YjHK@;M7UB8wRq zxI00Z(fs7;wLn2vPZ!4!jfu$y_kK-b literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_selector_disabled_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__list_selector_disabled_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..88726b69160589c8545759440e8d4e69dc984c67 GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^azGr$!3HF6SgS1tQk(@Ik;M!Q+?^oIXnykaTA*No zr;B4qM&sKXhJ1$tcw7#es=J@sd2yMiyW@jyg@u(=2qh%>1r1WJE1Ls*cJ{|veUO|(2?8OR-p?Vt(<)KXNk*dJ1<_`!jRpab6RMK;Rk47fDU#NEX#7yk4(~&Fr}L7DZp)K} zK)DDZgb+dqA%qY@2q7)3S*px^wsY!a9l?~jW2$HoDfOAoDc4?$q=mJH$Q@HesW|pH zEqI5t5pt#=^`ykNb$bDA+g_!6r>E#0Ebxb)V~E)@66{HSu%o+0#^7QK=<56_<*0g z4?VWXMFRkJB8s~XX6q}?LEeWW=Ef--P!X+fp` zQ#hbt=1@CWv@?Vrj0n$wG-wfB>s2&!$QdDJ0ulZgw-cuRiR{Y>^Hj3K6cvDZyr8vA z8lxp5*y$r9!v6G_XAF7`2PhmT)XW;J_(x39;8bKfgMu`e! zU+jWXwIOOF0-q>8C*JQsY~7_bBCuA z|Ap1-2&vJi9g(t&*dI@qVtrbEm_q)8uxlUymW^N&DQrSTF2REQdw9B(B*Fk-L?96w zfdFVX0=tCgq*<4>5rKwy4p!?>V+1b~mqyqhPm^M8N}pNlWK7Aa(;L|rtB1{dT%;u; z=)dm(?jeLfE6zhUB!2hW01y9MdY)1v=ujhBx3b+Xm&>Pd9KV)clx)K|j$bdA%O^}( zPFj=H`w_B~E-2}`eIdjBd_I2}hT(GvVW{|jkQIawhG7^!pU>wnc#H_%SRreOrJP6k z#f!~#`~_1^!^gPqw^)9R`+vop3DslHn(o!PiI0dTt@|45Za=)m1`%IwEW{fV$LVaF zE9RVsAMaWMjZlg;f(R_4iy{7r`=s=`3SdP<&^M)TPHqgUw5?z25;3$902*NlyMU*S zpa+j$RH$BIEX`7~H`b|A%pl=Pj|o!QHv-L&MvImjnCmfv9y@5Gq|A_|G$L4MNvqdg zg%(@J38}FG4N!(%uhEggMhM*%9HY#I^l zO-Wr$p$z~$ref=30GgqO)XJdORd}!BEq>NeB8p9{v^kJo2|NxCQwf^HCpGf6X;Wp4 zg!hgmb$FtdtQ>ASMriqL^@|$FBEhNWjw@zMktp~+Gzo9nO1w>OhBUKE#}ER(1L)vD UI+1b(O8@`>07*qoM6N<$f~tseq5uE@ literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..93066c8403ddaac9b19571152ef499620bcc0e02 GIT binary patch literal 1551 zcmV+q2JrcbP)ZMyJc+a5x+ehm5NR9U3;9%`Hyz-(tJnPJWK72_ZxFO$7HJ!wl=MA(TM` z5z;&LLlB#EA&f^$3`&>pe6X)LdJ&`vfROKm-xd+jMbSqLMZ|438|}{L$EEgM9M^%w zHa{i`W4qmEM~t#0eOdu-0W1NOh@<%YUknyuBI#0I?3#!O*zRI&T@|+kOaOda%IhNv zM;99T5trXGZJ+ZJPec%b)$c$hhFbzf1btKUoQ@WxJHBtqt%Djjh@==IkkXLZmr_R= zETUs(|D2YHL30h7B}jQ1@s(0WN*y++$>%9Px0_7;Q^61da}ymGVa5oGC6I`(Se|An zXj@SBzbdSFK)Um(Fw#d8Mr2~>phE(63xW_TA*G~C`G7107k~`S4FDISDe;mJcscGO zI_^QW2+SjBmZ1U=9v>gytZ(L+77q^(-%!w_2qCD0PZix`L1IaO$h(b>d0@F@G3Eaa zi55W^GL}q#AgNiNjxa=>FZdR(r+ zxE>NCSff^sd0^fBMHn)m#E-cU=7+{dF-K!9f{S1|kOWYSoDj6e26s~&lfViRc^MJj z^>Y9iF9eSfmVwbcxJ7UPa3MH8F;)otZ%)TN7|p{_AvpQV#UO5SLMWM?>!O$+C0vaD z8(N!X1GsBg3ar^sKmkXku0dO*!9}nfXnYiL)Hg=pYKs73(^zvc9aG}t;{#B5>C;Y2 z2$?l`wfXukgc)%>9s%7AsDyH^rRNDOAHyeHMgYzG`@1jfJOi4h!RzZQK)65|cOA0& z28%R3H(uBEzOL&YU%_z=>~=fscDp^gsmfTk*1@j+TejVzGC zpG{n`bp4r^(iKT*Io^&x%OHc_WZd_EkhCG`k)*sFZ|A&V23>!#)HToxrIRJ-1q1Q~ z3qHxB_z~+bgihSWK3otqlC9O%9BoMC(eAot5j0oOB3|pwbjUE4*ONZd@_Kxq z*B8(0XhE_FfV`ZZwcn~gXn8&5;sQ&h03_lPHzc@QD2L`A0DB!p$qE$r97Hn6cmgfM z$;^GEI@&qEx+o;VEJ0ZAK#dKOL6F|xU|IwgE6|`&x_D{{k^myy5)6fQcS{yR>LIlD zb0eL(UISu`k;Dp-=L_3_9uII4xG36?ZZ5uUxd1Up2yq&z=dNHjN&oIh<{D_CLJUbUG4w?002ovPDHLkV1n`$ Bwt@fv literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_bg_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_bg_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..345f5d3067c1b5a2b13f7234238468e8083e75e8 GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^Ahr?*8<0#p>+uXou@pObhHwBu4M$1`kk47*5n0T@ zz}*SLjOHg#uLTMQc)B=-SoFS~;>gutz{8S$H2ll||1$b2>+ab^8r zChoU9-sVBr1cr+EHAcpdxgPN?*fw!WN@w!F_di=AUe22-xp-2_jNr43yl#?i1$i|o QK(iS+uXou@pObhHwBu4M$1`kk47*5n0T@ zz}*SLjOHg#uLTPFdAc};SoFS~;>gutz{8S$^!?BO&wHlFT~V_1=)TZ8!I{mdT_A)Z zztl5%UbEjFE&+!7%~#Kq{9)d)y{;#I@4EEH*bSem)2!T7Pp)1*OL*gdvC7^*b6)~Y OX7F_Nb6Mw<&;$Uil{z^9 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_primary_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_primary_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..c6c3f1ec248835c16ee8a8f9d253769ea4196468 GIT binary patch literal 1309 zcmV+&1>*XNP)>2T29Hys?P&Vm zZA9*OOSNlf`Pu!y*8AUEO|D+e=9Pi3BR)agfw#}SukU>S5_JQH{fFX7qt#y26-7>F z^lg#%AL~){ay($Vl%dNK|ns=8F95J5u4IuT)_iO}FO5AO!x2YA-ev{((MiCMb95Z27y1N{d~<$0ZOiAzT-4$^Y~d8=D&GctVLiOE-HZCX=>916 zaB}eD93BUF6!cN|FY@&i`W7!}IIL?H*U-;b(9ZeC>T4fo-D~%;%Al$SM;o1{CK^c@ zLsL?U%;F5uW`mKV6p@jG8Wm~81rvcAg~E0r38^#=q@={j6{7*N{-mRal zZyi757l1u@+(UUVUpKQfbx4*^AEZ`NBGTk&djR!;W=;+8vR!2ZvkZUiF_Uw;@^@UHY_tFNo|bZ|HqK}~Z_0kB z>1@!nFOf~^{KOi&lvG5Os4i`3m5LaZ>S{(}C2cS_3u25qx+GSC0x^F*mC<6C%zjX} z`(@Gi@=yT|C0D;bu>bAn+W30Hh5ZfH4VVpRc=$wP71`a_ciV~TTQkNXRQHQat7toU zZx*3Z?Q~QYQO|ZUR_Tl#qXtzIiPWWo(#}&aV(i6KuEST$lYVRUVscgaEz?@VCh+@z zYdAdahv=OS&fP(?9$16?`l0%F3gfnP`B71?hw4@2e4pjZouU=>X|R*`N-YD-DJj}uU$#5 zV>X}RzD~bXHhFf?KK=4JTCWrMiS*`U`G2n9l*Y@cp7B$uQwuKJNIF$*XNP)>2T29Hys?P&Vm zZA9*OOSNlf`Pu!y*8AUEO|D+e=9Pi3BR)agfw#}SukU>S5_JQH{fFX7qt#y26-7>F z^lg#%AL~){ay($Vl%dNK|ns=8F95J5u4IuT)_iO}FO5AO!x2YA-ev{((MiCMb95Z27y1N{d~<$0ZOiAzT-4$^Y~d8=D&GctVLiOE-HZCX=>916 zaB}eD93BUF6!cN|FY@&i`W7!}IIL?H*U-;b(9ZeC>T4fo-D~%;%Al$SM;o1{CK^c@ zLsL?U%;F5uW`mKV6p@jG8Wm~81rvcAg~E0r38^#=q@={j6{7*N{-mRal zZyi757l1u@+(UUVUpKQfbx4*^AEZ`NBGTk&djR!;W=;+8vR!2ZvkZUiF_Uw;@^@UHY_tFNo|bZ|HqK}~Z_0kB z>1@!nFOf~^{KOi&lvG5Os4i`3m5LaZ>S{(}C2cS_3u25qx+GSC0x^F*mC<6C%zjX} z`(@Gi@=yT|C0D;bu>bAn+W30Hh5ZfH4VVpRc=$wP71`a_ciV~TTQkNXRQHQat7toU zZx*3Z?Q~QYQO|ZUR_Tl#qXtzIiPWWo(#}&aV(i6KuEST$lYVRUVscgaEz?@VCh+@z zYdAdahv=OS&fP(?9$16?`l0%F3gfnP`B71?hw4@2e4pjZouU=>X|R*`N-YD-DJj}uU$#5 zV>X}RzD~bXHhFf?KK=4JTCWrMiS*`U`G2n9l*Y@cp7B$uQwuKJNIF$+uXou@pObhHwBu4M$1`kk47*5n0T@ zz}*SLjOHg#uLTN5dAc};So9|U`2XLYnVI=;y-5$#f-D2o4GsT&Tr`prfMCHsr=)`p zy9zZlQWAk&gL|Kjh|gcN+0MxMkn!S`=@A+#%ic(Om>d23|9^ht#EF9It^fc3f1ZP3 Y!dJ=4-o~HPfwnMsy85}Sb4q9e06h#o+yDRo literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_secondary_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__progress_secondary_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..205b66e2cdef686c5ed6369b14e64b38d0182984 GIT binary patch literal 184 zcmeAS@N?(olHy`uVBq!ia0vp^Ahr?*8<0#p>+uXou@pObhHwBu4M$1`kk47*5n0T@ zz}*SLjOHg#uLTN5dAc};So9|U`2XLYnVI=;y-5$#f-D2o4GsT&Tr`prfMCHsr=)`p zy9zZlQWAk&gL|Kjh|gcN+0MxMkn!S`=@A+#%ic(Om>d23|9^ht#EF9It^fc3f1ZP3 Y!dJ=4-o~HPfwnMsy85}Sb4q9e06h#o+yDRo literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_48_inner_holo.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_48_inner_holo.png new file mode 100644 index 0000000000000000000000000000000000000000..19517c4b0aee1010c7041a76089fdfdbfa495e80 GIT binary patch literal 2769 zcmZ{mS5y;-5{5|(kkFChhK>RPiYD~XySTIjLIgq!5ZD-yra+_^kSaBR(jkI$M5=;8 zMWiYIH zJ{L4+9lA?MGnNjQqJIVMy|@+Y*x)5n@6@M^X%1QI>%HzU+s^F$A{uGSUK0 z#wO)d1v)g|N-fzez@Pj&KN3PQb&b(W}2sO#Qj`+a3CPNKCA#BE^jjI)tjC2m8529 z02D1x&?I`7IDU{j-Q&y{>)zeY&B`Ma8WJNrGwaNm`0uWt(pYLM@p)H2v)A~R+!)8F zgGA?$X`A<0`mH|V>|FVYItF+KSVc7^pC3V3%7=U@p1B3em})M$K(uwD6N9slB!(`T zi~R)>BQQ>9(EuopaR0r1fiuNtt$$G?AxUQ@M7fdP&b*T=zGv(+u4G zTQ zd|2UbSWW9ez=$eHfGIUaW6HipjZXJlnM;#Ny2G5k&zxqBW-hk8l}RPTCj&~v-_q8B;Zw4m;LP(&&JidwjDQ~ac_8#Y3JSaIVaz} zyux;b;PbeS(XUa_g!cmp3G0eiR1nI#(*cg`;6LDxk&B&UZ8rz&hgBr(y7O6rTkmQT zrhy=2eL5GJ7#qr?o||O28Lv&K7&3aywR-4iQ40MD_ir1|mARNdS-bGJerJz@cDgI~ zKZMq&dh8$ns!+~`c$m66V_VkBL{T))8QD)3VcaS&MzgHdAm9-34$~obv=v4^hN>o|d<8G$j##Q2b(LY)D`ks?MI?Bj|mqM(bkFmmohvBKvt$Q9Eg| zyXZKq$-o~^vIFdVLC`fNajQUh_^L?LN#cyA7T#%e%ecLIINl zaa-|hGb!|t5%rT7|G~~BHKnC(Cj*+1dj}!dLuH7c)m~U}TPtOUpq{v@8E4cSruw}v zP?r25lr7VN4=8*&WtXaomaReN2bA5Qe#=DrTI*iN zxJ0Y_4o7X@C1>APsW`y9ZDRrN?V@GJsw1M)OnX*zAx4o)Ld;Fc$sfnk;RLMHYsyQ7 z+8$_YLBAkmVb>l z^NPw5VgYZOYH|n`ns3NjmDgu2Yu32L2z~FCt<&E4IQ=~=CsQ8d)yQ4oG8NU>uy$+X zNf>bxv!t-TqNU1wX?;O>hN{qoXNl>c=dIC%k}p#8@HvfsRsDS9?sZrlpzpmlEWoa+ zE#xErtO9lePlYW#FAcWM?nI`J4|LI*l2_W>A4QqFId1Eb0cnhc;Y?q-cF6vXA%=Kp zTl&38dA-veWW#-bZt?S-9?&OJE$3JLuL|IS<5T4uf+Q}HNyZFaD2%jPwTM~u zidPW@em-aeW8>{R8XtHB|M< zqzyLS?bn}ASUr2W8?I|FWHX12r754 zKIHBi{Y;&qOIy%S+SoM1eYJ(GwLi*;ERNAj5~-B{`I|d*RT___Ad$P9`7Rm4^0m)} zsgpnGlpgth2w${(wGB%maw|SFY#m=RY*puF$vHJ}IEp_X{mj2^!Zxf%p)#_(m|pMt zE5ufXxyGSypt&mO@{9safwES>rn{ori@%a87<09J2=^iZ2kF4S7tJwTNpFM8jZFXLogNu#ZQIU4NEa~}Pb#!` zYPNgFL_d-(lVB&Hlip61zZTY2@VbiTT;B64r3sR%dn#(|!&|U6v&W%3utzAjiF}0u z2Q;oP0SIE&nDAb$a%|^P3c4L7TmALn#+C4MHD37aFX(F`e=Cjz|Z8 zTiV2qTSXyXz!ly5y;Tj@uBYwjmv&ibj6hkc)XgO>-{#?vk6Cti{l`V8i4PBb&KB=8 zx)P_xpuB=V*IIs%@7Rw??9@{*0Ut3_uPM?V900gEglK(YhnQSDCX73%vt*wGFki_& zP-w5AXw+dW0oHu>X7>3c8>0Og9ztC5>B!W!T}&Kg;TDQ~m3{I2Nm%uq{<)?%O?UqL zPW_qk3y@&xteNb$e(Lz!lfQ26blnGc9k1gZf^lU0VgF zr2~Tjw7VStClC53*w9%B3P=?aA_NH%FrjGZC`F`)4nioBUC=~8AW8|nWPuBU z$_Ax~QpE+Ngl3~F#l&Etsjw_Xv$*Hnhx>3JzWJRg->crS6J%m+QIvUZxhV?Jo-M#nxzF{J^|38LuZ7p2A{3`Uq`=6kIe>?XjoG zr?GU9y(f-uD6ci)?1uQVR4SRTa}|zrSmC&X%{3Uu#s!v3xTlSKYl2xXRH=XldiG8v z(NTpiD;+Y~m>M*QdTK>xZWq^1Gi8i~5S7o}q&SbO8eBpO0}glmjSVvH7iqi26bB%| ze)qmu=vH{`#f$>>(djQ0^Nd<2H1NqlRYSvb%bfxVSE-6hyvT5}iWKJBsJYUTMmHlb zv{AxVJ_-jqG)Isz@a^K$cM^+{e$!&jnX5OO8E8XRNKBd8M%eMRN2h}U8b(CNyXF_g zuNUp7s?z=QD$}|Yd9ZAQ6_1dXY%HHkm_JujD3E@{yoa-`U00;ZS$y^Kch)kpoM#-L z_hl0hcTHdzz3P<)L4tEt9m4YU94$VspFs>kyx$G43>YTSqKXzilVwxd7qomBM?e)0 zk70Hc`|MK3$79>mw09q37_K`7rCCb2Je8#;R&l3wIoUvgp*l01y`!k-Fb_5 zLjfJM*_>#E9is$M8{y8UF zc`)}6IgHUUW3OdBIJ8Hp{C;Gz79e0KH~zPbyGtCwB=d&F=mttg3`f7;P(54xp{|RR zuCSG=W?@N(vW>lt2EpQ^z#T{`#xM4!mdgzNHx)<1u}$v?^g+=6*9ecRo#a#lbymZ)6-p6z^Oni3 zsLEXV)_}Iwfa=*b4{k&Dd=wxu4wfdbo>!(imlp)*j4pv5ge6;)9owM4=9St^swSv{ zskok>E#MxCe6UUVusSMJNGR_6U4pG5H1hlHX%(t~>nKmo-|d0-{MbUO&bU~mKcE&# zK_zv4|CD1!H8jAfY`vSSl6kj5Wt9loIBf}POwl~4S?>?$T&{Mawq7O5qkqy#o-A4N zE|eq~B+4&zVcuWC$vrg@L14-|z}_N{7ai6X+LIyj5pcb|jwUl|0>Ek~Th%i#NI{1_ zBm3pUiwMhzLuXI=foW(FgEeV4z(3A`*yzwk~f+h&vY#xmxsf?5OY1hsd ztM%beiwI=D(k-wWDn9)VJJk!~4z@|bN-=_~*}T5DfK5!C3E@eSEsWaR*+?aH|7J32 zC+By&%_SPM+AS<3m|xNxz3pqO+_l<53yw$fu1oeLjY&kkfdiF=Q*Wdc`etyM*rdK( zp22kBzFv%4ur^fuXEGM-pX|Fkd%Nq2l6dRQ2XKwJF@_oc*%do|>Y6Qv~!9EN3 zF&dggK*AU2RyOj#FqbZdzB>B~aA?KNhqMjCP zxg%^}e6-VnyS`t)yIHRQ48~-EkCwOT+tHm-FNve|j%NMGANQwdwt$uv_8B$5dQ4qt zta;CYDP&5a>BeK^j6`R(AiCG7VaMyHMlZyJ5(>(;W*&VnHGV2AuFnNIz}wiAT7{P6 zzLG`Ao;5|df63pAJnK+9#KTd^>$h)+arJbu4vNUF`f^QCm+L^AP{SFHl{TDz|}ZV(SF{inp3522LyJ zSw}w{j~U+S-eU%!n4i!>i<1qPc*uvvdn0Equ&#u7KRLHmgc+YBp73B#_8nO(jI!6a zd|^=Eg{Z*a-EZraT;7p!4p4Bd9(wNu7coSR1qusz_AQ_YwQYlP_s|#mVMCws=x<_3 zw)$>kM#p7l7$^lrSc}QL@p{n?})PR^#Ne#?) zCgB#K1aGkR_pfe{pyO!Rvn|^H>G<#YXY-5pW!C!5cE@?0?1Se-EtcRG8{ivDI_Xa) z9RNV-BayoL#=1yj7vzbP28Jim7+rm%lluA~Oy{}(F+^Mn2nnS8e?t@r{NcbL_hWF!{4*;x%LlxuUCHn literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_default_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d8929fcd1864e92c78f24d34bb07ac0304bf5ebe GIT binary patch literal 395 zcmV;60d)R}P)%)khMb;v@5Yo)-?A$vWI3J{&4Tqm)VM&;#i3-!rXQ;}}A|kSK_xLoQ9!D=| zrQuRX_jo!D&!*woG(4MzXVdU(8lG)+!_Dl;%pOYTRyEwrUVwMtwRCnh!_9059DxJy zTsprAUsT~zdJlX8e>K+(FMd_}2<&RF8#?@^bn(8vHtbfpl-_eLJ!>=!D!!z&OE12( zv`a1CqqIva-mA1rDc-ZR3oqWgvUXO(tc zif5K~i;HKMc8iLSDD9eyk1Fk&iksP%L8V=5@ekmQ^NVfO%k2z5z^Qbob@&(X-FR)u p3HS~A?&0(Ut%!)oJooy?_kZokYAURbJh}h?002ovPDHLkV1n7-uz&yn literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_default_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_default_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..9174c4e4bc984a89e1ed643bc66b1569466ef52b GIT binary patch literal 394 zcmV;50d@X~P)pS_@$ zhD#gW|+S$zvH?tjZ06u}I z+WCj@MGelS_rM46*K*DD;uob4z^?VWsl%^ISMTdf({7b>={={?i$=qw;%iE~^x|tv zyVT+%O1re;qe{D!;v-AD@ZzIOyU^khrCnI@sM0Q^cw}ieym)kJH?(+0X*aBRR%th+ zcxGw0x_EYJx2pJz(yqJstkSNlxS72&skG}Y{tg(Y7u%+n+Xa4rW9?Ay@Gs!I^V*st o@Ei2q)9D9V5fPDPZuO7v|4Ms3SH1lZVgLXD07*qoM6N<$f(F>P&Hw-a literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..3015d307088f12d52a9e99ff4575fd2153127e5b GIT binary patch literal 381 zcmV-@0fPRCP)hG*08Y#N?T!?S64w!;lKvy+*1?>p3RGdlx#190x$dzj&7b^-9QUftoB@I?dG z(l;!l|3;oEFaA*ajtwD8hd-6>9*;+5M`bO2!%}+FXrQS0p3;u)|QJUO}XO$+G;+dssck%4fw5xbU zX__uxRhp)XSC*#P;_m>iSbo@k`^^CW{9xcU{p|2h0AG{O_A~&$L7!btFK9(XM7DX= bKfeD1Etg?&Fp}qT00000NkvXXu0mjfW#pxI literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..126637d1194f1d6609787774fb140818eaa4ba1f GIT binary patch literal 381 zcmV-@0fPRCP)hG*08Y#N?T!?S64w!;lKvy+*1?>p3RGdlx#190x$dzj&7b^-9QUftoB@I?dG z(l;!l|3;oEFaA*ajtwD8hd-6>9*;+5M`bO2!%}+FXrQS0p3;u)|QJUO}XO$+G;+dssck%4fw5xbU zX__uxRhp)XSC*#P;_m>iSbo@k`^^CW{9xcU{p|2h0AG{O_A~&$L7!btFK9(XM7DX= bKfeD1iaRu(IeFS@00000NkvXXu0mjfR7Ip< literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_focused_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_focused_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..d45c7a864d9b36fc5d06ef7650bd22c228e3533e GIT binary patch literal 680 zcmV;Z0$2TsP)JMg@Fn128fNR{httc z2n-9ae~A~-WYQOAyjJ3`v+tFS>H?h>cjZI44!YCDJ4vU-UH-NFC!H?dNqTY9^x~%J z#ZA+To2C~xO)qX5=ft;__PrJUYC9#q>!rbyQFMFHPb=3hoe|&n)9~p|baWUbMthlMtLL6k^E5&wx9H zfkWKo4DxGy27JSv%4KLW#~I|sPnXY+fCHfNj(}ks%-+uyBgtHbMG(R)| O00009q_DOpcx|jv*P1Z)f>u3p>g<+)ulGcHZsoOUd0`v$ideb3Xs*rv6J! zg}R0?Ejbavstni13%M+(h~#=Y?=G{+sY|c-R?LyC;M~J_EGz53I-4BR z+cU4@A4T%4{LQ{7{nooe_R?;9Ufq56+wp;!Z_W|LdHU^V zuiix!E)rt*mg%eid+||lw)K3kxzR2XQeoHKTo0e>Tz_Z7KF;I+KDl^G6{a%9AKj}v z@Aq1v55LRoZXbD)<16^lF!*Li$^7}+)mu{zFEMCaSs}k;w&aatvA+!FKCV6>P_Fen z(L?roLe!sxPkWei7+T9&rtD<0W7^%ZdcE}hdZyQpKhHVIBAEwFVGN$GelF{r5}E)^ Cjyh@p literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..2cb34d7f60401a563454c03e266cc5181d9de996 GIT binary patch literal 609 zcmV-n0-pVeP)%5ec8;(Nh#y0Zthco9&fD+Scz(J_kqCSd>@N)Jrb#iJx@ z@geV)|0U|;Q8J4AW)%0$DDIn4+&81RZ$@$73{E^#CTa6Odr;zqGLyGk)zfLB)26Y5 z5#LU9dOW?JALQjc$4r{WH?GVFg))<)qMW_Ts@W~*Hgkd(m(u%LwVNxGwVfAK{BG$~ zHD4Zg33jP$CptYU%GrKa?RJ%hK*cvHEqE`!X=%Z0aT}!tZ^dnu7Q7Uk{&1!u)wl@^>7cUfAnUfgwQ!D?|Ir3GuneU%oh6!%$L*todw(!xf?LzEVJ7Y|ih z=v92GOd6`R(5v{nqI~u|T|T)5eQi`_Q>fI*QllCl)AthpQf>YCTIE0c%xyxW%x|6C zG>z*e{-?!>T@(EFL|;a6&!||%qb(l4cp2298zt1@mjOk(atXEgIq-{NzY%9xIi5qk vb6%{!-vcjz*7vDBaRYn@J|M2KzWDwRiVUw(_ikNA00000NkvXXu0mjfOP&sp literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..82f752fdc28390f1dae188e66886f9fee783b4f7 GIT binary patch literal 602 zcmV-g0;TXoV&|>P?2N3a|H=XkIpb%g2C{mUcD8z%K5!WW71`A3B@}P?c zNzmeTUM-&`=;A@rh-=e`Ytx8p(}-)+h-=e`Yg0e*Nfwct-zMuNo?gfN+FNCOm6(Rs zNBrh8;rK_F^Mfu~8k>e2?@WdCI_7lHVR+IZj_>A~;=j0*zBpPVOJB@8&9C^w(v!^i zcs#`4qjGbZa60I4akN%e8hjOBptPW0e8JL!ZgC5x1-;^yN((y0EtVGC7q?tma9i9# zX~A7_N2LWf#T}Lw>=$=jTCiJOp|oJHxKe4sPI1N3!s5l1OACt?_fT4>Uffe@p<40r zRpP6(P_6jSy?2bx-x9}n#O>6o(Q^BiC^BxWR1^RB?JvEr|0>Nj5k)!eSD9&8HSzXK z2sbij-vth4?P;pL%~0mos(Tg<|DAn;kcS obzts&Y9%t@53qx{hWg?AJqc6disFjI`v3p{07*qoM6N<$f`4nJ zaCd?*qxs3xYk`8Mo-U3d5>t~6?){q5*x2~c-pCBZ5@_=ERFyG literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__tab_selected_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__tab_selected_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e4229f26b2771d884934b80d0056b8dd66d10edd GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol;0U|59*B=E^EX7WqAsj$Z!;#Vf4nJ zaCd?*qxs3xYk`8+o-U3d5>t~6?){q5*x2~c-l(n1@K5>ymj5$1a2Oc?!34d7Ck`Aq skg(^gW|wXH-lZoEvTk@AJm}J3sQWAGentL}KF}BjPgg&ebxsLQ0KFYBT>t<8 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__tab_selected_pressed_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__tab_selected_pressed_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e862cb12154541c150fb2d9bb98872bcff506317 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol;0U|59*B=E^EX7WqAsj$Z!;#Vf4nJ zaCd?*qxs3xYk`8Mo-U3d5>t~6?){q5*x2~c-pCBZ5m8aUV+M1MLNsm8aUV+8udAXlQhooEaFu)>JVsC;_i|1;&qn1z`CMwWxmD@8>XG@5j{z4 Z4Ch(42+t_Fa};PGgQu&X%Q~loCICWDCD8x? literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_right_default_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_right_default_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..98f4871bb52aa7c60414b62dc102a63025d14b86 GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^qCm{e!3HEJoIX|yq+C2*978nDC;#~W-=0~Khvol7 z1H)I2CW)>m8aUVm(v1b%el;0fY!m7fYzsPhAkg_?o6!P}0Ord_0t$qVOiDg+P{Wat YL8LkPQkkjERiJqcp00i_>zopr0H|OnC;$Ke literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_right_default_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_right_default_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..733373ed38d92906a3f639124b60d39cfe3ea469 GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^qCm{e!3HEJoIX|yq})7R978nDC;#~W-=0~Khvol7 z1H)I2CW)>m8aUVm(v20J8xM$gbsA4Oq2MIp#mnr@>uNTIF}6W!#;>-fvxg@opE#)D b$jGop@Lc3+&hjll6B#^R{an^LB{Ts5lN~2O literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_right_selected_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-xhdpi/abs__textfield_search_right_selected_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0c6bb036dbff7c452df0032fac9daaaf3ed36cff GIT binary patch literal 128 zcmeAS@N?(olHy`uVBq!ia0vp^qCm{e!3HEJoIX|yq})AS978nDC;#~W-=0~Khvol7 z1H)I2CW)>m8aUVm(v9t$CDZ2p!k(eA~|x?WSsfj bIFlKwHfSC=yJ^W9ppguou6{1-oD!Mm8aUVm(v9t$CDZ2p!k(eA~|x?WSsfj bIFlKwHfSC=yJ^W9ppguou6{1-oD!Mm8aUV)4xTaopEyItdE!^$Tn)$h3#7aBEDrH5l{lPKbU~WStl#0CqS)dY aj0`i|)DAxoJGT#LAcLo?pUXO@geCyp{V3}I literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__activated_background_holo_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__activated_background_holo_dark.xml new file mode 100644 index 00000000..85c2c021 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__activated_background_holo_dark.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__activated_background_holo_light.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__activated_background_holo_light.xml new file mode 100644 index 00000000..85c2c021 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__activated_background_holo_light.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__btn_cab_done_holo_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__btn_cab_done_holo_dark.xml new file mode 100644 index 00000000..cab89628 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__btn_cab_done_holo_dark.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__btn_cab_done_holo_light.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__btn_cab_done_holo_light.xml new file mode 100644 index 00000000..42ba8a0d --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__btn_cab_done_holo_light.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout-large-land/abs__screen_action_bar_overlay.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_clear.xml similarity index 71% rename from external/JakeWharton-ActionBarSherlock/library/res/layout-large-land/abs__screen_action_bar_overlay.xml rename to external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_clear.xml index 66a63f9d..a16f4b22 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout-large-land/abs__screen_action_bar_overlay.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_clear.xml @@ -1,25 +1,22 @@ - - - - - - + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__cab_ic_close_holo.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_clear_holo_light.xml similarity index 71% rename from external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__cab_ic_close_holo.xml rename to external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_clear_holo_light.xml index 0da7e237..256de80f 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__cab_ic_close_holo.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_clear_holo_light.xml @@ -15,9 +15,8 @@ --> - - - + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout-large-land/abs__screen_action_bar.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_menu_moreoverflow_holo_dark.xml similarity index 77% rename from external/JakeWharton-ActionBarSherlock/library/res/layout-large-land/abs__screen_action_bar.xml rename to external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_menu_moreoverflow_holo_dark.xml index 794f5283..2588a492 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout-large-land/abs__screen_action_bar.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_menu_moreoverflow_holo_dark.xml @@ -1,6 +1,5 @@ - - - - - - + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout-xlarge/abs__action_bar.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_menu_moreoverflow_holo_light.xml similarity index 73% rename from external/JakeWharton-ActionBarSherlock/library/res/layout-xlarge/abs__action_bar.xml rename to external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_menu_moreoverflow_holo_light.xml index a9641546..e2078c96 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout-xlarge/abs__action_bar.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__ic_menu_moreoverflow_holo_light.xml @@ -1,7 +1,5 @@ - - - - + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__item_background_holo_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__item_background_holo_dark.xml index b7b97b5a..d99b7a42 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__item_background_holo_dark.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__item_background_holo_dark.xml @@ -14,10 +14,7 @@ limitations under the License. --> - - - + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__item_background_holo_light.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__item_background_holo_light.xml index fdcac1d8..da5fb2e8 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__item_background_holo_light.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__item_background_holo_light.xml @@ -14,10 +14,7 @@ limitations under the License. --> - - - + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__list_selector_holo_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__list_selector_holo_dark.xml new file mode 100644 index 00000000..08b8b12f --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__list_selector_holo_dark.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__list_selector_holo_light.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__list_selector_holo_light.xml new file mode 100644 index 00000000..ada490bf --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__list_selector_holo_light.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_horizontal_holo_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_horizontal_holo_dark.xml new file mode 100644 index 00000000..bd19140a --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_horizontal_holo_dark.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_horizontal_holo_light.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_horizontal_holo_light.xml new file mode 100644 index 00000000..321f07c8 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_horizontal_holo_light.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_medium_holo.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_medium_holo.xml new file mode 100644 index 00000000..6d4814f8 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__progress_medium_holo.xml @@ -0,0 +1,34 @@ + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__search_dropdown_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__search_dropdown_dark.xml new file mode 100644 index 00000000..26284187 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__search_dropdown_dark.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__search_dropdown_light.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__search_dropdown_light.xml new file mode 100644 index 00000000..0d00c587 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__search_dropdown_light.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__spinner_background_holo_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__spinner_ab_holo_dark.xml similarity index 70% rename from external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__spinner_background_holo_dark.xml rename to external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__spinner_ab_holo_dark.xml index 8d350040..4af5e22a 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__spinner_background_holo_dark.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__spinner_ab_holo_dark.xml @@ -1,5 +1,5 @@ - - + - + - + - - + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_holo_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_holo_dark.xml new file mode 100644 index 00000000..b6d58c04 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_holo_dark.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_holo_light.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_holo_light.xml new file mode 100644 index 00000000..3d6acf80 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_holo_light.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_right_holo_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_right_holo_dark.xml new file mode 100644 index 00000000..05ff4eda --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_right_holo_dark.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_right_holo_light.xml b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_right_holo_light.xml new file mode 100644 index 00000000..f6d61e57 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/drawable/abs__textfield_searchview_right_holo_light.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout-large/abs__action_mode_close_item.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout-large/abs__action_mode_close_item.xml new file mode 100644 index 00000000..8811dad8 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout-large/abs__action_mode_close_item.xml @@ -0,0 +1,40 @@ + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout-v14/sherlock_spinner_dropdown_item.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout-v14/sherlock_spinner_dropdown_item.xml new file mode 100644 index 00000000..6c183c05 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout-v14/sherlock_spinner_dropdown_item.xml @@ -0,0 +1,26 @@ + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout-v14/sherlock_spinner_item.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout-v14/sherlock_spinner_item.xml new file mode 100644 index 00000000..61dc0252 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout-v14/sherlock_spinner_item.xml @@ -0,0 +1,26 @@ + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout-xlarge/abs__screen_action_bar.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout-xlarge/abs__screen_action_bar.xml index 794f5283..040df44a 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout-xlarge/abs__screen_action_bar.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout-xlarge/abs__screen_action_bar.xml @@ -1,6 +1,5 @@ - - - + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout-xlarge/abs__screen_action_bar_overlay.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout-xlarge/abs__screen_action_bar_overlay.xml index 66a63f9d..c64ef141 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout-xlarge/abs__screen_action_bar_overlay.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout-xlarge/abs__screen_action_bar_overlay.xml @@ -1,25 +1,49 @@ - + - - - - + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar.xml deleted file mode 100644 index 44f7dff2..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar.xml +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_home.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_home.xml index 3f846fbc..5c1e9ec4 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_home.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_home.xml @@ -1,37 +1,38 @@ - + - - - \ No newline at end of file + class="com.actionbarsherlock.internal.widget.ActionBarView$HomeView" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:background="?attr/actionBarItemBackground"> + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_inline.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_inline.xml deleted file mode 100644 index 2762c8bd..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_inline.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_item_layout.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_item_layout.xml deleted file mode 100644 index 85d86617..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_item_layout.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab.xml new file mode 100644 index 00000000..f46f7a04 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab.xml @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab_bar_view.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab_bar_view.xml new file mode 100644 index 00000000..0d51220c --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab_bar_view.xml @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab_layout.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab_layout.xml deleted file mode 100644 index 8af6662e..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_tab_layout.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_title_item.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_title_item.xml index 1d37ef58..dd69acad 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_title_item.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_bar_title_item.xml @@ -1,6 +1,5 @@ - - + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingRight="16dip" + android:background="?attr/actionBarItemBackground" + android:enabled="false"> + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_menu_item_layout.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_menu_item_layout.xml new file mode 100644 index 00000000..13149fd6 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_menu_item_layout.xml @@ -0,0 +1,56 @@ + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_menu_layout.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_menu_layout.xml new file mode 100644 index 00000000..a6f8e53f --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_menu_layout.xml @@ -0,0 +1,23 @@ + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_mode_bar.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_mode_bar.xml new file mode 100644 index 00000000..7168dc77 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_mode_bar.xml @@ -0,0 +1,24 @@ + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_mode_close_item.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_mode_close_item.xml new file mode 100644 index 00000000..875ec3e1 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__action_mode_close_item.xml @@ -0,0 +1,31 @@ + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__activity_chooser_view.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__activity_chooser_view.xml new file mode 100644 index 00000000..6a0ac9ec --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__activity_chooser_view.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__activity_chooser_view_list_item.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__activity_chooser_view_list_item.xml new file mode 100644 index 00000000..b430032a --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__activity_chooser_view_list_item.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__dialog_title_holo.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__dialog_title_holo.xml new file mode 100644 index 00000000..ab2b0ee6 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__dialog_title_holo.xml @@ -0,0 +1,46 @@ + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_checkbox.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_checkbox.xml new file mode 100644 index 00000000..39aca3a8 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_checkbox.xml @@ -0,0 +1,26 @@ + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_icon.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_icon.xml new file mode 100644 index 00000000..55ab28a2 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_icon.xml @@ -0,0 +1,28 @@ + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_layout.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_layout.xml new file mode 100644 index 00000000..147f36fe --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_layout.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_radio.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_radio.xml new file mode 100644 index 00000000..ff54bbec --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__list_menu_item_radio.xml @@ -0,0 +1,24 @@ + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__popup_menu_item_layout.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__popup_menu_item_layout.xml new file mode 100644 index 00000000..d42425ad --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__popup_menu_item_layout.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar.xml index d3a5fb79..1fb82fe9 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar.xml @@ -1,6 +1,5 @@ + android:fitsSystemWindows="true"> + style="?attr/actionBarStyle"> + style="?attr/actionBarStyle" /> + - - \ No newline at end of file + android:foreground="?attr/windowContentOverlay" /> + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_inline.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_inline.xml deleted file mode 100644 index 16c05d11..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_inline.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_inline_overlay.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_inline_overlay.xml deleted file mode 100644 index a8243dd4..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_inline_overlay.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_overlay.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_overlay.xml index a9c3cc7a..0961ef56 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_overlay.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_action_bar_overlay.xml @@ -1,48 +1,59 @@ - + - - - - + + style="?attr/actionBarStyle" /> + - - \ No newline at end of file + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_simple.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_simple.xml index 0687578f..33e2dea0 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_simple.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_simple.xml @@ -3,7 +3,6 @@ /* //device/apps/common/assets/res/layout/screen_simple.xml ** ** Copyright 2006, The Android Open Source Project -** Copyright 2011, Jake Wharton ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. @@ -23,21 +22,17 @@ enabled. --> - - + + android:foreground="?attr/windowContentOverlay" /> diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_simple_overlay_action_mode.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_simple_overlay_action_mode.xml new file mode 100644 index 00000000..f8b9fb18 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__screen_simple_overlay_action_mode.xml @@ -0,0 +1,38 @@ + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__search_dropdown_item_icons_2line.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__search_dropdown_item_icons_2line.xml new file mode 100644 index 00000000..e1d3dc49 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__search_dropdown_item_icons_2line.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__search_view.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__search_view.xml new file mode 100644 index 00000000..6ba31912 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__search_view.xml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__simple_dropdown_hint.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__simple_dropdown_hint.xml new file mode 100644 index 00000000..8fc0eb12 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__simple_dropdown_hint.xml @@ -0,0 +1,29 @@ + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/sherlock_spinner_dropdown_item.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/sherlock_spinner_dropdown_item.xml new file mode 100644 index 00000000..a6c6252d --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/sherlock_spinner_dropdown_item.xml @@ -0,0 +1,26 @@ + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__simple_spinner_item.xml b/external/JakeWharton-ActionBarSherlock/library/res/layout/sherlock_spinner_item.xml similarity index 96% rename from external/JakeWharton-ActionBarSherlock/library/res/layout/abs__simple_spinner_item.xml rename to external/JakeWharton-ActionBarSherlock/library/res/layout/sherlock_spinner_item.xml index 9be5ea8d..bea74017 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout/abs__simple_spinner_item.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/layout/sherlock_spinner_item.xml @@ -19,7 +19,7 @@ --> - - - 4 - \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-land/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-land/abs__dimens.xml new file mode 100644 index 00000000..502cc16a --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-land/abs__dimens.xml @@ -0,0 +1,33 @@ + + + + + 40dip + + 4dip + + 16dp + + 12dp + + -2dp + + 4dip + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-large-hdpi-1024x600/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-large-hdpi-1024x600/abs__dimens.xml new file mode 100644 index 00000000..3312cfa7 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-large-hdpi-1024x600/abs__dimens.xml @@ -0,0 +1,33 @@ + + + + + 48dip + + 8dip + + 18dp + + 14dp + + -3dp + + 5dip + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-large-land-hdpi-1024x600/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-large-land-hdpi-1024x600/abs__dimens.xml new file mode 100644 index 00000000..502cc16a --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-large-land-hdpi-1024x600/abs__dimens.xml @@ -0,0 +1,33 @@ + + + + + 40dip + + 4dip + + 16dp + + 12dp + + -2dp + + 4dip + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-large-land-mdpi-1024x600/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-large-land-mdpi-1024x600/abs__dimens.xml new file mode 100644 index 00000000..3312cfa7 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-large-land-mdpi-1024x600/abs__dimens.xml @@ -0,0 +1,33 @@ + + + + + 48dip + + 8dip + + 18dp + + 14dp + + -3dp + + 5dip + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-large-mdpi-1024x600/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-large-mdpi-1024x600/abs__dimens.xml new file mode 100644 index 00000000..35910333 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-large-mdpi-1024x600/abs__dimens.xml @@ -0,0 +1,36 @@ + + + + + 56dip + + 4dip + + 18dp + + 14dp + + -3dp + + 9dip + + + 64dip + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-large/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-large/abs__dimens.xml new file mode 100644 index 00000000..63b12f7f --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-large/abs__dimens.xml @@ -0,0 +1,29 @@ + + + + + 55% + + 80% + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/layout-large-land/abs__action_bar.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-sw600dp/abs__bools.xml similarity index 75% rename from external/JakeWharton-ActionBarSherlock/library/res/layout-large-land/abs__action_bar.xml rename to external/JakeWharton-ActionBarSherlock/library/res/values-sw600dp/abs__bools.xml index a9641546..7a48e154 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/layout-large-land/abs__action_bar.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-sw600dp/abs__bools.xml @@ -1,7 +1,5 @@ - - - - + + + false + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-sw600dp/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-sw600dp/abs__dimens.xml new file mode 100644 index 00000000..f6785381 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-sw600dp/abs__dimens.xml @@ -0,0 +1,38 @@ + + + + + 56dip + + 4dip + + 18dp + + 14dp + + -3dp + + 9dip + + 5 + + + 64dip + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-v11/abs__styles.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-v11/abs__styles.xml deleted file mode 100644 index 5c0dd103..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/values-v11/abs__styles.xml +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-v11/abs__themes.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-v11/abs__themes.xml new file mode 100644 index 00000000..03473572 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-v11/abs__themes.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-v13/abs__styles.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-v13/abs__styles.xml deleted file mode 100644 index 4112a4aa..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/values-v13/abs__styles.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-v14/abs__styles.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-v14/abs__styles.xml new file mode 100644 index 00000000..88a60dd9 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-v14/abs__styles.xml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-v14/abs__themes.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-v14/abs__themes.xml new file mode 100644 index 00000000..5fac1ab5 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-v14/abs__themes.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-w360dp/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-w360dp/abs__dimens.xml new file mode 100644 index 00000000..6f49d7e4 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-w360dp/abs__dimens.xml @@ -0,0 +1,22 @@ + + + + 3 + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-w480dp/abs__bools.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-w480dp/abs__bools.xml new file mode 100644 index 00000000..3eaf4aee --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-w480dp/abs__bools.xml @@ -0,0 +1,22 @@ + + + + true + false + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-w480dp/abs__config.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-w480dp/abs__config.xml new file mode 100644 index 00000000..88357b0a --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-w480dp/abs__config.xml @@ -0,0 +1,29 @@ + + + + + + + + true + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-w500dp/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-w500dp/abs__dimens.xml new file mode 100644 index 00000000..2fd4deea --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-w500dp/abs__dimens.xml @@ -0,0 +1,22 @@ + + + + 4 + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-w600dp/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-w600dp/abs__dimens.xml new file mode 100644 index 00000000..b085952d --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-w600dp/abs__dimens.xml @@ -0,0 +1,22 @@ + + + + 5 + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values-xlarge/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values-xlarge/abs__dimens.xml new file mode 100644 index 00000000..bfc535de --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values-xlarge/abs__dimens.xml @@ -0,0 +1,45 @@ + + + + + 56dip + + 4dip + + 18dp + + 14dp + + -3dp + + 9dip + + + 64dip + + + 45% + + 72% + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__attrs.xml b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__attrs.xml index 0e51e5ad..32631ca8 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__attrs.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__attrs.xml @@ -1,60 +1,432 @@ + + + + + + + - - + + + + + - - + + + + + + + + + + + + - + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + - + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__bools.xml b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__bools.xml new file mode 100644 index 00000000..0b432448 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__bools.xml @@ -0,0 +1,22 @@ + + + + + false + true + true + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__colors.xml b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__colors.xml new file mode 100644 index 00000000..625c632f --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__colors.xml @@ -0,0 +1,27 @@ + + + + + #ff000000 + #fff3f3f3 + @color/abs__background_holo_light + @color/abs__background_holo_dark + #ff4c4c4c + #ffb2b2b2 + @color/abs__bright_foreground_holo_light + @color/abs__bright_foreground_holo_dark + #ff33b5e5 + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__config.xml b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__config.xml new file mode 100644 index 00000000..4c7b5d45 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__config.xml @@ -0,0 +1,43 @@ + + + + + + + + 320dp + + + false + + + true + + + false + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__constants.xml b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__constants.xml deleted file mode 100644 index ddcb58b9..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__constants.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - #FF6899FF - 3 - tabUnderAb - \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__dimens.xml b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__dimens.xml new file mode 100644 index 00000000..831289e0 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__dimens.xml @@ -0,0 +1,67 @@ + + + + + 48dip + + 8dip + + 18dp + + 14dp + + -3dp + + 5dip + + 2 + + + 56dip + + + 64dip + + + 65% + + 95% + + + + 8dip + + + 8dip + + + 32dip + + + + 160dip + + + 320dip + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__ids.xml b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__ids.xml new file mode 100644 index 00000000..f9f56045 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__ids.xml @@ -0,0 +1,26 @@ + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__strings.xml b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__strings.xml new file mode 100644 index 00000000..06a2a2af --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__strings.xml @@ -0,0 +1,53 @@ + + + + + Navigate home + + Navigate up + + More options + + + Done + + + See all... + + Select activity + + Share with... + + Choose an application + + Share with + + Share with %s + + + Search + + Search query + + Clear query + + Submit query + + Voice search + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__styles.xml b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__styles.xml index a1fee779..45a18c18 100644 --- a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__styles.xml +++ b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__styles.xml @@ -1,224 +1,412 @@ - - - - - - - + + + + + + + + + + - - + + + + + + + + + + - - - + - - - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - + + + + + + - - - - + + - - - - - - + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/values/abs__themes.xml b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__themes.xml new file mode 100644 index 00000000..634fa798 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/values/abs__themes.xml @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/ActionBar.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/ActionBar.java deleted file mode 100644 index e4a72d03..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/ActionBar.java +++ /dev/null @@ -1,807 +0,0 @@ -/* - * Copyright 2011 Jake Wharton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -import android.app.Activity; -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.support.v4.view.ActionMode; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.MarginLayoutParams; -import android.widget.SpinnerAdapter; - -/** - * This is the public interface to the contextual ActionBar. The ActionBar acts - * as a replacement for the title bar in Activities. It provides facilities for - * creating toolbar actions as well as methods of navigating around an - * application. - */ -public abstract class ActionBar { - /** Parent activity. */ - protected final SupportActivity mActivity; - /** Parent context. */ - protected final Context mContext; - - - protected ActionBar(T activity) { - mActivity = activity; - mContext = activity; - } - - /** - * Return the actual public action bar instance. This will either return - * itself or null depending on the state of the underlying action bar. - * - * @return Action bar instance. - */ - protected abstract ActionBar getPublicInstance(); - - // ------------------------------------------------------------------------ - // ACTION MODE SUPPORT - // ------------------------------------------------------------------------ - - protected abstract ActionMode startActionMode(ActionMode.Callback callback); - - // ------------------------------------------------------------------------ - // ACTION BAR SUPPORT - // ------------------------------------------------------------------------ - - /** - * Per-child layout information associated with action bar custom views. - */ - public static class LayoutParams extends MarginLayoutParams { - /** - * Gravity for the view associated with these LayoutParams. - * - * @see android.view.Gravity - */ - public int gravity = -1; - - public LayoutParams() { - this(-1); - } - public LayoutParams(Context c, AttributeSet attrs) { - super(c, attrs); - } - public LayoutParams(int width, int height) { - super(width, height); - } - public LayoutParams(int width, int height, int gravity) { - this(width, height); - this.gravity = gravity; - } - public LayoutParams(int gravity) { - this(0, 0, gravity); - } - public LayoutParams(LayoutParams source) { - super(source); - this.gravity = source.gravity; - } - public LayoutParams(ViewGroup.LayoutParams source) { - super(source); - } - } - - /** - * Listener for receiving events when action bar menus are shown or hidden. - */ - public interface OnMenuVisibilityListener { - /** - * Called when an action bar menu is shown or hidden. Applications may - * want to use this to tune auto-hiding behavior for the action bar or - * pause/resume video playback, gameplay, or other activity within the - * main content area. - * - * @param isVisible True if an action bar menu is now visible, false if - * no action bar menus are visible. - */ - void onMenuVisibilityChanged(boolean isVisible); - } - - /** - * Listener interface for ActionBar navigation events. - */ - public interface OnNavigationListener { - /** - * This method is called whenever a navigation item in your action bar - * is selected. - * - * @param itemPosition Position of the item clicked. - * @param itemId ID of the item clicked. - * @return True if the event was handled, false otherwise. - */ - boolean onNavigationItemSelected(int itemPosition, long itemId); - } - - /** - *

A tab in the action bar.

- * - *

Tabs manage the hiding and showing of - * {@link android.support.v4.app.Fragment}.

- */ - public static abstract class Tab { - /** - * An invalid position for a tab. - * - * @see #getPosition() - */ - public static int INVALID_POSITION = android.app.ActionBar.Tab.INVALID_POSITION; - - - /** - * Retrieve a previously set custom view for this tab. - * - * @return The custom view set by {@link #setCustomView(View)}. - */ - public abstract View getCustomView(); - - /** - * Return the icon associated with this tab. - * - * @return The tab's icon - */ - public abstract Drawable getIcon(); - - /** - * Return the current position of this tab in the action bar. - * - * @return Current position, or {@link #INVALID_POSITION} if this tab is - * not currently in the action bar. - */ - public abstract int getPosition(); - - /** - * Return the current tab listener. - * - * @return Tab listener. - */ - public abstract ActionBar.TabListener getTabListener(); - - /** - * @return This Tab's tag object. - */ - public abstract Object getTag(); - - /** - * Return the text of this tab. - * - * @return The tab's text - */ - public abstract CharSequence getText(); - - /** - * Select this tab. Only valid if the tab has been added to the action - * bar. - */ - public abstract void select(); - - /** - * Set a custom view to be used for this tab. This overrides values set - * by {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}. - * - * @param layoutResId A layout resource to inflate and use as a custom - * tab view - * @return The current instance for call chaining - */ - public abstract ActionBar.Tab setCustomView(int layoutResId); - - /** - * Set a custom view to be used for this tab. This overrides values set - * by {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}. - * - * @param view Custom view to be used as a tab. - * @return The current instance for call chaining - */ - public abstract ActionBar.Tab setCustomView(View view); - - /** - * Set the icon displayed on this tab. - * - * @param icon The drawable to use as an icon - * @return The current instance for call chaining - */ - public abstract ActionBar.Tab setIcon(Drawable icon); - - /** - * Set the icon displayed on this tab. - * - * @param resId Resource ID referring to the drawable to use as an icon - * @return The current instance for call chaining - */ - public abstract ActionBar.Tab setIcon(int resId); - - /** - * Set the {@link ActionBar.TabListener} that will handle switching to - * and from this tab. All tabs must have a TabListener set before being - * added to the ActionBar. - * - * @param listener Listener to handle tab selection events - * @return The current instance for call chaining - */ - public abstract ActionBar.Tab setTabListener(ActionBar.TabListener listener); - - /** - * Give this Tab an arbitrary object to hold for later use. - * - * @param obj Object to store - * @return The current instance for call chaining - */ - public abstract ActionBar.Tab setTag(Object obj); - - /** - * Set the text displayed on this tab. Text may be truncated if there is - * not room to display the entire string. - * - * @param resId A resource ID referring to the text that should be displayed - * @return The current instance for call chaining - */ - public abstract ActionBar.Tab setText(int resId); - - /** - * Set the text displayed on this tab. Text may be truncated if there is - * not room to display the entire string. - * - * @param text The text to display - * @return The current instance for call chaining - */ - public abstract ActionBar.Tab setText(CharSequence text); - } - - /** - * Callback interface invoked when a tab is focused, unfocused, added, or - * removed. - */ - public interface TabListener { - /** - * Called when a tab that is already selected is chosen again by the - * user. Some applications may use this action to return to the top - * level of a category. - * - * @param tab The tab that was reselected. - * @param ft Unused, always {@code null}. Begin your own transaction by - * calling {@link FragmentActivity#getSupportFragmentManager()}. - */ - void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft); - - /** - * Called when a tab enters the selected state. - * - * @param tab The tab that was selected - * @param ft Unused, always {@code null}. Begin your own transaction by - * calling {@link FragmentActivity#getSupportFragmentManager()}. - */ - void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft); - - /** - * Called when a tab exits the selected state. - * - * @param tab The tab that was unselected - * @param ft Unused, always {@code null}. Begin your own transaction by - * calling {@link FragmentActivity#getSupportFragmentManager()}. - */ - void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft); - } - - - - /** - * Display the 'home' element such that it appears as an 'up' affordance. - * e.g. show an arrow to the left indicating the action that will be taken. - * Set this flag if selecting the 'home' button in the action bar to return - * up by a single level in your UI rather than back to the top level or - * front page. - * - * @see #setDisplayOptions(int) - * @see #setDisplayOptions(int, int) - */ - public static final int DISPLAY_HOME_AS_UP = android.app.ActionBar.DISPLAY_HOME_AS_UP; - - /** - * Show the custom view if one has been set. - * - * @see #setCustomView(int) - * @see #setCustomView(View) - * @see #setCustomView(View, LayoutParams) - * @see #setDisplayOptions(int) - * @see #setDisplayOptions(int, int) - */ - public static final int DISPLAY_SHOW_CUSTOM = android.app.ActionBar.DISPLAY_SHOW_CUSTOM; - - /** - * Show 'home' elements in this action bar, leaving more space for other - * navigation elements. This includes logo and icon. - * - * @see #setDisplayOptions(int) - * @see #setDisplayOptions(int, int) - */ - public static final int DISPLAY_SHOW_HOME = android.app.ActionBar.DISPLAY_SHOW_HOME; - - /** - * Show the activity title and subtitle, if present. - * - * @see #setTitle(CharSequence) - * @see #setTitle(int) - * @see #setSubtitle(CharSequence) - * @see #setSubtitle(int) - * @see #setDisplayOptions(int) - * @see #setDisplayOptions(int, int) - */ - public static final int DISPLAY_SHOW_TITLE = android.app.ActionBar.DISPLAY_SHOW_TITLE; - - /** - * Use logo instead of icon if available. This flag will cause appropriate - * navigation modes to use a wider logo in place of the standard icon. - * - * @see #setDisplayOptions(int) - * @see #setDisplayOptions(int, int) - */ - public static final int DISPLAY_USE_LOGO = android.app.ActionBar.DISPLAY_USE_LOGO; - - /** - * List navigation mode. Instead of static title text this mode presents a - * list menu for navigation within the activity. e.g. this might be - * presented to the user as a dropdown list. - */ - public static final int NAVIGATION_MODE_LIST = android.app.ActionBar.NAVIGATION_MODE_LIST; - - /** - * Standard navigation mode. Consists of either a logo or icon and title - * text with an optional subtitle. Clicking any of these elements will - * dispatch onOptionsItemSelected to the host Activity with a MenuItem with - * item ID android.R.id.home. - */ - public static final int NAVIGATION_MODE_STANDARD = android.app.ActionBar.NAVIGATION_MODE_STANDARD; - - /** - * Tab navigation mode. Instead of static title text this mode presents a - * series of tabs for navigation within the activity. - */ - public static final int NAVIGATION_MODE_TABS = android.app.ActionBar.NAVIGATION_MODE_TABS; - - - - /** - * Add a listener that will respond to menu visibility change events. - * - * @param listener The new listener to add - */ - public abstract void addOnMenuVisibilityListener(ActionBar.OnMenuVisibilityListener listener); - - /** - * Add a tab for use in tabbed navigation mode. The tab will be added at the - * end of the list. If this is the first tab to be added it will become the - * selected tab. - * - * @param tab Tab to add - */ - public abstract void addTab(ActionBar.Tab tab); - - /** - * Add a tab for use in tabbed navigation mode. The tab will be added at the - * end of the list. - * - * @param tab Tab to add - * @param setSelected True if the added tab should become the selected tab. - */ - public abstract void addTab(ActionBar.Tab tab, boolean setSelected); - - /** - * Add a tab for use in tabbed navigation mode. The tab will be inserted at - * {@code position}. If this is the first tab to be added it will become the - * selected tab. - * - * @param tab The tab to add - * @param position The new position of the tab - */ - public abstract void addTab(ActionBar.Tab tab, int position); - - /** - * Add a tab for use in tabbed navigation mode. The tab will be insterted at - * {@code position}. - * - * @param tab The tab to add - * @param position The new position of the tab - * @param setSelected True if the added tab should become the selected tab. - */ - public abstract void addTab(ActionBar.Tab tab, int position, boolean setSelected); - - /** - * @return The current custom view. - */ - public abstract View getCustomView(); - - /** - * @return The current set of display options. - */ - public abstract int getDisplayOptions(); - - /** - * Retrieve the current height of the ActionBar. - * - * @return The ActionBar's height - */ - public abstract int getHeight(); - - /** - * Get the number of navigation items present in the current navigation - * mode. - * - * @return Number of navigation items. - */ - public abstract int getNavigationItemCount(); - - /** - * Returns the current navigation mode. The result will be one of: - *
    - *
  • {@link #NAVIGATION_MODE_STANDARD}
  • - *
  • {@link #NAVIGATION_MODE_LIST}
  • - *
  • {@link #NAVIGATION_MODE_TABS}
  • - *
- * - * @return The current navigation mode. - * @see #setNavigationMode(int) - */ - public abstract int getNavigationMode(); - - /** - * Get the position of the selected navigation item in list or tabbed - * navigation modes. - * - * @return Position of the selected item. - */ - public abstract int getSelectedNavigationIndex(); - - /** - * Returns the currently selected tab if in tabbed navigation mode and there - * is at least one tab present. - * - * @return The currently selected tab or null. - */ - public abstract ActionBar.Tab getSelectedTab(); - - /** - * Returns the current ActionBar subtitle in standard mode. Returns null if - * {@link #getNavigationMode()} would not return - * {@link #NAVIGATION_MODE_STANDARD}. - * - * @return The current ActionBar subtitle or null. - */ - public abstract CharSequence getSubtitle(); - - /** - * Returns the tab at the specified index. - * - * @param index Index value in the range 0-get - * @return Tab at specified index - */ - public abstract ActionBar.Tab getTabAt(int index); - - /** - * Returns the number of tabs currently registered with the action bar. - * - * @return Tab count - */ - public abstract int getTabCount(); - - /** - * Returns the current ActionBar title in standard mode. Returns null if - * {@link #getNavigationMode()} would not return - * {@link #NAVIGATION_MODE_STANDARD}. - * - * @return The current ActionBar title or null. - */ - public abstract CharSequence getTitle(); - - /** - * Hide the ActionBar if it is not currently showing. If the window hosting - * the ActionBar does not have the feature - * {@link android.support.v4.view.Window#FEATURE_ACTION_BAR_OVERLAY} - * it will resize application content to fit the new space available. - */ - public abstract void hide(); - - /** - * @return {@code true} if the ActionBar is showing, {@code false} - * otherwise. - */ - public abstract boolean isShowing(); - - /** - * Create and return a new ActionBar.Tab. This tab will not be included in - * the action bar until it is added. - * - * @return A new Tab - * @see #addTab(Tab) - * @see #addTab(Tab, boolean) - * @see #addTab(Tab, int) - * @see #addTab(Tab, int, boolean) - */ - public abstract ActionBar.Tab newTab(); - - /** - * Remove all tabs from the action bar and deselect the current tab. - */ - public abstract void removeAllTabs(); - - /** - * Remove a menu visibility listener. This listener will no longer receive - * menu visibility change events. - * - * @param listener A listener to remove that was previously added - */ - public abstract void removeOnMenuVisibilityListener(ActionBar.OnMenuVisibilityListener listener); - - /** - * Remove a tab from the action bar. If the removed tab was selected it will - * be deselected and another tab will be selected if present. - * - * @param tab The tab to remove - */ - public abstract void removeTab(ActionBar.Tab tab); - - /** - * Remove a tab from the action bar. If the removed tab was selected it will - * be deselected and another tab will be selected if present. - * - * @param position Position of the tab to remove - */ - public abstract void removeTabAt(int position); - - /** - *

Select the specified tab. If it is not a child of this action bar it - * will be added.

- * - *

Note: If you want to select by index, use - * {@link #setSelectedNavigationItem(int)}.

- * - * @param tab Tab to select - */ - public abstract void selectTab(ActionBar.Tab tab); - - /** - * Set the ActionBar's background. - * - * @param d Background drawable - */ - public abstract void setBackgroundDrawable(Drawable d); - - /** - *

Set the action bar into custom navigation mode, supplying a view for - * custom navigation.

- * - *

Custom navigation views appear between the application icon and any - * action buttons and may use any space available there. Common use cases - * for custom navigation views might include an auto-suggesting address bar - * for a browser or other navigation mechanisms that do not translate well - * to provided navigation modes.

- * - *

The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for the - * custom view to be displayed.

- * - * @param resId Resource ID of a layout to inflate into the ActionBar. - * @see #setDisplayOptions(int, int) - */ - public abstract void setCustomView(int resId); - - /** - * Set the action bar into custom navigation mode, supplying a view for - * custom navigation. Custom navigation views appear between the application - * icon and any action buttons and may use any space available there. Common - * use cases for custom navigation views might include an auto-suggesting - * address bar for a browser or other navigation mechanisms that do not - * translate well to provided navigation modes. - * - * @param view Custom navigation view to place in the ActionBar. - */ - public abstract void setCustomView(View view); - - /** - *

Set the action bar into custom navigation mode, supplying a view for - * custom navigation.

- * - *

Custom navigation views appear between the application icon and any - * action buttons and may use any space available there. Common use cases - * for custom navigation views might include an auto-suggesting address bar - * for a browser or other navigation mechanisms that do not translate well - * to provided navigation modes.

- * - *

The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for the - * custom view to be displayed.

- * - * @param view Custom navigation view to place in the ActionBar. - * @param layoutParams How this custom view should layout in the bar. - * @see #setDisplayOptions(int, int) - */ - public abstract void setCustomView(View view, ActionBar.LayoutParams layoutParams); - - /** - *

Set whether home should be displayed as an "up" affordance. Set this - * to true if selecting "home" returns up by a single level in your UI - * rather than back to the top level or front page.

- * - *

To set several display options at once, see the setDisplayOptions - * methods.

- * - * @param showHomeAsUp {@code true} to show the user that selecting home - * will return one level up rather than to the top level of the app. - * @see #setDisplayOptions(int) - * @see #setDisplayOptions(int, int) - */ - public abstract void setDisplayHomeAsUpEnabled(boolean showHomeAsUp); - - /** - *

Set selected display options. Only the options specified by mask will - * be changed. To change all display option bits at once, see - * {@link #setDisplayOptions(int)}. - * - *

Example: {@code setDisplayOptions(0, DISPLAY_SHOW_HOME)} will disable - * the {@link #DISPLAY_SHOW_HOME} option. - * {@code setDisplayOptions(DISPLAY_SHOW_HOME, DISPLAY_SHOW_HOME | DISPLAY_USE_LOGO)} - * will enable {@link #DISPLAY_SHOW_HOME} and disable - * {@link #DISPLAY_USE_LOGO}.

- * - * @param options A combination of the bits defined by the DISPLAY_ - * constants defined in ActionBar. - * @param mask A bit mask declaring which display options should be changed. - */ - public abstract void setDisplayOptions(int options, int mask); - - /** - * Set display options. This changes all display option bits at once. To - * change a limited subset of display options, see - * {@link #setDisplayOptions(int, int)}. - * - * @param options A combination of the bits defined by the DISPLAY_ - * constants defined in ActionBar. - */ - public abstract void setDisplayOptions(int options); - - /** - *

Set whether a custom view should be displayed, if set.

- * - *

To set several display options at once, see the setDisplayOptions - * methods.

- * - * @param showCustom {@code true} if the currently set custom view should be - * displayed, {@code false} otherwise. - * @see #setDisplayOptions(int) - * @see #setDisplayOptions(int, int) - */ - public abstract void setDisplayShowCustomEnabled(boolean showCustom); - - /** - *

Set whether to include the application home affordance in the action - * bar. Home is presented as either an activity icon or logo.

- * - *

To set several display options at once, see the setDisplayOptions - * methods.

- * - * @param showHome {@code true} to show home, {@code false} otherwise. - * @see #setDisplayOptions(int) - * @see #setDisplayOptions(int, int) - */ - public abstract void setDisplayShowHomeEnabled(boolean showHome); - - /** - *

Set whether an activity title/subtitle should be displayed.

- * - *

To set several display options at once, see the setDisplayOptions - * methods.

- * - * @param showTitle {@code true} to display a title/subtitle if present. - * @see #setDisplayOptions(int) - * @see #setDisplayOptions(int, int) - */ - public abstract void setDisplayShowTitleEnabled(boolean showTitle); - - /** - *

Set whether to display the activity logo rather than the activity - * icon. A logo is often a wider, more detailed image.

- * - *

To set several display options at once, see the setDisplayOptions - * methods.

- * - * @param useLogo {@code true} to use the activity logo, {@code false} to - * use the activity icon. - * @see #setDisplayOptions(int) - * @see #setDisplayOptions(int, int) - */ - public abstract void setDisplayUseLogoEnabled(boolean useLogo); - - /** - * Set the adapter and navigation callback for list navigation mode. The - * supplied adapter will provide views for the expanded list as well as the - * currently selected item. (These may be displayed differently.) The - * supplied OnNavigationListener will alert the application when the user - * changes the current list selection. - * - * @param adapter An adapter that will provide views both to display the - * current navigation selection and populate views within the dropdown - * navigation menu. - * @param callback An OnNavigationListener that will receive events when the - * user selects a navigation item. - */ - public abstract void setListNavigationCallbacks(SpinnerAdapter adapter, ActionBar.OnNavigationListener callback); - - /** - * Set the current navigation mode. - * - * @param mode The new mode to set. - * @see #NAVIGATION_MODE_STANDARD - * @see #NAVIGATION_MODE_LIST - * @see #NAVIGATION_MODE_TABS - */ - public abstract void setNavigationMode(int mode); - - /** - * Set the selected navigation item in list or tabbed navigation modes. - * - * @param position Position of the item to select. - */ - public abstract void setSelectedNavigationItem(int position); - - /** - * Set the action bar's subtitle. This will only be displayed if - * @link #DISPLAY_SHOW_TITLE} is set. - * - * @param resId Resource ID of subtitle string to set - * @see #setSubtitle(CharSequence) - * @see #setDisplayOptions(int, int) - */ - public abstract void setSubtitle(int resId); - - /** - * Set the action bar's subtitle. This will only be displayed if - * @{link #DISPLAY_SHOW_TITLE} is set. Set to null to disable the subtitle - * entirely. - * - * @param subtitle Subtitle to set - * @see #setSubtitle(int) - * @see #setDisplayOptions(int, int) - */ - public abstract void setSubtitle(CharSequence subtitle); - - /** - * Set the action bar's title. This will only be displayed if - * @{link #DISPLAY_SHOW_TITLE} is set. - * - * @param title Title to set - * @see #setTitle(int) - * @see #setDisplayOptions(int, int) - */ - public abstract void setTitle(CharSequence title); - - /** - * Set the action bar's title. This will only be displayed if - * {@link #DISPLAY_SHOW_TITLE} is set. - * - * @param resId Resource ID of title string to set - * @see #setTitle(CharSequence) - * @see #setDisplayOptions(int, int) - */ - public abstract void setTitle(int resId); - - /** - * Show the ActionBar if it is not currently showing. If the window hosting - * the ActionBar does not have the feature - * {@link android.support.v4.view.Window#FEATURE_ACTION_BAR_OVERLAY} - * it will resize application content to fit the new space available. - */ - public abstract void show(); -} \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/BackStackRecord.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/BackStackRecord.java deleted file mode 100644 index 8da02c67..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/BackStackRecord.java +++ /dev/null @@ -1,721 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; -import android.text.TextUtils; -import android.util.Log; -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import com.actionbarsherlock.R; - -final class BackStackState implements Parcelable { - final int[] mOps; - final int mTransition; - final int mTransitionStyle; - final String mName; - final int mIndex; - final int mBreadCrumbTitleRes; - final CharSequence mBreadCrumbTitleText; - final int mBreadCrumbShortTitleRes; - final CharSequence mBreadCrumbShortTitleText; - - public BackStackState(FragmentManagerImpl fm, BackStackRecord bse) { - int numRemoved = 0; - BackStackRecord.Op op = bse.mHead; - while (op != null) { - if (op.removed != null) numRemoved += op.removed.size(); - op = op.next; - } - mOps = new int[bse.mNumOp*5 + numRemoved]; - - if (!bse.mAddToBackStack) { - throw new IllegalStateException("Not on back stack"); - } - - op = bse.mHead; - int pos = 0; - while (op != null) { - mOps[pos++] = op.cmd; - mOps[pos++] = op.fragment.mIndex; - mOps[pos++] = op.enterAnim; - mOps[pos++] = op.exitAnim; - if (op.removed != null) { - final int N = op.removed.size(); - mOps[pos++] = N; - for (int i=0; i 0) { - op.removed = new ArrayList(N); - for (int i=0; i CREATOR - = new Parcelable.Creator() { - public BackStackState createFromParcel(Parcel in) { - return new BackStackState(in); - } - - public BackStackState[] newArray(int size) { - return new BackStackState[size]; - } - }; -} - -/** - * @hide Entry of an operation on the fragment back stack. - */ -final class BackStackRecord extends FragmentTransaction implements - FragmentManager.BackStackEntry, Runnable { - static final String TAG = "BackStackEntry"; - - private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; - - final FragmentManagerImpl mManager; - - static final int OP_NULL = 0; - static final int OP_ADD = 1; - static final int OP_REPLACE = 2; - static final int OP_REMOVE = 3; - static final int OP_HIDE = 4; - static final int OP_SHOW = 5; - static final int OP_DETACH = 6; - static final int OP_ATTACH = 7; - - static final class Op { - Op next; - Op prev; - int cmd; - Fragment fragment; - int enterAnim; - int exitAnim; - ArrayList removed; - } - - Op mHead; - Op mTail; - int mNumOp; - int mEnterAnim; - int mExitAnim; - int mTransition; - int mTransitionStyle; - boolean mAddToBackStack; - boolean mAllowAddToBackStack = true; - String mName; - boolean mCommitted; - int mIndex; - - int mBreadCrumbTitleRes; - CharSequence mBreadCrumbTitleText; - int mBreadCrumbShortTitleRes; - CharSequence mBreadCrumbShortTitleText; - - public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { - writer.print(prefix); writer.print("mName="); writer.print(mName); - writer.print(" mIndex="); writer.print(mIndex); - writer.print(" mCommitted="); writer.println(mCommitted); - if (mTransition != FragmentTransaction.TRANSIT_NONE) { - writer.print(prefix); writer.print("mTransition=#"); - writer.print(Integer.toHexString(mTransition)); - writer.print(" mTransitionStyle=#"); - writer.println(Integer.toHexString(mTransitionStyle)); - } - if (mEnterAnim != 0 || mExitAnim !=0) { - writer.print(prefix); writer.print("mEnterAnim=#"); - writer.print(Integer.toHexString(mEnterAnim)); - writer.print(" mExitAnim=#"); - writer.println(Integer.toHexString(mExitAnim)); - } - if (mBreadCrumbTitleRes != 0 || mBreadCrumbTitleText != null) { - writer.print(prefix); writer.print("mBreadCrumbTitleRes=#"); - writer.print(Integer.toHexString(mBreadCrumbTitleRes)); - writer.print(" mBreadCrumbTitleText="); - writer.println(mBreadCrumbTitleText); - } - if (mBreadCrumbShortTitleRes != 0 || mBreadCrumbShortTitleText != null) { - writer.print(prefix); writer.print("mBreadCrumbShortTitleRes=#"); - writer.print(Integer.toHexString(mBreadCrumbShortTitleRes)); - writer.print(" mBreadCrumbShortTitleText="); - writer.println(mBreadCrumbShortTitleText); - } - - if (mHead != null) { - writer.print(prefix); writer.println("Operations:"); - String innerPrefix = prefix + " "; - Op op = mHead; - int num = 0; - while (op != null) { - writer.print(prefix); writer.print(" Op #"); writer.print(num); - writer.println(":"); - writer.print(innerPrefix); writer.print("cmd="); writer.print(op.cmd); - writer.print(" fragment="); writer.println(op.fragment); - if (op.enterAnim != 0 || op.exitAnim != 0) { - writer.print(prefix); writer.print("enterAnim="); writer.print(op.enterAnim); - writer.print(" exitAnim="); writer.println(op.exitAnim); - } - if (op.removed != null && op.removed.size() > 0) { - for (int i=0; i=0; i--) { - Fragment r = op.removed.get(i); - r.mBackStackNesting += amt; - if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Bump nesting of " - + r + " to " + r.mBackStackNesting); - } - } - op = op.next; - } - } - - public int commit() { - return commitInternal(false); - } - - public int commitAllowingStateLoss() { - return commitInternal(true); - } - - int commitInternal(boolean allowStateLoss) { - if (mCommitted) throw new IllegalStateException("commit already called"); - if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Commit: " + this); - mCommitted = true; - if (mAddToBackStack) { - mIndex = mManager.allocBackStackIndex(this); - } else { - mIndex = -1; - } - mManager.enqueueAction(this, allowStateLoss); - return mIndex; - } - - public void run() { - if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this); - - if (mAddToBackStack) { - if (mIndex < 0) { - throw new IllegalStateException("addToBackStack() called after commit()"); - } - } - - bumpBackStackNesting(1); - - Op op = mHead; - while (op != null) { - switch (op.cmd) { - case OP_ADD: { - Fragment f = op.fragment; - f.mNextAnim = op.enterAnim; - mManager.addFragment(f, false); - } break; - case OP_REPLACE: { - Fragment f = op.fragment; - if (mManager.mAdded != null) { - for (int i=0; i= 0) { - mManager.freeBackStackIndex(mIndex); - mIndex = -1; - } - } - - public String getName() { - return mName; - } - - public int getTransition() { - return mTransition; - } - - public int getTransitionStyle() { - return mTransitionStyle; - } - - public boolean isEmpty() { - return mNumOp == 0; - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/DialogFragment.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/DialogFragment.java deleted file mode 100644 index a5b89a91..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/DialogFragment.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; - -/** - * Static library support version of the framework's {@link android.app.DialogFragment}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - */ -public class DialogFragment extends Fragment - implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { - - /** - * Style for {@link #setStyle(int, int)}: a basic, - * normal dialog. - */ - public static final int STYLE_NORMAL = 0; - - /** - * Style for {@link #setStyle(int, int)}: don't include - * a title area. - */ - public static final int STYLE_NO_TITLE = 1; - - /** - * Style for {@link #setStyle(int, int)}: don't draw - * any frame at all; the view hierarchy returned by {@link #onCreateView} - * is entirely responsible for drawing the dialog. - */ - public static final int STYLE_NO_FRAME = 2; - - /** - * Style for {@link #setStyle(int, int)}: like - * {@link #STYLE_NO_FRAME}, but also disables all input to the dialog. - * The user can not touch it, and its window will not receive input focus. - */ - public static final int STYLE_NO_INPUT = 3; - - private static final String SAVED_DIALOG_STATE_TAG = "android:savedDialogState"; - private static final String SAVED_STYLE = "android:style"; - private static final String SAVED_THEME = "android:theme"; - private static final String SAVED_CANCELABLE = "android:cancelable"; - private static final String SAVED_SHOWS_DIALOG = "android:showsDialog"; - private static final String SAVED_BACK_STACK_ID = "android:backStackId"; - - int mStyle = STYLE_NORMAL; - int mTheme = 0; - boolean mCancelable = true; - boolean mShowsDialog = false; - int mBackStackId = -1; - - Dialog mDialog; - boolean mDestroyed; - boolean mRemoved; - - public DialogFragment() { - } - - /** - * Call to customize the basic appearance and behavior of the - * fragment's dialog. This can be used for some common dialog behaviors, - * taking care of selecting flags, theme, and other options for you. The - * same effect can be achieve by manually setting Dialog and Window - * attributes yourself. Calling this after the fragment's Dialog is - * created will have no effect. - * - * @param style Selects a standard style: may be {@link #STYLE_NORMAL}, - * {@link #STYLE_NO_TITLE}, {@link #STYLE_NO_FRAME}, or - * {@link #STYLE_NO_INPUT}. - * @param theme Optional custom theme. If 0, an appropriate theme (based - * on the style) will be selected for you. - */ - public void setStyle(int style, int theme) { - mStyle = style; - if (mStyle == STYLE_NO_FRAME || mStyle == STYLE_NO_INPUT) { - mTheme = android.R.style.Theme_Panel; - } - if (theme != 0) { - mTheme = theme; - } - } - - /** - * Display the dialog, adding the fragment to the given FragmentManager. This - * is a convenience for explicitly creating a transaction, adding the - * fragment to it with the given tag, and committing it. This does - * not add the transaction to the back stack. When the fragment - * is dismissed, a new transaction will be executed to remove it from - * the activity. - * @param manager The FragmentManager this fragment will be added to. - * @param tag The tag for this fragment, as per - * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}. - */ - public void show(FragmentManager manager, String tag) { - setShowsDialog(true); - FragmentTransaction ft = manager.beginTransaction(); - ft.add(this, tag); - ft.commit(); - } - - /** - * Display the dialog, adding the fragment using an existing transaction - * and then committing the transaction. - * @param transaction An existing transaction in which to add the fragment. - * @param tag The tag for this fragment, as per - * {@link FragmentTransaction#add(Fragment, String) FragmentTransaction.add}. - * @return Returns the identifier of the committed transaction, as per - * {@link FragmentTransaction#commit() FragmentTransaction.commit()}. - */ - public int show(FragmentTransaction transaction, String tag) { - setShowsDialog(true); - transaction.add(this, tag); - mRemoved = false; - mBackStackId = transaction.commit(); - return mBackStackId; - } - - /** - * Dismiss the fragment and its dialog. If the fragment was added to the - * back stack, all back stack state up to and including this entry will - * be popped. Otherwise, a new transaction will be committed to remove - * the fragment. - */ - public void dismiss() { - dismissInternal(false); - } - - void dismissInternal(boolean allowStateLoss) { - if (mDialog != null) { - mDialog.dismiss(); - mDialog = null; - } - mRemoved = true; - if (mBackStackId >= 0) { - getFragmentManager().popBackStack(mBackStackId, - FragmentManager.POP_BACK_STACK_INCLUSIVE); - mBackStackId = -1; - } else { - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.remove(this); - if (allowStateLoss) { - ft.commitAllowingStateLoss(); - } else { - ft.commit(); - } - } - } - - public Dialog getDialog() { - return mDialog; - } - - public int getTheme() { - return mTheme; - } - - /** - * Control whether the shown Dialog is cancelable. Use this instead of - * directly calling {@link Dialog#setCancelable(boolean) - * Dialog.setCancelable(boolean)}, because DialogFragment needs to change - * its behavior based on this. - * - * @param cancelable If true, the dialog is cancelable. The default - * is true. - */ - public void setCancelable(boolean cancelable) { - mCancelable = cancelable; - if (mDialog != null) mDialog.setCancelable(cancelable); - } - - /** - * Return the current value of {@link #setCancelable(boolean)}. - */ - public boolean isCancelable() { - return mCancelable; - } - - /** - * Controls whether this fragment should be shown in a dialog. If not - * set, no Dialog will be created in {@link #onActivityCreated(Bundle)}, - * and the fragment's view hierarchy will thus not be added to it. This - * allows you to instead use it as a normal fragment (embedded inside of - * its activity). - * - *

This is normally set for you based on whether the fragment is - * associated with a container view ID passed to - * {@link FragmentTransaction#add(int, Fragment) FragmentTransaction.add(int, Fragment)}. - * If the fragment was added with a container, setShowsDialog will be - * initialized to false; otherwise, it will be true. - * - * @param showsDialog If true, the fragment will be displayed in a Dialog. - * If false, no Dialog will be created and the fragment's view hierarchly - * left undisturbed. - */ - public void setShowsDialog(boolean showsDialog) { - mShowsDialog = showsDialog; - } - - /** - * Return the current value of {@link #setShowsDialog(boolean)}. - */ - public boolean getShowsDialog() { - return mShowsDialog; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - //SEE: http://stackoverflow.com/questions/5637894/dialogfragments-with-devices-api-level-11/7560686#7560686 - //mShowsDialog = mContainerId == 0; - - if (savedInstanceState != null) { - mStyle = savedInstanceState.getInt(SAVED_STYLE, STYLE_NORMAL); - mTheme = savedInstanceState.getInt(SAVED_THEME, 0); - mCancelable = savedInstanceState.getBoolean(SAVED_CANCELABLE, true); - mShowsDialog = savedInstanceState.getBoolean(SAVED_SHOWS_DIALOG, mShowsDialog); - mBackStackId = savedInstanceState.getInt(SAVED_BACK_STACK_ID, -1); - } - - } - - /** @hide */ - @Override - public LayoutInflater getLayoutInflater(Bundle savedInstanceState) { - if (!mShowsDialog) { - return super.getLayoutInflater(savedInstanceState); - } - - mDialog = onCreateDialog(savedInstanceState); - mDestroyed = false; - switch (mStyle) { - case STYLE_NO_INPUT: - mDialog.getWindow().addFlags( - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | - WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); - // fall through... - case STYLE_NO_FRAME: - case STYLE_NO_TITLE: - mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); - } - return (LayoutInflater)mDialog.getContext().getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - } - - /** - * Override to build your own custom Dialog container. This is typically - * used to show an AlertDialog instead of a generic Dialog; when doing so, - * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} does not need - * to be implemented since the AlertDialog takes care of its own content. - * - *

This method will be called after {@link #onCreate(Bundle)} and - * before {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}. The - * default implementation simply instantiates and returns a {@link Dialog} - * class. - * - *

Note: DialogFragment own the {@link Dialog#setOnCancelListener - * Dialog.setOnCancelListener} and {@link Dialog#setOnDismissListener - * Dialog.setOnDismissListener} callbacks. You must not set them yourself. - * To find out about these events, override {@link #onCancel(DialogInterface)} - * and {@link #onDismiss(DialogInterface)}.

- * - * @param savedInstanceState The last saved instance state of the Fragment, - * or null if this is a freshly created Fragment. - * - * @return Return a new Dialog instance to be displayed by the Fragment. - */ - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new Dialog(getActivity(), getTheme()); - } - - public void onCancel(DialogInterface dialog) { - } - - public void onDismiss(DialogInterface dialog) { - if (!mRemoved) { - // Note: we need to use allowStateLoss, because the dialog - // dispatches this asynchronously so we can receive the call - // after the activity is paused. Worst case, when the user comes - // back to the activity they see the dialog again. - dismissInternal(true); - } - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - if (!mShowsDialog) { - return; - } - - View view = getView(); - if (view != null) { - if (view.getParent() != null) { - throw new IllegalStateException("DialogFragment can not be attached to a container view"); - } - mDialog.setContentView(view); - } - mDialog.setOwnerActivity(getActivity()); - mDialog.setCancelable(mCancelable); - mDialog.setOnCancelListener(this); - mDialog.setOnDismissListener(this); - if (savedInstanceState != null) { - Bundle dialogState = savedInstanceState.getBundle(SAVED_DIALOG_STATE_TAG); - if (dialogState != null) { - mDialog.onRestoreInstanceState(dialogState); - } - } - } - - @Override - public void onStart() { - super.onStart(); - if (mDialog != null) { - mRemoved = false; - mDialog.show(); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (mDialog != null) { - Bundle dialogState = mDialog.onSaveInstanceState(); - if (dialogState != null) { - outState.putBundle(SAVED_DIALOG_STATE_TAG, dialogState); - } - } - if (mStyle != STYLE_NORMAL) { - outState.putInt(SAVED_STYLE, mStyle); - } - if (mTheme != 0) { - outState.putInt(SAVED_THEME, mTheme); - } - if (!mCancelable) { - outState.putBoolean(SAVED_CANCELABLE, mCancelable); - } - if (!mShowsDialog) { - outState.putBoolean(SAVED_SHOWS_DIALOG, mShowsDialog); - } - if (mBackStackId != -1) { - outState.putInt(SAVED_BACK_STACK_ID, mBackStackId); - } - } - - @Override - public void onStop() { - super.onStop(); - if (mDialog != null) { - mDialog.hide(); - } - } - - /** - * Remove dialog. - */ - @Override - public void onDestroyView() { - super.onDestroyView(); - mDestroyed = true; - if (mDialog != null) { - // Set removed here because this dismissal is just to hide - // the dialog -- we don't want this to cause the fragment to - // actually be removed. - mRemoved = true; - mDialog.dismiss(); - mDialog = null; - } - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/Fragment.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/Fragment.java deleted file mode 100644 index b701fddf..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/Fragment.java +++ /dev/null @@ -1,1339 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -import android.app.Activity; -import android.content.ComponentCallbacks; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.support.v4.util.DebugUtils; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuItem; -import android.util.AttributeSet; -import android.util.SparseArray; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.MenuInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.View.OnCreateContextMenuListener; -import android.view.animation.Animation; -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.HashMap; - -final class FragmentState implements Parcelable { - final String mClassName; - final int mIndex; - final boolean mFromLayout; - final int mFragmentId; - final int mContainerId; - final String mTag; - final boolean mRetainInstance; - final boolean mDetached; - final Bundle mArguments; - - Bundle mSavedFragmentState; - - Fragment mInstance; - - public FragmentState(Fragment frag) { - mClassName = frag.getClass().getName(); - mIndex = frag.mIndex; - mFromLayout = frag.mFromLayout; - mFragmentId = frag.mFragmentId; - mContainerId = frag.mContainerId; - mTag = frag.mTag; - mRetainInstance = frag.mRetainInstance; - mDetached = frag.mDetached; - mArguments = frag.mArguments; - } - - public FragmentState(Parcel in) { - mClassName = in.readString(); - mIndex = in.readInt(); - mFromLayout = in.readInt() != 0; - mFragmentId = in.readInt(); - mContainerId = in.readInt(); - mTag = in.readString(); - mRetainInstance = in.readInt() != 0; - mDetached = in.readInt() != 0; - mArguments = in.readBundle(); - mSavedFragmentState = in.readBundle(); - } - - public Fragment instantiate(SupportActivity activity) { - if (mInstance != null) { - return mInstance; - } - - if (mArguments != null) { - mArguments.setClassLoader(activity.getClassLoader()); - } - - mInstance = Fragment.instantiate(activity.asActivity(), mClassName, mArguments); - - if (mSavedFragmentState != null) { - mSavedFragmentState.setClassLoader(activity.getClassLoader()); - mInstance.mSavedFragmentState = mSavedFragmentState; - } - mInstance.setIndex(mIndex); - mInstance.mFromLayout = mFromLayout; - mInstance.mRestored = true; - mInstance.mFragmentId = mFragmentId; - mInstance.mContainerId = mContainerId; - mInstance.mTag = mTag; - mInstance.mRetainInstance = mRetainInstance; - mInstance.mDetached = mDetached; - mInstance.mFragmentManager = activity.getInternalCallbacks().getFragments(); - - return mInstance; - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(mClassName); - dest.writeInt(mIndex); - dest.writeInt(mFromLayout ? 1 : 0); - dest.writeInt(mFragmentId); - dest.writeInt(mContainerId); - dest.writeString(mTag); - dest.writeInt(mRetainInstance ? 1 : 0); - dest.writeInt(mDetached ? 1 : 0); - dest.writeBundle(mArguments); - dest.writeBundle(mSavedFragmentState); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public FragmentState createFromParcel(Parcel in) { - return new FragmentState(in); - } - - public FragmentState[] newArray(int size) { - return new FragmentState[size]; - } - }; -} - -/** - * Static library support version of the framework's {@link android.app.Fragment}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - */ -public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener { - private static final HashMap> sClassMap = - new HashMap>(); - - static final int INITIALIZING = 0; // Not yet created. - static final int CREATED = 1; // Created. - static final int ACTIVITY_CREATED = 2; // The activity has finished its creation. - static final int STOPPED = 3; // Fully created, not started. - static final int STARTED = 4; // Created and started, not resumed. - static final int RESUMED = 5; // Created started and resumed. - - int mState = INITIALIZING; - - // Non-null if the fragment's view hierarchy is currently animating away, - // meaning we need to wait a bit on completely destroying it. This is the - // view that is animating. - View mAnimatingAway; - - // If mAnimatingAway != null, this is the state we should move to once the - // animation is done. - int mStateAfterAnimating; - - // When instantiated from saved state, this is the saved state. - Bundle mSavedFragmentState; - SparseArray mSavedViewState; - - // Index into active fragment array. - int mIndex = -1; - - // Internal unique name for this fragment; - String mWho; - - // Construction arguments; - Bundle mArguments; - - // Target fragment. - Fragment mTarget; - - // For use when retaining a fragment: this is the index of the last mTarget. - int mTargetIndex = -1; - - // Target request code. - int mTargetRequestCode; - - // True if the fragment is in the list of added fragments. - boolean mAdded; - - // If set this fragment is being removed from its activity. - boolean mRemoving; - - // True if the fragment is in the resumed state. - boolean mResumed; - - // Set to true if this fragment was instantiated from a layout file. - boolean mFromLayout; - - // Set to true when the view has actually been inflated in its layout. - boolean mInLayout; - - // True if this fragment has been restored from previously saved state. - boolean mRestored; - - // Number of active back stack entries this fragment is in. - int mBackStackNesting; - - // The fragment manager we are associated with. Set as soon as the - // fragment is used in a transaction; cleared after it has been removed - // from all transactions. - FragmentManager mFragmentManager; - - // Set as soon as a fragment is added to a transaction (or removed), - // to be able to do validation. - SupportActivity mImmediateActivity; - - // Activity this fragment is attached to. - SupportActivity mActivity; - - // The optional identifier for this fragment -- either the container ID if it - // was dynamically added to the view hierarchy, or the ID supplied in - // layout. - int mFragmentId; - - // When a fragment is being dynamically added to the view hierarchy, this - // is the identifier of the parent container it is being added to. - int mContainerId; - - // The optional named tag for this fragment -- usually used to find - // fragments that are not part of the layout. - String mTag; - - // Set to true when the app has requested that this fragment be hidden - // from the user. - boolean mHidden; - - // Set to true when the app has requested that this fragment be deactivated. - boolean mDetached; - - // If set this fragment would like its instance retained across - // configuration changes. - boolean mRetainInstance; - - // If set this fragment is being retained across the current config change. - boolean mRetaining; - - // If set this fragment has menu items to contribute. - boolean mHasMenu; - - // Used to control whether or not this fragments menus (both options and - // context) are exposed regardless of whether or not they actually exist. - boolean mExposesMenu = true; - - // Used to verify that subclasses call through to super class. - boolean mCalled; - - // If app has requested a specific animation, this is the one to use. - int mNextAnim; - - // The parent container of the fragment after dynamically added to UI. - ViewGroup mContainer; - - // The View generated for this fragment. - View mView; - - // The real inner view that will save/restore state. - View mInnerView; - - LoaderManagerImpl mLoaderManager; - boolean mLoadersStarted; - boolean mCheckedForLoaderManager; - - /** - * State information that has been retrieved from a fragment instance - * through {@link FragmentManager#saveFragmentInstanceState(Fragment) - * FragmentManager.saveFragmentInstanceState}. - */ - public static class SavedState implements Parcelable { - final Bundle mState; - - SavedState(Bundle state) { - mState = state; - } - - SavedState(Parcel in, ClassLoader loader) { - mState = in.readBundle(); - if (loader != null && mState != null) { - mState.setClassLoader(loader); - } - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeBundle(mState); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public SavedState createFromParcel(Parcel in) { - return new SavedState(in, null); - } - - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; - } - - /** - * Thrown by {@link Fragment#instantiate(Context, String, Bundle)} when - * there is an instantiation failure. - */ - static public class InstantiationException extends RuntimeException { - private static final long serialVersionUID = 8423238441973733190L; - - public InstantiationException(String msg, Exception cause) { - super(msg, cause); - } - } - - /** - * Default constructor. Every fragment must have an - * empty constructor, so it can be instantiated when restoring its - * activity's state. It is strongly recommended that subclasses do not - * have other constructors with parameters, since these constructors - * will not be called when the fragment is re-instantiated; instead, - * arguments can be supplied by the caller with {@link #setArguments} - * and later retrieved by the Fragment with {@link #getArguments}. - * - *

Applications should generally not implement a constructor. The - * first place application code an run where the fragment is ready to - * be used is in {@link #onAttach(Activity)}, the point where the fragment - * is actually associated with its activity. Some applications may also - * want to implement {@link #onInflate} to retrieve attributes from a - * layout resource, though should take care here because this happens for - * the fragment is attached to its activity. - */ - public Fragment() { - } - - /** - * Like {@link #instantiate(Context, String, Bundle)} but with a null - * argument Bundle. - */ - public static Fragment instantiate(Context context, String fname) { - return instantiate(context, fname, null); - } - - /** - * Create a new instance of a Fragment with the given class name. This is - * the same as calling its empty constructor. - * - * @param context The calling context being used to instantiate the fragment. - * This is currently just used to get its ClassLoader. - * @param fname The class name of the fragment to instantiate. - * @param args Bundle of arguments to supply to the fragment, which it - * can retrieve with {@link #getArguments()}. May be null. - * @return Returns a new fragment instance. - * @throws InstantiationException If there is a failure in instantiating - * the given fragment class. This is a runtime exception; it is not - * normally expected to happen. - */ - public static Fragment instantiate(Context context, String fname, Bundle args) { - try { - Class clazz = sClassMap.get(fname); - if (clazz == null) { - // Class not found in the cache, see if it's real, and try to add it - clazz = context.getClassLoader().loadClass(fname); - sClassMap.put(fname, clazz); - } - Fragment f = (Fragment)clazz.newInstance(); - if (args != null) { - args.setClassLoader(f.getClass().getClassLoader()); - f.mArguments = args; - } - return f; - } catch (ClassNotFoundException e) { - throw new InstantiationException("Unable to instantiate fragment " + fname - + ": make sure class name exists, is public, and has an" - + " empty constructor that is public", e); - } catch (java.lang.InstantiationException e) { - throw new InstantiationException("Unable to instantiate fragment " + fname - + ": make sure class name exists, is public, and has an" - + " empty constructor that is public", e); - } catch (IllegalAccessException e) { - throw new InstantiationException("Unable to instantiate fragment " + fname - + ": make sure class name exists, is public, and has an" - + " empty constructor that is public", e); - } - } - - final void restoreViewState() { - if (mSavedViewState != null) { - mInnerView.restoreHierarchyState(mSavedViewState); - mSavedViewState = null; - } - } - - final void setIndex(int index) { - mIndex = index; - mWho = "android:fragment:" + mIndex; - } - - final boolean isInBackStack() { - return mBackStackNesting > 0; - } - - /** - * Subclasses can not override equals(). - */ - @Override final public boolean equals(Object o) { - return super.equals(o); - } - - /** - * Subclasses can not override hashCode(). - */ - @Override final public int hashCode() { - return super.hashCode(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(128); - DebugUtils.buildShortClassTag(this, sb); - if (mIndex >= 0) { - sb.append(" #"); - sb.append(mIndex); - } - if (mFragmentId != 0) { - sb.append(" id=0x"); - sb.append(Integer.toHexString(mFragmentId)); - } - if (mTag != null) { - sb.append(" "); - sb.append(mTag); - } - sb.append('}'); - return sb.toString(); - } - - /** - * Return the identifier this fragment is known by. This is either - * the android:id value supplied in a layout or the container view ID - * supplied when adding the fragment. - */ - final public int getId() { - return mFragmentId; - } - - /** - * Get the tag name of the fragment, if specified. - */ - final public String getTag() { - return mTag; - } - - /** - * Supply the construction arguments for this fragment. This can only - * be called before the fragment has been attached to its activity; that - * is, you should call it immediately after constructing the fragment. The - * arguments supplied here will be retained across fragment destroy and - * creation. - */ - public void setArguments(Bundle args) { - if (mIndex >= 0) { - throw new IllegalStateException("Fragment already active"); - } - mArguments = args; - } - - /** - * Return the arguments supplied when the fragment was instantiated, - * if any. - */ - final public Bundle getArguments() { - return mArguments; - } - - /** - * Set the initial saved state that this Fragment should restore itself - * from when first being constructed, as returned by - * {@link FragmentManager#saveFragmentInstanceState(Fragment) - * FragmentManager.saveFragmentInstanceState}. - * - * @param state The state the fragment should be restored from. - */ - public void setInitialSavedState(SavedState state) { - if (mIndex >= 0) { - throw new IllegalStateException("Fragment already active"); - } - mSavedFragmentState = state != null && state.mState != null - ? state.mState : null; - } - - /** - * Optional target for this fragment. This may be used, for example, - * if this fragment is being started by another, and when done wants to - * give a result back to the first. The target set here is retained - * across instances via {@link FragmentManager#putFragment - * FragmentManager.putFragment()}. - * - * @param fragment The fragment that is the target of this one. - * @param requestCode Optional request code, for convenience if you - * are going to call back with {@link #onActivityResult(int, int, Intent)}. - */ - public void setTargetFragment(Fragment fragment, int requestCode) { - mTarget = fragment; - mTargetRequestCode = requestCode; - } - - /** - * Return the target fragment set by {@link #setTargetFragment}. - */ - final public Fragment getTargetFragment() { - return mTarget; - } - - /** - * Return the target request code set by {@link #setTargetFragment}. - */ - final public int getTargetRequestCode() { - return mTargetRequestCode; - } - - /** - * Return the Activity this fragment is currently associated with. - * - * @see #getSupportActivity() - */ - final public Activity getActivity() { - return (mActivity != null) ? mActivity.asActivity() : null; - } - - /** - * Return the SupportActivity interface for the activity in which this - * fragment is currently associated. - * - * @see #getActivity() - */ - final public SupportActivity getSupportActivity() { - return mActivity; - } - - /** - * Return getActivity().getResources(). - */ - final public Resources getResources() { - if (mActivity == null) { - throw new IllegalStateException("Fragment " + this + " not attached to Activity"); - } - return mActivity.getResources(); - } - - /** - * Return a localized, styled CharSequence from the application's package's - * default string table. - * - * @param resId Resource id for the CharSequence text - */ - public final CharSequence getText(int resId) { - return getResources().getText(resId); - } - - /** - * Return a localized string from the application's package's - * default string table. - * - * @param resId Resource id for the string - */ - public final String getString(int resId) { - return getResources().getString(resId); - } - - /** - * Return a localized formatted string from the application's package's - * default string table, substituting the format arguments as defined in - * {@link java.util.Formatter} and {@link java.lang.String#format}. - * - * @param resId Resource id for the format string - * @param formatArgs The format arguments that will be used for substitution. - */ - - public final String getString(int resId, Object... formatArgs) { - return getResources().getString(resId, formatArgs); - } - - /** - * Return the FragmentManager for interacting with fragments associated - * with this fragment's activity. Note that this will be non-null slightly - * before {@link #getActivity()}, during the time from when the fragment is - * placed in a {@link FragmentTransaction} until it is committed and - * attached to its activity. - */ - final public FragmentManager getFragmentManager() { - return mFragmentManager; - } - - /** - * A clone of {@link #getFragmentManager()} to maintain naming conventions - * throughout the compatibility library. - */ - final public FragmentManager getSupportFragmentManager() { - return mFragmentManager; - } - - /** - * Return true if the fragment is currently added to its activity. - */ - final public boolean isAdded() { - return mActivity != null && mAdded; - } - - /** - * Return true if the fragment has been explicitly detached from the UI. - * That is, {@link FragmentTransaction#detach(Fragment) - * FragmentTransaction.detach(Fragment)} has been used on it. - */ - final public boolean isDetached() { - return mDetached; - } - - /** - * Return true if this fragment is currently being removed from its - * activity. This is not whether its activity is finishing, but - * rather whether it is in the process of being removed from its activity. - */ - final public boolean isRemoving() { - return mRemoving; - } - - /** - * Return true if the layout is included as part of an activity view - * hierarchy via the <fragment> tag. This will always be true when - * fragments are created through the <fragment> tag, except - * in the case where an old fragment is restored from a previous state and - * it does not appear in the layout of the current state. - */ - final public boolean isInLayout() { - return mInLayout; - } - - /** - * Return true if the fragment is in the resumed state. This is true - * for the duration of {@link #onResume()} and {@link #onPause()} as well. - */ - final public boolean isResumed() { - return mResumed; - } - - /** - * Return true if the fragment is currently visible to the user. This means - * it: (1) has been added, (2) has its view attached to the window, and - * (3) is not hidden. - */ - final public boolean isVisible() { - return isAdded() && !isHidden() && mView != null - && mView.getWindowToken() != null && mView.getVisibility() == View.VISIBLE; - } - - /** - * Return true if the fragment has been hidden. By default fragments - * are shown. You can find out about changes to this state with - * {@link #onHiddenChanged}. Note that the hidden state is orthogonal - * to other states -- that is, to be visible to the user, a fragment - * must be both started and not hidden. - */ - final public boolean isHidden() { - return mHidden; - } - - /** - * Called when the hidden state (as returned by {@link #isHidden()} of - * the fragment has changed. Fragments start out not hidden; this will - * be called whenever the fragment changes state from that. - * @param hidden True if the fragment is now hidden, false if it is not - * visible. - */ - public void onHiddenChanged(boolean hidden) { - } - - /** - * Control whether a fragment instance is retained across Activity - * re-creation (such as from a configuration change). This can only - * be used with fragments not in the back stack. If set, the fragment - * lifecycle will be slightly different when an activity is recreated: - *

    - *
  • {@link #onDestroy()} will not be called (but {@link #onDetach()} still - * will be, because the fragment is being detached from its current activity). - *
  • {@link #onCreate(Bundle)} will not be called since the fragment - * is not being re-created. - *
  • {@link #onAttach(Activity)} and {@link #onActivityCreated(Bundle)} will - * still be called. - *
- */ - public void setRetainInstance(boolean retain) { - mRetainInstance = retain; - } - - final public boolean getRetainInstance() { - return mRetainInstance; - } - - /** - * Report that this fragment would like to participate in populating - * the options menu by receiving a call to {@link #onCreateOptionsMenu} - * and related methods. - * - * @param hasMenu If true, the fragment has menu items to contribute. - */ - public void setHasOptionsMenu(boolean hasMenu) { - if (mHasMenu != hasMenu) { - mHasMenu = hasMenu; - if (isAdded() && !isHidden()) { - mActivity.invalidateOptionsMenu(); - } - } - } - - /** - * Return the LoaderManager for this fragment, creating it if needed. - */ - public LoaderManager getLoaderManager() { - if (mLoaderManager != null) { - return mLoaderManager; - } - if (mActivity == null) { - throw new IllegalStateException("Fragment " + this + " not attached to Activity"); - } - mCheckedForLoaderManager = true; - mLoaderManager = mActivity.getInternalCallbacks().getLoaderManager(mIndex, mLoadersStarted, true); - return mLoaderManager; - } - - /** - * Call {@link Activity#startActivity(Intent)} on the fragment's - * containing Activity. - */ - public void startActivity(Intent intent) { - if (mActivity == null) { - throw new IllegalStateException("Fragment " + this + " not attached to Activity"); - } - mActivity.startActivityFromFragment(this, intent, -1); - } - - /** - * Call {@link Activity#startActivityForResult(Intent, int)} on the fragment's - * containing Activity. - */ - public void startActivityForResult(Intent intent, int requestCode) { - if (mActivity == null) { - throw new IllegalStateException("Fragment " + this + " not attached to Activity"); - } - mActivity.startActivityFromFragment(this, intent, requestCode); - } - - /** - * Receive the result from a previous call to - * {@link #startActivityForResult(Intent, int)}. This follows the - * related Activity API as described there in - * {@link Activity#onActivityResult(int, int, Intent)}. - * - * @param requestCode The integer request code originally supplied to - * startActivityForResult(), allowing you to identify who this - * result came from. - * @param resultCode The integer result code returned by the child activity - * through its setResult(). - * @param data An Intent, which can return result data to the caller - * (various data can be attached to Intent "extras"). - */ - public void onActivityResult(int requestCode, int resultCode, Intent data) { - } - - /** - * @hide Hack so that DialogFragment can make its Dialog before creating - * its views, and the view construction can use the dialog's context for - * inflation. Maybe this should become a public API. Note sure. - */ - public LayoutInflater getLayoutInflater(Bundle savedInstanceState) { - return mActivity.getLayoutInflater(); - } - - /** - * Called when a fragment is being created as part of a view layout - * inflation, typically from setting the content view of an activity. This - * may be called immediately after the fragment is created from a - * tag in a layout file. Note this is before the fragment's - * {@link #onAttach(Activity)} has been called; all you should do here is - * parse the attributes and save them away. - * - *

This is called every time the fragment is inflated, even if it is - * being inflated into a new instance with saved state. It typically makes - * sense to re-parse the parameters each time, to allow them to change with - * different configurations.

- * - *

Here is a typical implementation of a fragment that can take parameters - * both through attributes supplied here as well from {@link #getArguments()}:

- * - * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentArguments.java - * fragment} - * - *

Note that parsing the XML attributes uses a "styleable" resource. The - * declaration for the styleable used here is:

- * - * {@sample development/samples/ApiDemos/res/values/attrs.xml fragment_arguments} - * - *

The fragment can then be declared within its activity's content layout - * through a tag like this:

- * - * {@sample development/samples/ApiDemos/res/layout/fragment_arguments.xml from_attributes} - * - *

This fragment can also be created dynamically from arguments given - * at runtime in the arguments Bundle; here is an example of doing so at - * creation of the containing activity:

- * - * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentArguments.java - * create} - * - * @param activity The Activity that is inflating this fragment. - * @param attrs The attributes at the tag where the fragment is - * being created. - * @param savedInstanceState If the fragment is being re-created from - * a previous saved state, this is the state. - */ - public void onInflate(SupportActivity activity, AttributeSet attrs, Bundle savedInstanceState) { - mCalled = true; - } - - /** - * Called when a fragment is first attached to its activity. - * {@link #onCreate(Bundle)} will be called after this. - */ - public void onAttach(SupportActivity activity) { - mCalled = true; - } - - /** - * Called when a fragment loads an animation. - */ - public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) { - return null; - } - - /** - * Called to do initial creation of a fragment. This is called after - * {@link #onAttach(Activity)} and before - * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}. - * - *

Note that this can be called while the fragment's activity is - * still in the process of being created. As such, you can not rely - * on things like the activity's content view hierarchy being initialized - * at this point. If you want to do work once the activity itself is - * created, see {@link #onActivityCreated(Bundle)}. - * - * @param savedInstanceState If the fragment is being re-created from - * a previous saved state, this is the state. - */ - public void onCreate(Bundle savedInstanceState) { - mCalled = true; - } - - /** - * Called to have the fragment instantiate its user interface view. - * This is optional, and non-graphical fragments can return null (which - * is the default implementation). This will be called between - * {@link #onCreate(Bundle)} and {@link #onActivityCreated(Bundle)}. - * - *

If you return a View from here, you will later be called in - * {@link #onDestroyView} when the view is being released. - * - * @param inflater The LayoutInflater object that can be used to inflate - * any views in the fragment, - * @param container If non-null, this is the parent view that the fragment's - * UI should be attached to. The fragment should not add the view itself, - * but this can be used to generate the LayoutParams of the view. - * @param savedInstanceState If non-null, this fragment is being re-constructed - * from a previous saved state as given here. - * - * @return Return the View for the fragment's UI, or null. - */ - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - return null; - } - - /** - * Called immediately after {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)} - * has returned, but before any saved state has been restored in to the view. - * This gives subclasses a chance to initialize themselves once - * they know their view hierarchy has been completely created. The fragment's - * view hierarchy is not however attached to its parent at this point. - * @param view The View returned by {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}. - * @param savedInstanceState If non-null, this fragment is being re-constructed - * from a previous saved state as given here. - */ - public void onViewCreated(View view, Bundle savedInstanceState) { - } - - /** - * Get the root view for the fragment's layout (the one returned by {@link #onCreateView}), - * if provided. - * - * @return The fragment's root view, or null if it has no layout. - */ - public View getView() { - return mView; - } - - /** - * Called when the fragment's activity has been created and this - * fragment's view hierarchy instantiated. It can be used to do final - * initialization once these pieces are in place, such as retrieving - * views or restoring state. It is also useful for fragments that use - * {@link #setRetainInstance(boolean)} to retain their instance, - * as this callback tells the fragment when it is fully associated with - * the new activity instance. This is called after {@link #onCreateView} - * and before {@link #onStart()}. - * - * @param savedInstanceState If the fragment is being re-created from - * a previous saved state, this is the state. - */ - public void onActivityCreated(Bundle savedInstanceState) { - mCalled = true; - } - - /** - * Called when the Fragment is visible to the user. This is generally - * tied to {@link Activity#onStart() Activity.onStart} of the containing - * Activity's lifecycle. - */ - public void onStart() { - mCalled = true; - - if (!mLoadersStarted) { - mLoadersStarted = true; - if (!mCheckedForLoaderManager) { - mCheckedForLoaderManager = true; - mLoaderManager = mActivity.getInternalCallbacks().getLoaderManager(mIndex, mLoadersStarted, false); - } - if (mLoaderManager != null) { - mLoaderManager.doStart(); - } - } - } - - /** - * Called when the fragment is visible to the user and actively running. - * This is generally - * tied to {@link Activity#onResume() Activity.onResume} of the containing - * Activity's lifecycle. - */ - public void onResume() { - mCalled = true; - } - - /** - * Called to ask the fragment to save its current dynamic state, so it - * can later be reconstructed in a new instance of its process is - * restarted. If a new instance of the fragment later needs to be - * created, the data you place in the Bundle here will be available - * in the Bundle given to {@link #onCreate(Bundle)}, - * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}, and - * {@link #onActivityCreated(Bundle)}. - * - *

This corresponds to {@link Activity#onSaveInstanceState(Bundle) - * Activity.onSaveInstanceState(Bundle)} and most of the discussion there - * applies here as well. Note however: this method may be called - * at any time before {@link #onDestroy()}. There are many situations - * where a fragment may be mostly torn down (such as when placed on the - * back stack with no UI showing), but its state will not be saved until - * its owning activity actually needs to save its state. - * - * @param outState Bundle in which to place your saved state. - */ - public void onSaveInstanceState(Bundle outState) { - } - - public void onConfigurationChanged(Configuration newConfig) { - mCalled = true; - } - - /** - * Called when the Fragment is no longer resumed. This is generally - * tied to {@link Activity#onPause() Activity.onPause} of the containing - * Activity's lifecycle. - */ - public void onPause() { - mCalled = true; - } - - /** - * Called when the Fragment is no longer started. This is generally - * tied to {@link Activity#onStop() Activity.onStop} of the containing - * Activity's lifecycle. - */ - public void onStop() { - mCalled = true; - } - - public void onLowMemory() { - mCalled = true; - } - - /** - * Called when the view previously created by {@link #onCreateView} has - * been detached from the fragment. The next time the fragment needs - * to be displayed, a new view will be created. This is called - * after {@link #onStop()} and before {@link #onDestroy()}. It is called - * regardless of whether {@link #onCreateView} returned a - * non-null view. Internally it is called after the view's state has - * been saved but before it has been removed from its parent. - */ - public void onDestroyView() { - mCalled = true; - } - - /** - * Called when the fragment is no longer in use. This is called - * after {@link #onStop()} and before {@link #onDetach()}. - */ - public void onDestroy() { - mCalled = true; - //Log.v("foo", "onDestroy: mCheckedForLoaderManager=" + mCheckedForLoaderManager - // + " mLoaderManager=" + mLoaderManager); - if (!mCheckedForLoaderManager) { - mCheckedForLoaderManager = true; - mLoaderManager = mActivity.getInternalCallbacks().getLoaderManager(mIndex, mLoadersStarted, false); - } - if (mLoaderManager != null) { - mLoaderManager.doDestroy(); - } - } - - /** - * Called by the fragment manager once this fragment has been removed, - * so that we don't have any left-over state if the application decides - * to re-use the instance. This only clears state that the framework - * internally manages, not things the application sets. - */ - void initState() { - mIndex = -1; - mWho = null; - mAdded = false; - mRemoving = false; - mResumed = false; - mFromLayout = false; - mInLayout = false; - mRestored = false; - mBackStackNesting = 0; - mFragmentManager = null; - mActivity = null; - mImmediateActivity = null; - mFragmentId = 0; - mContainerId = 0; - mTag = null; - mHidden = false; - mDetached = false; - mRetaining = false; - mLoaderManager = null; - mLoadersStarted = false; - mCheckedForLoaderManager = false; - } - - /** - * Called when the fragment is no longer attached to its activity. This - * is called after {@link #onDestroy()}. - */ - public void onDetach() { - mCalled = true; - } - - /** - * Initialize the contents of the Activity's standard options menu. You - * should place your menu items in to menu. For this method - * to be called, you must have first called {@link #setHasOptionsMenu}. See - * {@link Activity#onCreateOptionsMenu(Menu) Activity.onCreateOptionsMenu} - * for more information. - * - * @param menu The options menu in which you place your items. - * - * @see #setHasOptionsMenu - * @see #onPrepareOptionsMenu - * @see #onOptionsItemSelected - */ - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - } - - /** - * Prepare the Screen's standard options menu to be displayed. This is - * called right before the menu is shown, every time it is shown. You can - * use this method to efficiently enable/disable items or otherwise - * dynamically modify the contents. See - * {@link Activity#onPrepareOptionsMenu(Menu) Activity.onPrepareOptionsMenu} - * for more information. - * - * @param menu The options menu as last shown or first initialized by - * onCreateOptionsMenu(). - * - * @see #setHasOptionsMenu - * @see #onCreateOptionsMenu - */ - public void onPrepareOptionsMenu(Menu menu) { - } - - /** - * Called when this fragment's option menu items are no longer being - * included in the overall options menu. Receiving this call means that - * the menu needed to be rebuilt, but this fragment's items were not - * included in the newly built menu (its {@link #onCreateOptionsMenu(Menu, MenuInflater)} - * was not called). - */ - public void onDestroyOptionsMenu() { - } - - /** - * This hook is called whenever an item in your options menu is selected. - * The default implementation simply returns false to have the normal - * processing happen (calling the item's Runnable or sending a message to - * its Handler as appropriate). You can use this method for any items - * for which you would like to do processing without those other - * facilities. - * - *

Derived classes should call through to the base class for it to - * perform the default menu handling. - * - * @param item The menu item that was selected. - * - * @return boolean Return false to allow normal menu processing to - * proceed, true to consume it here. - * - * @see #onCreateOptionsMenu - */ - public boolean onOptionsItemSelected(MenuItem item) { - return false; - } - - /** - * This hook is called whenever the options menu is being closed (either by the user canceling - * the menu with the back/menu button, or when an item is selected). - * - * @param menu The options menu as last shown or first initialized by - * onCreateOptionsMenu(). - */ - public void onOptionsMenuClosed(android.view.Menu menu) { - } - - /** - * Called when a context menu for the {@code view} is about to be shown. - * Unlike {@link #onCreateOptionsMenu}, this will be called every - * time the context menu is about to be shown and should be populated for - * the view (or item inside the view for {@link AdapterView} subclasses, - * this can be found in the {@code menuInfo})). - *

- * Use {@link #onContextItemSelected(android.view.MenuItem)} to know when an - * item has been selected. - *

- * The default implementation calls up to - * {@link Activity#onCreateContextMenu Activity.onCreateContextMenu}, though - * you can not call this implementation if you don't want that behavior. - *

- * It is not safe to hold onto the context menu after this method returns. - * {@inheritDoc} - */ - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - getActivity().onCreateContextMenu(menu, v, menuInfo); - } - - /** - * Registers a context menu to be shown for the given view (multiple views - * can show the context menu). This method will set the - * {@link OnCreateContextMenuListener} on the view to this fragment, so - * {@link #onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} will be - * called when it is time to show the context menu. - * - * @see #unregisterForContextMenu(View) - * @param view The view that should show a context menu. - */ - public void registerForContextMenu(View view) { - view.setOnCreateContextMenuListener(this); - } - - /** - * Prevents a context menu to be shown for the given view. This method will - * remove the {@link OnCreateContextMenuListener} on the view. - * - * @see #registerForContextMenu(View) - * @param view The view that should stop showing a context menu. - */ - public void unregisterForContextMenu(View view) { - view.setOnCreateContextMenuListener(null); - } - - /** - * This hook is called whenever an item in a context menu is selected. The - * default implementation simply returns false to have the normal processing - * happen (calling the item's Runnable or sending a message to its Handler - * as appropriate). You can use this method for any items for which you - * would like to do processing without those other facilities. - *

- * Use {@link MenuItem#getMenuInfo()} to get extra information set by the - * View that added this menu item. - *

- * Derived classes should call through to the base class for it to perform - * the default menu handling. - * - * @param item The context menu item that was selected. - * @return boolean Return false to allow normal context menu processing to - * proceed, true to consume it here. - */ - public boolean onContextItemSelected(android.view.MenuItem item) { - return false; - } - - /** - * Print the Fragments's state into the given stream. - * - * @param prefix Text to print at the front of each line. - * @param fd The raw file descriptor that the dump is being sent to. - * @param writer The PrintWriter to which you should dump your state. This will be - * closed for you after you return. - * @param args additional arguments to the dump request. - */ - public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { - writer.print(prefix); writer.print("mFragmentId=#"); - writer.print(Integer.toHexString(mFragmentId)); - writer.print(" mContainerId#="); - writer.print(Integer.toHexString(mContainerId)); - writer.print(" mTag="); writer.println(mTag); - writer.print(prefix); writer.print("mState="); writer.print(mState); - writer.print(" mIndex="); writer.print(mIndex); - writer.print(" mWho="); writer.print(mWho); - writer.print(" mBackStackNesting="); writer.println(mBackStackNesting); - writer.print(prefix); writer.print("mAdded="); writer.print(mAdded); - writer.print(" mRemoving="); writer.print(mRemoving); - writer.print(" mResumed="); writer.print(mResumed); - writer.print(" mFromLayout="); writer.print(mFromLayout); - writer.print(" mInLayout="); writer.println(mInLayout); - writer.print(prefix); writer.print("mHidden="); writer.print(mHidden); - writer.print(" mDetached="); writer.print(mDetached); - writer.print(" mRetainInstance="); writer.print(mRetainInstance); - writer.print(" mRetaining="); writer.print(mRetaining); - writer.print(" mHasMenu="); writer.println(mHasMenu); - if (mFragmentManager != null) { - writer.print(prefix); writer.print("mFragmentManager="); - writer.println(mFragmentManager); - } - if (mImmediateActivity != null) { - writer.print(prefix); writer.print("mImmediateActivity="); - writer.println(mImmediateActivity); - } - if (mActivity != null) { - writer.print(prefix); writer.print("mActivity="); - writer.println(mActivity); - } - if (mArguments != null) { - writer.print(prefix); writer.print("mArguments="); writer.println(mArguments); - } - if (mSavedFragmentState != null) { - writer.print(prefix); writer.print("mSavedFragmentState="); - writer.println(mSavedFragmentState); - } - if (mSavedViewState != null) { - writer.print(prefix); writer.print("mSavedViewState="); - writer.println(mSavedViewState); - } - if (mTarget != null) { - writer.print(prefix); writer.print("mTarget="); writer.print(mTarget); - writer.print(" mTargetRequestCode="); - writer.println(mTargetRequestCode); - } - if (mNextAnim != 0) { - writer.print(prefix); writer.print("mNextAnim="); writer.println(mNextAnim); - } - if (mContainer != null) { - writer.print(prefix); writer.print("mContainer="); writer.println(mContainer); - } - if (mView != null) { - writer.print(prefix); writer.print("mView="); writer.println(mView); - } - if (mInnerView != null) { - writer.print(prefix); writer.print("mInnerView="); writer.println(mView); - } - if (mAnimatingAway != null) { - writer.print(prefix); writer.print("mAnimatingAway="); writer.println(mAnimatingAway); - writer.print(prefix); writer.print("mStateAfterAnimating="); - writer.println(mStateAfterAnimating); - } - if (mLoaderManager != null) { - writer.print(prefix); writer.println("Loader Manager:"); - mLoaderManager.dump(prefix + " ", fd, writer, args); - } - } - - void performStart() { - onStart(); - if (mLoaderManager != null) { - mLoaderManager.doReportStart(); - } - } - - void performStop() { - onStop(); - } - - void performReallyStop(boolean retaining) { - if (mLoadersStarted) { - mLoadersStarted = false; - if (!mCheckedForLoaderManager) { - mCheckedForLoaderManager = true; - mLoaderManager = mActivity.getInternalCallbacks().getLoaderManager(mIndex, mLoadersStarted, false); - } - if (mLoaderManager != null) { - if (!retaining) { - mLoaderManager.doStop(); - } else { - mLoaderManager.doRetain(); - } - } - } - } - - void performDestroyView() { - onDestroyView(); - if (mLoaderManager != null) { - mLoaderManager.doReportNextStart(); - } - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentActivity.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentActivity.java deleted file mode 100644 index d3e4b703..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentActivity.java +++ /dev/null @@ -1,1213 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * Copyright (C) 2011 Jake Wharton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.HashMap; -import com.actionbarsherlock.R; -import com.actionbarsherlock.internal.app.ActionBarWrapper; -import com.actionbarsherlock.internal.app.ActionBarImpl; -import com.actionbarsherlock.internal.view.menu.MenuBuilder; -import com.actionbarsherlock.internal.view.menu.MenuInflaterWrapper; -import com.actionbarsherlock.internal.view.menu.MenuItemImpl; -import com.actionbarsherlock.internal.view.menu.MenuItemWrapper; -import com.actionbarsherlock.internal.view.menu.MenuWrapper; -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.content.res.TypedArray; -import android.content.res.Resources.Theme; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Parcelable; -import android.support.v4.view.ActionMode; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuInflater; -import android.support.v4.view.MenuItem; -import android.support.v4.view.Window; -import android.util.AttributeSet; -import android.util.Log; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewGroup.LayoutParams; -import android.widget.FrameLayout; - -/** - * Base class for activities that want to use the support-based ActionBar, - * Fragment, and Loader APIs. - * - *

Known limitations:

- *
    - *
  • When using the <fragment> tag, this implementation can not - * use the parent view's ID as the new fragment's ID. You must explicitly - * specify an ID (or tag) in the <fragment>.

    - *
  • Prior to Honeycomb (3.0), an activity's state was saved before pausing. - * Fragments are a significant amount of new state, and dynamic enough that one - * often wants them to change between pausing and stopping. These classes - * throw an exception if you try to change the fragment state after it has been - * saved, to avoid accidental loss of UI state. However this is too restrictive - * prior to Honeycomb, where the state is saved before pausing. To address this, - * when running on platforms prior to Honeycomb an exception will not be thrown - * if you change fragments between the state save and the activity being stopped. - * This means that is some cases if the activity is restored from its last saved - * state, this may be a snapshot slightly before what the user last saw.

    - *
- */ -public class FragmentActivity extends Activity implements SupportActivity { - private static final String TAG = "FragmentActivity"; - private static final boolean DEBUG = false; - - //The following are used so FragmentMapActivity gets the same resources WITHOUT inlining the values in its jar. - static int R$layout$screen_action_bar_overlay = R.layout.abs__screen_action_bar_overlay; - static int R$layout$screen_action_bar = R.layout.abs__screen_action_bar; - static int R$layout$screen_simple = R.layout.abs__screen_simple; - static int R$id$content = R.id.abs__content; - static int[] R$styleable$SherlockTheme = R.styleable.SherlockTheme; - static int R$styleable$SherlockTheme_windowActionBar = R.styleable.SherlockTheme_windowActionBar; - static int R$styleable$SherlockTheme_windowActionModeOverlay = R.styleable.SherlockTheme_windowActionModeOverlay; - - private static final String FRAGMENTS_TAG = "android:support:fragments"; - - static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; - - static final int MSG_REALLY_STOPPED = 1; - static final int MSG_RESUME_PENDING = 2; - - private static final int WINDOW_FLAG_ACTION_BAR = 1 << Window.FEATURE_ACTION_BAR; - private static final int WINDOW_FLAG_ACTION_BAR_ITEM_TEXT = 1 << Window.FEATURE_ACTION_BAR_ITEM_TEXT; - private static final int WINDOW_FLAG_ACTION_BAR_OVERLAY = 1 << Window.FEATURE_ACTION_BAR_OVERLAY; - private static final int WINDOW_FLAG_ACTION_MODE_OVERLAY = 1 << Window.FEATURE_ACTION_MODE_OVERLAY; - private static final int WINDOW_FLAG_INDETERMINANTE_PROGRESS = 1 << Window.FEATURE_INDETERMINATE_PROGRESS; - - final SupportActivity.InternalCallbacks mInternalCallbacks = new SupportActivity.InternalCallbacks() { - @Override - void invalidateSupportFragmentIndex(int index) { - FragmentActivity.this.invalidateSupportFragmentIndex(index); - } - - @Override - LoaderManagerImpl getLoaderManager(int index, boolean started, boolean create) { - return FragmentActivity.this.getLoaderManager(index, started, create); - } - - @Override - Handler getHandler() { - return mHandler; - } - - @Override - FragmentManagerImpl getFragments() { - return mFragments; - } - - @Override - void ensureSupportActionBarAttached() { - FragmentActivity.this.ensureSupportActionBarAttached(); - } - }; - - final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_REALLY_STOPPED: - if (mStopped) { - doReallyStop(false); - } - break; - case MSG_RESUME_PENDING: - mFragments.dispatchResume(); - mFragments.execPendingActions(); - break; - default: - super.handleMessage(msg); - } - } - }; - final FragmentManagerImpl mFragments = new FragmentManagerImpl(); - - ActionBar mActionBar; - boolean mIsActionBarImplAttached; - long mWindowFlags = 0; - - final MenuBuilder mSupportMenu; - final MenuBuilder.Callback mSupportMenuCallback = new MenuBuilder.Callback() { - @Override - public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { - return FragmentActivity.this.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item); - } - }; - - boolean mCreated; - boolean mResumed; - boolean mStopped; - boolean mReallyStopped; - - boolean mOptionsMenuInvalidated; - boolean mOptionsMenuCreateResult; - - boolean mCheckedForLoaderManager; - boolean mLoadersStarted; - HCSparseArray mAllLoaderManagers; - LoaderManagerImpl mLoaderManager; - - static final class NonConfigurationInstances { - Object activity; - HashMap children; - ArrayList fragments; - HCSparseArray loaders; - } - - static class FragmentTag { - public static final int[] Fragment = { - 0x01010003, 0x010100d0, 0x010100d1 - }; - public static final int Fragment_id = 1; - public static final int Fragment_name = 0; - public static final int Fragment_tag = 2; - } - - - - public FragmentActivity() { - super(); - - if (IS_HONEYCOMB) { - mActionBar = ActionBarWrapper.createFor(this); - mSupportMenu = null; //Everything should be done natively - } else { - mSupportMenu = new MenuBuilder(this); - mSupportMenu.setCallback(mSupportMenuCallback); - } - } - - @Override - public SupportActivity.InternalCallbacks getInternalCallbacks() { - return mInternalCallbacks; - } - - @Override - public Activity asActivity() { - return this; - } - - protected void ensureSupportActionBarAttached() { - if (IS_HONEYCOMB) { - return; - } - if (!mIsActionBarImplAttached) { - if (isChild()) { - //Do not allow an action bar if we have a parent activity - mWindowFlags &= ~WINDOW_FLAG_ACTION_BAR; - } - if ((mWindowFlags & WINDOW_FLAG_ACTION_BAR) == WINDOW_FLAG_ACTION_BAR) { - if ((mWindowFlags & WINDOW_FLAG_ACTION_BAR_OVERLAY) == WINDOW_FLAG_ACTION_BAR_OVERLAY) { - super.setContentView(R.layout.abs__screen_action_bar_overlay); - } else { - super.setContentView(R.layout.abs__screen_action_bar); - } - - mActionBar = new ActionBarImpl(this); - ((ActionBarImpl)mActionBar).init(); - - final boolean textEnabled = ((mWindowFlags & WINDOW_FLAG_ACTION_BAR_ITEM_TEXT) == WINDOW_FLAG_ACTION_BAR_ITEM_TEXT); - mSupportMenu.setShowsActionItemText(textEnabled); - - if ((mWindowFlags & WINDOW_FLAG_INDETERMINANTE_PROGRESS) == WINDOW_FLAG_INDETERMINANTE_PROGRESS) { - ((ActionBarImpl)mActionBar).setProgressBarIndeterminateVisibility(false); - } - - //TODO set other flags - } else { - if ((mWindowFlags & WINDOW_FLAG_INDETERMINANTE_PROGRESS) == WINDOW_FLAG_INDETERMINANTE_PROGRESS) { - super.requestWindowFeature((int)Window.FEATURE_INDETERMINATE_PROGRESS); - } - super.setContentView(R.layout.abs__screen_simple); - } - - invalidateOptionsMenu(); - mIsActionBarImplAttached = true; - } - } - - // ------------------------------------------------------------------------ - // HOOKS INTO ACTIVITY - // ------------------------------------------------------------------------ - - /** - * Enable extended window features. - * - * @param featureId The desired feature as defined in - * {@link android.support.v4.view.Window}. - * @return Returns {@code true} if the requested feature is supported and - * now enabled. - */ - @Override - public boolean requestWindowFeature(long featureId) { - if (!IS_HONEYCOMB) { - switch ((int)featureId) { - case (int)Window.FEATURE_ACTION_BAR: - case (int)Window.FEATURE_ACTION_BAR_ITEM_TEXT: - case (int)Window.FEATURE_ACTION_BAR_OVERLAY: - case (int)Window.FEATURE_ACTION_MODE_OVERLAY: - case (int)Window.FEATURE_INDETERMINATE_PROGRESS: - mWindowFlags |= (1 << featureId); - return true; - } - } - return super.requestWindowFeature((int)featureId); - } - - @Override - public android.view.MenuInflater getMenuInflater() { - if (IS_HONEYCOMB) { - if (DEBUG) Log.d(TAG, "getMenuInflater(): Wrapping native inflater."); - - //Wrap the native inflater so it can unwrap the native menu first - return new MenuInflaterWrapper(this, super.getMenuInflater()); - } - - if (DEBUG) Log.d(TAG, "getMenuInflater(): Returning support inflater."); - - //Use our custom menu inflater - return new MenuInflater(this, super.getMenuInflater()); - } - - @Override - public void setContentView(int layoutResId) { - ensureSupportActionBarAttached(); - if (IS_HONEYCOMB) { - super.setContentView(layoutResId); - } else { - FrameLayout contentView = (FrameLayout)findViewById(R.id.abs__content); - contentView.removeAllViews(); - getLayoutInflater().inflate(layoutResId, contentView, true); - } - } - - @Override - public void setContentView(View view, LayoutParams params) { - ensureSupportActionBarAttached(); - if (IS_HONEYCOMB) { - super.setContentView(view, params); - } else { - FrameLayout contentView = (FrameLayout)findViewById(R.id.abs__content); - contentView.removeAllViews(); - contentView.addView(view, params); - } - } - - @Override - public void setContentView(View view) { - ensureSupportActionBarAttached(); - if (IS_HONEYCOMB) { - super.setContentView(view); - } else { - FrameLayout contentView = (FrameLayout)findViewById(R.id.abs__content); - contentView.removeAllViews(); - contentView.addView(view); - } - } - - @Override - public void setTitle(CharSequence title) { - if (IS_HONEYCOMB || (getSupportActionBar() == null)) { - super.setTitle(title); - } else { - getSupportActionBar().setTitle(title); - } - } - - @Override - public void setTitle(int titleId) { - if (IS_HONEYCOMB || (getSupportActionBar() == null)) { - super.setTitle(titleId); - } else { - getSupportActionBar().setTitle(titleId); - } - } - - /** - * Dispatch incoming result to the correct fragment. - */ - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - int index = requestCode>>16; - if (index != 0) { - index--; - if (mFragments.mActive == null || index < 0 || index >= mFragments.mActive.size()) { - Log.w(TAG, "Activity result fragment index out of range: 0x" - + Integer.toHexString(requestCode)); - return; - } - Fragment frag = mFragments.mActive.get(index); - if (frag == null) { - Log.w(TAG, "Activity result no fragment exists for index: 0x" - + Integer.toHexString(requestCode)); - } else { - frag.onActivityResult(requestCode&0xffff, resultCode, data); - } - return; - } - - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - protected void onApplyThemeResource(Theme theme, int resid, boolean first) { - TypedArray attrs = theme.obtainStyledAttributes(resid, R.styleable.SherlockTheme); - - final boolean actionBar = attrs.getBoolean(R.styleable.SherlockTheme_windowActionBar, false); - mWindowFlags |= actionBar ? WINDOW_FLAG_ACTION_BAR : 0; - - final boolean actionModeOverlay = attrs.getBoolean(R.styleable.SherlockTheme_windowActionModeOverlay, false); - mWindowFlags |= actionModeOverlay ? WINDOW_FLAG_ACTION_MODE_OVERLAY : 0; - - attrs.recycle(); - super.onApplyThemeResource(theme, resid, first); - } - - /** - * Take care of popping the fragment back stack or finishing the activity - * as appropriate. - */ - @Override - public void onBackPressed() { - if (!mFragments.popBackStackImmediate()) { - finish(); - } - } - - /** - * Dispatch configuration change to all fragments. - */ - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - mFragments.dispatchConfigurationChanged(newConfig); - } - - /** - * Perform initialization of all fragments and loaders. - */ - @Override - protected void onCreate(Bundle savedInstanceState) { - mFragments.attachActivity(this); - // Old versions of the platform didn't do this! - if (getLayoutInflater().getFactory() == null) { - getLayoutInflater().setFactory(this); - } - - super.onCreate(savedInstanceState); - - NonConfigurationInstances nc = (NonConfigurationInstances) - getLastNonConfigurationInstance(); - if (nc != null) { - mAllLoaderManagers = nc.loaders; - } - if (savedInstanceState != null) { - Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG); - mFragments.restoreAllState(p, nc != null ? nc.fragments : null); - } - mFragments.dispatchCreate(); - } - - /** - *

Initialize the contents of the Activity's standard options menu. You - * should place your menu items in to menu.

- * - *

The default implementation populates the menu with standard system - * menu items. These are placed in the {@link Menu.CATEGORY_SYSTEM} group - * so that they will be correctly ordered with application-defined menu - * items. Deriving classes should always call through to the base - * implementation.

- * - *

You can safely hold on to menu (and any items created from it), - * making modifications to it as desired, until the next time - * {@code onCreateOptionsMenu()} is called.

- * - *

When you add items to the menu, you can implement the Activity's - * {@link #onOptionsItemSelected(MenuItem)} method to handle them - * there.

- * - * @param menu The options menu in which you place your items. - * @return You must return true for the menu to be displayed; if you return - * false it will not be shown. - */ - @Override - public boolean onCreateOptionsMenu(Menu menu) { - if (DEBUG) Log.d(TAG, "onCreateOptionsMenu(Menu): Returning " + menu.hasVisibleItems()); - return menu.hasVisibleItems(); - } - - @Override - public final boolean onCreateOptionsMenu(android.view.Menu menu) { - // Prior to Honeycomb, the framework can't invalidate the options - // menu, so we must always say we have one in case the app later - // invalidates it and needs to have it shown. - boolean result = true; - - if (IS_HONEYCOMB) { - if (DEBUG) Log.d(TAG, "onCreateOptionsMenu(android.view.Menu): Calling support method with wrapped native menu."); - MenuWrapper wrapped = new MenuWrapper(menu); - result = onCreateOptionsMenu(wrapped); - result |= mFragments.dispatchCreateOptionsMenu(wrapped, getMenuInflater()); - } - - if (DEBUG) Log.d(TAG, "onCreateOptionsMenu(android.view.Menu): Returning " + result); - return result; - } - - /** - * Add support for inflating the <fragment> tag. - */ - @Override - public View onCreateView(String name, Context context, AttributeSet attrs) { - if (!"fragment".equals(name)) { - return super.onCreateView(name, context, attrs); - } - - String fname = attrs.getAttributeValue(null, "class"); - TypedArray a = context.obtainStyledAttributes(attrs, FragmentTag.Fragment); - if (fname == null) { - fname = a.getString(FragmentTag.Fragment_name); - } - int id = a.getResourceId(FragmentTag.Fragment_id, View.NO_ID); - String tag = a.getString(FragmentTag.Fragment_tag); - a.recycle(); - - View parent = null; // NOTE: no way to get parent pre-Honeycomb. - int containerId = parent != null ? parent.getId() : 0; - if (containerId == View.NO_ID && id == View.NO_ID && tag == null) { - throw new IllegalArgumentException(attrs.getPositionDescription() - + ": Must specify unique android:id, android:tag, or have a parent with an id for " + fname); - } - - // If we restored from a previous state, we may already have - // instantiated this fragment from the state and should use - // that instance instead of making a new one. - Fragment fragment = id != View.NO_ID ? mFragments.findFragmentById(id) : null; - if (fragment == null && tag != null) { - fragment = mFragments.findFragmentByTag(tag); - } - if (fragment == null && containerId != View.NO_ID) { - fragment = mFragments.findFragmentById(containerId); - } - - if (FragmentManagerImpl.DEBUG) Log.v(TAG, "onCreateView: id=0x" - + Integer.toHexString(id) + " fname=" + fname - + " existing=" + fragment); - if (fragment == null) { - fragment = Fragment.instantiate(this, fname); - fragment.mFromLayout = true; - fragment.mFragmentId = id != 0 ? id : containerId; - fragment.mContainerId = containerId; - fragment.mTag = tag; - fragment.mInLayout = true; - fragment.mImmediateActivity = this; - fragment.mFragmentManager = mFragments; - fragment.onInflate(this, attrs, fragment.mSavedFragmentState); - mFragments.addFragment(fragment, true); - - } else if (fragment.mInLayout) { - // A fragment already exists and it is not one we restored from - // previous state. - throw new IllegalArgumentException(attrs.getPositionDescription() - + ": Duplicate id 0x" + Integer.toHexString(id) - + ", tag " + tag + ", or parent id 0x" + Integer.toHexString(containerId) - + " with another fragment for " + fname); - } else { - // This fragment was retained from a previous instance; get it - // going now. - fragment.mInLayout = true; - fragment.mImmediateActivity = this; - // If this fragment is newly instantiated (either right now, or - // from last saved state), then give it the attributes to - // initialize itself. - if (!fragment.mRetaining) { - fragment.onInflate(this, attrs, fragment.mSavedFragmentState); - } - mFragments.moveToState(fragment); - } - - if (fragment.mView == null) { - throw new IllegalStateException("Fragment " + fname - + " did not create a view."); - } - if (id != 0) { - fragment.mView.setId(id); - } - if (fragment.mView.getTag() == null) { - fragment.mView.setTag(tag); - } - return fragment.mView; - } - - @Override - public void invalidateOptionsMenu() { - if (DEBUG) Log.d(TAG, "supportInvalidateOptionsMenu(): Invalidating menu."); - - if (IS_HONEYCOMB) { - HoneycombInvalidateOptionsMenu.invoke(this); - } else { - mSupportMenu.clear(); - - mOptionsMenuCreateResult = onCreateOptionsMenu(mSupportMenu); - mOptionsMenuCreateResult |= mFragments.dispatchCreateOptionsMenu(mSupportMenu, getMenuInflater()); - - if (getSupportActionBar() != null) { - //Since we now know we are using a custom action bar, perform the - //inflation callback to allow it to display any items it wants. - //Any items that were displayed will have a boolean toggled so that we - //do not display them on the options menu. - ((ActionBarImpl)mActionBar).onMenuInflated(mSupportMenu); - } - - // Whoops, older platform... we'll use a hack, to manually rebuild - // the options menu the next time it is prepared. - mOptionsMenuInvalidated = true; - } - } - - private static final class HoneycombInvalidateOptionsMenu { - static void invoke(Activity activity) { - activity.getWindow().invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL); - } - } - - /** - * Destroy all fragments and loaders. - */ - @Override - protected void onDestroy() { - super.onDestroy(); - - doReallyStop(false); - - mFragments.dispatchDestroy(); - if (mLoaderManager != null) { - mLoaderManager.doDestroy(); - } - } - - /** - * Take care of calling onBackPressed() for pre-Eclair platforms. - */ - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (android.os.Build.VERSION.SDK_INT < 5 /* ECLAIR */ - && keyCode == KeyEvent.KEYCODE_BACK - && event.getRepeatCount() == 0) { - // Take care of calling this method on earlier versions of - // the platform where it doesn't exist. - onBackPressed(); - return true; - } - - return super.onKeyDown(keyCode, event); - } - - /** - * Dispatch onLowMemory() to all fragments. - */ - @Override - public void onLowMemory() { - super.onLowMemory(); - mFragments.dispatchLowMemory(); - } - - /** - * Dispatch context and options menu to fragments. - */ - @Override - public final boolean onMenuItemSelected(int featureId, android.view.MenuItem item) { - if (super.onMenuItemSelected(featureId, item)) { - return true; - } - - switch (featureId) { - case Window.FEATURE_OPTIONS_PANEL: - return mFragments.dispatchOptionsItemSelected(new MenuItemWrapper(item)); - - case Window.FEATURE_CONTEXT_MENU: - return mFragments.dispatchContextItemSelected(new MenuItemWrapper(item)); - - default: - return false; - } - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - if (onOptionsItemSelected(item)) { - return true; - } - - switch (featureId) { - case Window.FEATURE_OPTIONS_PANEL: - return mFragments.dispatchOptionsItemSelected(item); - - case Window.FEATURE_CONTEXT_MENU: - return mFragments.dispatchContextItemSelected(item); - - default: - return false; - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - return super.onOptionsItemSelected(item); - } - - @Override - public final boolean onOptionsItemSelected(android.view.MenuItem item) { - return onOptionsItemSelected(new MenuItemWrapper(item)); - } - - /** - * Call onOptionsMenuClosed() on fragments. - */ - @Override - public void onPanelClosed(int featureId, android.view.Menu menu) { - switch (featureId) { - case Window.FEATURE_OPTIONS_PANEL: - mFragments.dispatchOptionsMenuClosed(menu); - - if (!IS_HONEYCOMB && (getSupportActionBar() != null)) { - if (DEBUG) Log.d(TAG, "onPanelClosed(int, android.view.Menu): Dispatch menu visibility false to custom action bar."); - ((ActionBarImpl)mActionBar).onMenuVisibilityChanged(false); - } - break; - } - super.onPanelClosed(featureId, menu); - } - - /** - * Dispatch onPause() to fragments. - */ - @Override - protected void onPause() { - super.onPause(); - mResumed = false; - if (mHandler.hasMessages(MSG_RESUME_PENDING)) { - mHandler.removeMessages(MSG_RESUME_PENDING); - mFragments.dispatchResume(); - } - mFragments.dispatchPause(); - } - - /** - * Dispatch onResume() to fragments. - */ - @Override - protected void onResume() { - super.onResume(); - mHandler.sendEmptyMessage(MSG_RESUME_PENDING); - mResumed = true; - mFragments.execPendingActions(); - } - - /** - * Dispatch onResume() to fragments. - */ - @Override - protected void onPostResume() { - super.onPostResume(); - mHandler.removeMessages(MSG_RESUME_PENDING); - mFragments.dispatchResume(); - mFragments.execPendingActions(); - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - boolean result = menu.hasVisibleItems(); - if (DEBUG) Log.d(TAG, "onPrepareOptionsMenu(Menu): Returning " + result); - return result; - } - - @Override - public final boolean onPrepareOptionsMenu(android.view.Menu menu) { - boolean result = super.onPrepareOptionsMenu(menu); - - if (!IS_HONEYCOMB) { - if (DEBUG) { - Log.d(TAG, "onPrepareOptionsMenu(android.view.Menu): mOptionsMenuCreateResult = " + mOptionsMenuCreateResult); - Log.d(TAG, "onPrepareOptionsMenu(android.view.Menu): mOptionsMenuInvalidated = " + mOptionsMenuInvalidated); - } - - boolean prepareResult = true; - if (mOptionsMenuCreateResult) { - if (DEBUG) Log.d(TAG, "onPrepareOptionsMenu(android.view.Menu): Calling support method with custom menu."); - prepareResult = onPrepareOptionsMenu(mSupportMenu); - if (DEBUG) Log.d(TAG, "onPrepareOptionsMenu(android.view.Menu): Support method result returned " + prepareResult); - if (prepareResult) { - if (DEBUG) Log.d(TAG, "onPrepareOptionsMenu(android.view.Menu): Dispatching fragment method with custom menu."); - mFragments.dispatchPrepareOptionsMenu(mSupportMenu); - } - } - - if (mOptionsMenuInvalidated) { - if (DEBUG) Log.d(TAG, "onPrepareOptionsMenu(android.view.Menu): Clearing existing options menu."); - menu.clear(); - mOptionsMenuInvalidated = false; - - if (mOptionsMenuCreateResult && prepareResult) { - if (DEBUG) Log.d(TAG, "onPrepareOptionsMenu(android.view.Menu): Adding any action items that are not displayed on the action bar."); - //Only add items that have not already been added to our custom - //action bar implementation - for (MenuItemImpl item : mSupportMenu.getItems()) { - if (!item.isShownOnActionBar()) { - item.addTo(menu); - } - } - } - } - - if (mOptionsMenuCreateResult && prepareResult && menu.hasVisibleItems()) { - if (getSupportActionBar() != null) { - if (DEBUG) Log.d(TAG, "onPrepareOptionsMenu(android.view.Menu): Dispatch menu visibility true to custom action bar."); - ((ActionBarImpl)mActionBar).onMenuVisibilityChanged(true); - } - result = true; - } - } else { - if (DEBUG) Log.d(TAG, "onPrepareOptionsMenu(android.view.Menu): Calling support method with wrapped native menu."); - final MenuWrapper wrappedMenu = new MenuWrapper(menu); - result = onPrepareOptionsMenu(wrappedMenu); - if (result) { - if (DEBUG) Log.d(TAG, "onPrepareOptionsMenu(android.view.Menu): Dispatching fragment method with wrapped native menu."); - mFragments.dispatchPrepareOptionsMenu(wrappedMenu); - } - } - - if (DEBUG) Log.d(TAG, "onPrepareOptionsMenu(android.view.Menu): Returning " + result); - return result; - } - - /** - * Cause this Activity to be recreated with a new instance. This results in - * essentially the same flow as when the Activity is created due to a - * configuration change -- the current instance will go through its - * lifecycle to onDestroy() and a new instance then created after it. - */ - @Override - public void recreate() { - //This SUCKS! Figure out a way to call the super method and support Android 1.6 - /* - if (IS_HONEYCOMB) { - super.recreate(); - } else { - */ - final Intent intent = getIntent(); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - - startActivity(intent); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) { - OverridePendingTransition.invoke(this); - } - - finish(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) { - OverridePendingTransition.invoke(this); - } - /* - } - */ - } - - private static final class OverridePendingTransition { - static void invoke(Activity activity) { - activity.overridePendingTransition(0, 0); - } - } - - /** - * Retain all appropriate fragment and loader state. You can NOT - * override this yourself! - */ - @Override - public final Object onRetainNonConfigurationInstance() { - if (mStopped) { - doReallyStop(true); - } - - ArrayList fragments = mFragments.retainNonConfig(); - boolean retainLoaders = false; - if (mAllLoaderManagers != null) { - // prune out any loader managers that were already stopped and so - // have nothing useful to retain. - for (int i=mAllLoaderManagers.size()-1; i>=0; i--) { - LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i); - if (lm.mRetaining) { - retainLoaders = true; - } else { - lm.doDestroy(); - mAllLoaderManagers.removeAt(i); - } - } - } - if (fragments == null && !retainLoaders) { - return null; - } - - NonConfigurationInstances nci = new NonConfigurationInstances(); - nci.activity = null; - nci.children = null; - nci.fragments = fragments; - nci.loaders = mAllLoaderManagers; - return nci; - } - - /** - * Save all appropriate fragment state. - */ - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - Parcelable p = mFragments.saveAllState(); - if (p != null) { - outState.putParcelable(FRAGMENTS_TAG, p); - } - } - - /** - * Dispatch onStart() to all fragments. Ensure any created loaders are - * now started. - */ - @Override - protected void onStart() { - super.onStart(); - - mStopped = false; - mHandler.removeMessages(MSG_REALLY_STOPPED); - - if (!mCreated) { - mCreated = true; - ensureSupportActionBarAttached(); //Needed for retained fragments - mFragments.dispatchActivityCreated(); - } - - mFragments.noteStateNotSaved(); - mFragments.execPendingActions(); - - if (!mLoadersStarted) { - mLoadersStarted = true; - if (mLoaderManager != null) { - mLoaderManager.doStart(); - } else if (!mCheckedForLoaderManager) { - mLoaderManager = getLoaderManager(-1, mLoadersStarted, false); - } - mCheckedForLoaderManager = true; - } - // NOTE: HC onStart goes here. - - mFragments.dispatchStart(); - if (mAllLoaderManagers != null) { - for (int i=mAllLoaderManagers.size()-1; i>=0; i--) { - LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i); - lm.finishRetain(); - lm.doReportStart(); - } - } - } - - /** - * Dispatch onStop() to all fragments. Ensure all loaders are stopped. - */ - @Override - protected void onStop() { - super.onStop(); - - mStopped = true; - mHandler.sendEmptyMessage(MSG_REALLY_STOPPED); - - mFragments.dispatchStop(); - } - - /** - *

Sets the visibility of the indeterminate progress bar in the - * title.

- * - *

In order for the progress bar to be shown, the feature must be - * requested via {@link #requestWindowFeature(long)}.

- * - *

This method must be used instead of - * {@link #setProgressBarIndeterminateVisibility(boolean)} for - * ActionBarSherlock. Pass {@link Boolean.TRUE} or - * {@link Boolean.FALSE} to ensure the appropriate one is called.

- * - * @param visible Whether to show the progress bars in the title. - */ - @Override - public void setProgressBarIndeterminateVisibility(Boolean visible) { - if (IS_HONEYCOMB || (getSupportActionBar() == null)) { - super.setProgressBarIndeterminateVisibility(visible); - } else if ((mWindowFlags & WINDOW_FLAG_INDETERMINANTE_PROGRESS) == WINDOW_FLAG_INDETERMINANTE_PROGRESS) { - ((ActionBarImpl)mActionBar).setProgressBarIndeterminateVisibility(visible); - } - } - - // ------------------------------------------------------------------------ - // NEW METHODS - // ------------------------------------------------------------------------ - - /** - * Print the Activity's state into the given stream. This gets invoked if - * you run "adb shell dumpsys activity ". - * - * @param prefix Desired prefix to prepend at each line of output. - * @param fd The raw file descriptor that the dump is being sent to. - * @param writer The PrintWriter to which you should dump your state. This will be - * closed for you after you return. - * @param args additional arguments to the dump request. - */ - @Override - public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { - if (IS_HONEYCOMB) { - //This can only work if we can call the super-class impl. :/ - //ActivityCompatHoneycomb.dump(this, prefix, fd, writer, args); - } - writer.print(prefix); writer.print("Local FragmentActivity "); - writer.print(Integer.toHexString(System.identityHashCode(this))); - writer.println(" State:"); - String innerPrefix = prefix + " "; - writer.print(innerPrefix); writer.print("mCreated="); - writer.print(mCreated); writer.print("mResumed="); - writer.print(mResumed); writer.print(" mStopped="); - writer.print(mStopped); writer.print(" mReallyStopped="); - writer.println(mReallyStopped); - writer.print(innerPrefix); writer.print("mLoadersStarted="); - writer.println(mLoadersStarted); - if (mLoaderManager != null) { - writer.print(prefix); writer.print("Loader Manager "); - writer.print(Integer.toHexString(System.identityHashCode(mLoaderManager))); - writer.println(":"); - mLoaderManager.dump(prefix + " ", fd, writer, args); - } - mFragments.dump(prefix, fd, writer, args); - } - - void doReallyStop(boolean retaining) { - if (!mReallyStopped) { - mReallyStopped = true; - mHandler.removeMessages(MSG_REALLY_STOPPED); - onReallyStop(retaining); - } - } - - /** - * Pre-HC, we didn't have a way to determine whether an activity was - * being stopped for a config change or not until we saw - * onRetainNonConfigurationInstance() called after onStop(). However - * we need to know this, to know whether to retain fragments. This will - * tell us what we need to know. - */ - void onReallyStop(boolean retaining) { - if (mLoadersStarted) { - mLoadersStarted = false; - if (mLoaderManager != null) { - if (!retaining) { - mLoaderManager.doStop(); - } else { - mLoaderManager.doRetain(); - } - } - } - - mFragments.dispatchReallyStop(retaining); - } - - // ------------------------------------------------------------------------ - // ACTION BAR AND ACTION MODE SUPPORT - // ------------------------------------------------------------------------ - - /** - * Retrieve a reference to this activity's action bar handler. - * - * @return The handler for the appropriate action bar, or null. - */ - @Override - public ActionBar getSupportActionBar() { - return (mActionBar != null) ? mActionBar.getPublicInstance() : null; - } - - /** - * Notifies the activity that an action mode has finished. Activity - * subclasses overriding this method should call the superclass - * implementation. - * - * @param mode The action mode that just finished. - */ - @Override - public void onActionModeFinished(ActionMode mode) { - } - - /** - * Notifies the Activity that an action mode has been started. Activity - * subclasses overriding this method should call the superclass - * implementation. - * - * @param mode The new action mode. - */ - @Override - public void onActionModeStarted(ActionMode mode) { - } - - /** - *

Give the Activity a chance to control the UI for an action mode - * requested by the system.

- * - *

Note: If you are looking for a notification callback that an action - * mode has been started for this activity, see - * {@link #onActionModeStarted(ActionMode)}.

- * - * @param callback The callback that should control the new action mode - * @return The new action mode, or null if the activity does not want to - * provide special handling for this action mode. (It will be handled by the - * system.) - */ - @Override - public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) { - return null; - } - - /** - * Start an action mode. - * - * @param callback Callback that will manage lifecycle events for this - * context mode - * @return The ContextMode that was started, or null if it was cancelled - * @see android.support.v4.view.ActionMode - */ - @Override - public final ActionMode startActionMode(final ActionMode.Callback callback) { - //Give the activity override a chance to handle the action mode - ActionMode actionMode = onWindowStartingActionMode(callback); - - if (actionMode == null) { - //If the activity did not handle, send to action bar for platform- - //specific implementation - actionMode = mActionBar.startActionMode(callback); - } - if (actionMode != null) { - //Send the activity callback that our action mode was started - onActionModeStarted(actionMode); - } - - //Return to the caller - return actionMode; - } - - // ------------------------------------------------------------------------ - // FRAGMENT SUPPORT - // ------------------------------------------------------------------------ - - /** - * Called when a fragment is attached to the activity. - */ - @Override - public void onAttachFragment(Fragment fragment) { - } - - /** - * Return the FragmentManager for interacting with fragments associated - * with this activity. - */ - @Override - public FragmentManager getSupportFragmentManager() { - return mFragments; - } - - /** - * Modifies the standard behavior to allow results to be delivered to fragments. - * This imposes a restriction that requestCode be <= 0xffff. - */ - @Override - public void startActivityForResult(Intent intent, int requestCode) { - if (requestCode != -1 && (requestCode&0xffff0000) != 0) { - throw new IllegalArgumentException("Can only use lower 16 bits for requestCode"); - } - super.startActivityForResult(intent, requestCode); - } - - /** - * Called by Fragment.startActivityForResult() to implement its behavior. - */ - @Override - public void startActivityFromFragment(Fragment fragment, Intent intent, - int requestCode) { - if (requestCode == -1) { - super.startActivityForResult(intent, -1); - return; - } - if ((requestCode&0xffff0000) != 0) { - throw new IllegalArgumentException("Can only use lower 16 bits for requestCode"); - } - super.startActivityForResult(intent, ((fragment.mIndex+1)<<16) + (requestCode&0xffff)); - } - - void invalidateSupportFragmentIndex(int index) { - //Log.v(TAG, "invalidateFragmentIndex: index=" + index); - if (mAllLoaderManagers != null) { - LoaderManagerImpl lm = mAllLoaderManagers.get(index); - if (lm != null) { - lm.doDestroy(); - } - mAllLoaderManagers.remove(index); - } - } - - // ------------------------------------------------------------------------ - // LOADER SUPPORT - // ------------------------------------------------------------------------ - - /** - * Return the LoaderManager for this fragment, creating it if needed. - */ - @Override - public LoaderManager getSupportLoaderManager() { - if (mLoaderManager != null) { - return mLoaderManager; - } - mCheckedForLoaderManager = true; - mLoaderManager = getLoaderManager(-1, mLoadersStarted, true); - return mLoaderManager; - } - - LoaderManagerImpl getLoaderManager(int index, boolean started, boolean create) { - if (mAllLoaderManagers == null) { - mAllLoaderManagers = new HCSparseArray(); - } - LoaderManagerImpl lm = mAllLoaderManagers.get(index); - if (lm == null) { - if (create) { - lm = new LoaderManagerImpl(this, started); - mAllLoaderManagers.put(index, lm); - } - } else { - lm.updateActivity(this); - } - return lm; - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentManager.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentManager.java deleted file mode 100644 index dd3c736b..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentManager.java +++ /dev/null @@ -1,1923 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -import android.content.Context; -import android.content.res.Configuration; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Parcel; -import android.os.Parcelable; -import android.support.v4.util.DebugUtils; -import android.support.v4.util.LogWriter; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuItem; -import android.util.Log; -import android.util.SparseArray; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.view.animation.AnimationSet; -import android.view.animation.AnimationUtils; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; -import android.view.animation.ScaleAnimation; -import android.view.animation.Animation.AnimationListener; -import android.view.MenuInflater; -import android.view.View; -import android.view.ViewGroup; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Arrays; - -/** - * Static library support version of the framework's {@link android.app.FragmentManager}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - * - *

Your activity must derive from {@link FragmentActivity} to use this. - */ -public abstract class FragmentManager { - /** - * Representation of an entry on the fragment back stack, as created - * with {@link FragmentTransaction#addToBackStack(String) - * FragmentTransaction.addToBackStack()}. Entries can later be - * retrieved with {@link FragmentManager#getBackStackEntryAt(int) - * FragmentManager.getBackStackEntry()}. - * - *

Note that you should never hold on to a BackStackEntry object; - * the identifier as returned by {@link #getId} is the only thing that - * will be persisted across activity instances. - */ - public interface BackStackEntry { - /** - * Return the unique identifier for the entry. This is the only - * representation of the entry that will persist across activity - * instances. - */ - public int getId(); - - /** - * Return the full bread crumb title resource identifier for the entry, - * or 0 if it does not have one. - */ - public int getBreadCrumbTitleRes(); - - /** - * Return the short bread crumb title resource identifier for the entry, - * or 0 if it does not have one. - */ - public int getBreadCrumbShortTitleRes(); - - /** - * Return the full bread crumb title for the entry, or null if it - * does not have one. - */ - public CharSequence getBreadCrumbTitle(); - - /** - * Return the short bread crumb title for the entry, or null if it - * does not have one. - */ - public CharSequence getBreadCrumbShortTitle(); - } - - /** - * Interface to watch for changes to the back stack. - */ - public interface OnBackStackChangedListener { - /** - * Called whenever the contents of the back stack change. - */ - public void onBackStackChanged(); - } - - /** - * Start a series of edit operations on the Fragments associated with - * this FragmentManager. - * - *

Note: A fragment transaction can only be created/committed prior - * to an activity saving its state. If you try to commit a transaction - * after {@link FragmentActivity#onSaveInstanceState FragmentActivity.onSaveInstanceState()} - * (and prior to a following {@link FragmentActivity#onStart FragmentActivity.onStart} - * or {@link FragmentActivity#onResume FragmentActivity.onResume()}, you will get an error. - * This is because the framework takes care of saving your current fragments - * in the state, and if changes are made after the state is saved then they - * will be lost.

- */ - public abstract FragmentTransaction beginTransaction(); - - /** @hide -- remove once prebuilts are in. */ - @Deprecated - public FragmentTransaction openTransaction() { - return beginTransaction(); - } - - /** - * After a {@link FragmentTransaction} is committed with - * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it - * is scheduled to be executed asynchronously on the process's main thread. - * If you want to immediately executing any such pending operations, you - * can call this function (only from the main thread) to do so. Note that - * all callbacks and other related behavior will be done from within this - * call, so be careful about where this is called from. - * - * @return Returns true if there were any pending transactions to be - * executed. - */ - public abstract boolean executePendingTransactions(); - - /** - * Finds a fragment that was identified by the given id either when inflated - * from XML or as the container ID when added in a transaction. This first - * searches through fragments that are currently added to the manager's - * activity; if no such fragment is found, then all fragments currently - * on the back stack associated with this ID are searched. - * @return The fragment if found or null otherwise. - */ - public abstract Fragment findFragmentById(int id); - - /** - * Finds a fragment that was identified by the given tag either when inflated - * from XML or as supplied when added in a transaction. This first - * searches through fragments that are currently added to the manager's - * activity; if no such fragment is found, then all fragments currently - * on the back stack are searched. - * @return The fragment if found or null otherwise. - */ - public abstract Fragment findFragmentByTag(String tag); - - /** - * Flag for {@link #popBackStack(String, int)} - * and {@link #popBackStack(int, int)}: If set, and the name or ID of - * a back stack entry has been supplied, then all matching entries will - * be consumed until one that doesn't match is found or the bottom of - * the stack is reached. Otherwise, all entries up to but not including that entry - * will be removed. - */ - public static final int POP_BACK_STACK_INCLUSIVE = 1<<0; - - /** - * Pop the top state off the back stack. Returns true if there was one - * to pop, else false. This function is asynchronous -- it enqueues the - * request to pop, but the action will not be performed until the application - * returns to its event loop. - */ - public abstract void popBackStack(); - - /** - * Like {@link #popBackStack()}, but performs the operation immediately - * inside of the call. This is like calling {@link #executePendingTransactions()} - * afterwards. - * @return Returns true if there was something popped, else false. - */ - public abstract boolean popBackStackImmediate(); - - /** - * Pop the last fragment transition from the manager's fragment - * back stack. If there is nothing to pop, false is returned. - * This function is asynchronous -- it enqueues the - * request to pop, but the action will not be performed until the application - * returns to its event loop. - * - * @param name If non-null, this is the name of a previous back state - * to look for; if found, all states up to that state will be popped. The - * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether - * the named state itself is popped. If null, only the top state is popped. - * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}. - */ - public abstract void popBackStack(String name, int flags); - - /** - * Like {@link #popBackStack(String, int)}, but performs the operation immediately - * inside of the call. This is like calling {@link #executePendingTransactions()} - * afterwards. - * @return Returns true if there was something popped, else false. - */ - public abstract boolean popBackStackImmediate(String name, int flags); - - /** - * Pop all back stack states up to the one with the given identifier. - * This function is asynchronous -- it enqueues the - * request to pop, but the action will not be performed until the application - * returns to its event loop. - * - * @param id Identifier of the stated to be popped. If no identifier exists, - * false is returned. - * The identifier is the number returned by - * {@link FragmentTransaction#commit() FragmentTransaction.commit()}. The - * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether - * the named state itself is popped. - * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}. - */ - public abstract void popBackStack(int id, int flags); - - /** - * Like {@link #popBackStack(int, int)}, but performs the operation immediately - * inside of the call. This is like calling {@link #executePendingTransactions()} - * afterwards. - * @return Returns true if there was something popped, else false. - */ - public abstract boolean popBackStackImmediate(int id, int flags); - - /** - * Return the number of entries currently in the back stack. - */ - public abstract int getBackStackEntryCount(); - - /** - * Return the BackStackEntry at index index in the back stack; - * entries start index 0 being the bottom of the stack. - */ - public abstract BackStackEntry getBackStackEntryAt(int index); - - /** - * Add a new listener for changes to the fragment back stack. - */ - public abstract void addOnBackStackChangedListener(OnBackStackChangedListener listener); - - /** - * Remove a listener that was previously added with - * {@link #addOnBackStackChangedListener(OnBackStackChangedListener)}. - */ - public abstract void removeOnBackStackChangedListener(OnBackStackChangedListener listener); - - /** - * Put a reference to a fragment in a Bundle. This Bundle can be - * persisted as saved state, and when later restoring - * {@link #getFragment(Bundle, String)} will return the current - * instance of the same fragment. - * - * @param bundle The bundle in which to put the fragment reference. - * @param key The name of the entry in the bundle. - * @param fragment The Fragment whose reference is to be stored. - */ - public abstract void putFragment(Bundle bundle, String key, Fragment fragment); - - /** - * Retrieve the current Fragment instance for a reference previously - * placed with {@link #putFragment(Bundle, String, Fragment)}. - * - * @param bundle The bundle from which to retrieve the fragment reference. - * @param key The name of the entry in the bundle. - * @return Returns the current Fragment instance that is associated with - * the given reference. - */ - public abstract Fragment getFragment(Bundle bundle, String key); - - /** - * Save the current instance state of the given Fragment. This can be - * used later when creating a new instance of the Fragment and adding - * it to the fragment manager, to have it create itself to match the - * current state returned here. Note that there are limits on how - * this can be used: - * - *
    - *
  • The Fragment must currently be attached to the FragmentManager. - *
  • A new Fragment created using this saved state must be the same class - * type as the Fragment it was created from. - *
  • The saved state can not contain dependencies on other fragments -- - * that is it can't use {@link #putFragment(Bundle, String, Fragment)} to - * store a fragment reference because that reference may not be valid when - * this saved state is later used. Likewise the Fragment's target and - * result code are not included in this state. - *
- * - * @param f The Fragment whose state is to be saved. - * @return The generated state. This will be null if there was no - * interesting state created by the fragment. - */ - public abstract Fragment.SavedState saveFragmentInstanceState(Fragment f); - - /** - * Print the FragmentManager's state into the given stream. - * - * @param prefix Text to print at the front of each line. - * @param fd The raw file descriptor that the dump is being sent to. - * @param writer A PrintWriter to which the dump is to be set. - * @param args Additional arguments to the dump request. - */ - public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args); - - /** - * Control whether the framework's internal fragment manager debugging - * logs are turned on. If enabled, you will see output in logcat as - * the framework performs fragment operations. - */ - public static void enableDebugLogging(boolean enabled) { - FragmentManagerImpl.DEBUG = enabled; - } -} - -final class FragmentManagerState implements Parcelable { - FragmentState[] mActive; - int[] mAdded; - BackStackState[] mBackStack; - - public FragmentManagerState() { - } - - public FragmentManagerState(Parcel in) { - mActive = in.createTypedArray(FragmentState.CREATOR); - mAdded = in.createIntArray(); - mBackStack = in.createTypedArray(BackStackState.CREATOR); - } - - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - dest.writeTypedArray(mActive, flags); - dest.writeIntArray(mAdded); - dest.writeTypedArray(mBackStack, flags); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public FragmentManagerState createFromParcel(Parcel in) { - return new FragmentManagerState(in); - } - - public FragmentManagerState[] newArray(int size) { - return new FragmentManagerState[size]; - } - }; -} - -/** - * Container for fragments associated with an activity. - */ -final class FragmentManagerImpl extends FragmentManager { - static boolean DEBUG = false; - static final String TAG = "FragmentManager"; - - static final boolean HONEYCOMB = android.os.Build.VERSION.SDK_INT >= 11; - - static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state"; - static final String TARGET_STATE_TAG = "android:target_state"; - static final String VIEW_STATE_TAG = "android:view_state"; - - ArrayList mPendingActions; - Runnable[] mTmpActions; - boolean mExecutingActions; - - ArrayList mActive; - ArrayList mAdded; - ArrayList mAvailIndices; - ArrayList mBackStack; - ArrayList mCreatedMenus; - - // Must be accessed while locked. - ArrayList mBackStackIndices; - ArrayList mAvailBackStackIndices; - - ArrayList mBackStackChangeListeners; - - int mCurState = Fragment.INITIALIZING; - SupportActivity mActivity; - - boolean mNeedMenuInvalidate; - boolean mStateSaved; - boolean mDestroyed; - String mNoTransactionsBecause; - - // Temporary vars for state save and restore. - Bundle mStateBundle = null; - SparseArray mStateArray = null; - - Runnable mExecCommit = new Runnable() { - @Override - public void run() { - execPendingActions(); - } - }; - - @Override - public FragmentTransaction beginTransaction() { - return new BackStackRecord(this); - } - - @Override - public boolean executePendingTransactions() { - return execPendingActions(); - } - - @Override - public void popBackStack() { - enqueueAction(new Runnable() { - @Override public void run() { - popBackStackState(mActivity.getInternalCallbacks().getHandler(), null, -1, 0); - } - }, false); - } - - @Override - public boolean popBackStackImmediate() { - checkStateLoss(); - executePendingTransactions(); - return popBackStackState(mActivity.getInternalCallbacks().getHandler(), null, -1, 0); - } - - @Override - public void popBackStack(final String name, final int flags) { - enqueueAction(new Runnable() { - @Override public void run() { - popBackStackState(mActivity.getInternalCallbacks().getHandler(), name, -1, flags); - } - }, false); - } - - @Override - public boolean popBackStackImmediate(String name, int flags) { - checkStateLoss(); - executePendingTransactions(); - return popBackStackState(mActivity.getInternalCallbacks().getHandler(), name, -1, flags); - } - - @Override - public void popBackStack(final int id, final int flags) { - if (id < 0) { - throw new IllegalArgumentException("Bad id: " + id); - } - enqueueAction(new Runnable() { - @Override public void run() { - popBackStackState(mActivity.getInternalCallbacks().getHandler(), null, id, flags); - } - }, false); - } - - @Override - public boolean popBackStackImmediate(int id, int flags) { - checkStateLoss(); - executePendingTransactions(); - if (id < 0) { - throw new IllegalArgumentException("Bad id: " + id); - } - return popBackStackState(mActivity.getInternalCallbacks().getHandler(), null, id, flags); - } - - @Override - public int getBackStackEntryCount() { - return mBackStack != null ? mBackStack.size() : 0; - } - - @Override - public BackStackEntry getBackStackEntryAt(int index) { - return mBackStack.get(index); - } - - @Override - public void addOnBackStackChangedListener(OnBackStackChangedListener listener) { - if (mBackStackChangeListeners == null) { - mBackStackChangeListeners = new ArrayList(); - } - mBackStackChangeListeners.add(listener); - } - - @Override - public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) { - if (mBackStackChangeListeners != null) { - mBackStackChangeListeners.remove(listener); - } - } - - @Override - public void putFragment(Bundle bundle, String key, Fragment fragment) { - if (fragment.mIndex < 0) { - throw new IllegalStateException("Fragment " + fragment - + " is not currently in the FragmentManager"); - } - bundle.putInt(key, fragment.mIndex); - } - - @Override - public Fragment getFragment(Bundle bundle, String key) { - int index = bundle.getInt(key, -1); - if (index == -1) { - return null; - } - if (index >= mActive.size()) { - throw new IllegalStateException("Fragement no longer exists for key " - + key + ": index " + index); - } - Fragment f = mActive.get(index); - if (f == null) { - throw new IllegalStateException("Fragement no longer exists for key " - + key + ": index " + index); - } - return f; - } - - @Override - public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) { - if (fragment.mIndex < 0) { - throw new IllegalStateException("Fragment " + fragment - + " is not currently in the FragmentManager"); - } - if (fragment.mState > Fragment.INITIALIZING) { - Bundle result = saveFragmentBasicState(fragment); - return result != null ? new Fragment.SavedState(result) : null; - } - return null; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(128); - sb.append("FragmentManager{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(" in "); - DebugUtils.buildShortClassTag(mActivity, sb); - sb.append("}}"); - return sb.toString(); - } - - @Override - public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { - String innerPrefix = prefix + " "; - - int N; - if (mActive != null) { - N = mActive.size(); - if (N > 0) { - writer.print(prefix); writer.print("Active Fragments in "); - writer.print(Integer.toHexString(System.identityHashCode(this))); - writer.println(":"); - for (int i=0; i 0) { - writer.print(prefix); writer.println("Added Fragments:"); - for (int i=0; i 0) { - writer.print(prefix); writer.println("Fragments Created Menus:"); - for (int i=0; i 0) { - writer.print(prefix); writer.println("Back Stack:"); - for (int i=0; i 0) { - writer.print(prefix); writer.println("Back Stack Indices:"); - for (int i=0; i 0) { - writer.print(prefix); writer.print("mAvailBackStackIndices: "); - writer.println(Arrays.toString(mAvailBackStackIndices.toArray())); - } - } - - if (mPendingActions != null) { - N = mPendingActions.size(); - if (N > 0) { - writer.print(prefix); writer.println("Pending Actions:"); - for (int i=0; i Fragment.CREATED) { - newState = Fragment.CREATED; - } - if (f.mRemoving && newState > f.mState) { - // While removing a fragment, we can't change it to a higher state. - newState = f.mState; - } - - if (f.mState < newState) { - // For fragments that are created from a layout, when restoring from - // state we don't want to allow them to be created until they are - // being reloaded from the layout. - if (f.mFromLayout && !f.mInLayout) { - return; - } - if (f.mAnimatingAway != null) { - // The fragment is currently being animated... but! Now we - // want to move our state back up. Give up on waiting for the - // animation, move to whatever the final state should be once - // the animation is done, and then we can proceed from there. - f.mAnimatingAway = null; - moveToState(f, f.mStateAfterAnimating, 0, 0); - } - switch (f.mState) { - case Fragment.INITIALIZING: - if (DEBUG) Log.v(TAG, "moveto CREATED: " + f); - if (f.mSavedFragmentState != null) { - f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray( - FragmentManagerImpl.VIEW_STATE_TAG); - f.mTarget = getFragment(f.mSavedFragmentState, - FragmentManagerImpl.TARGET_STATE_TAG); - if (f.mTarget != null) { - f.mTargetRequestCode = f.mSavedFragmentState.getInt( - FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0); - } - } - f.mActivity = mActivity; - f.mFragmentManager = mActivity.getInternalCallbacks().getFragments(); - f.mCalled = false; - f.onAttach(mActivity); - if (!f.mCalled) { - throw new SuperNotCalledException("Fragment " + f - + " did not call through to super.onAttach()"); - } - mActivity.onAttachFragment(f); - - if (!f.mRetaining) { - f.mCalled = false; - f.onCreate(f.mSavedFragmentState); - if (!f.mCalled) { - throw new SuperNotCalledException("Fragment " + f - + " did not call through to super.onCreate()"); - } - } - f.mRetaining = false; - if (f.mFromLayout) { - // For fragments that are part of the content view - // layout, we need to instantiate the view immediately - // and the inflater will take care of adding it. - f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState), - null, f.mSavedFragmentState); - if (f.mView != null) { - f.mInnerView = f.mView; - f.mView = NoSaveStateFrameLayout.wrap(f.mView); - if (f.mHidden) f.mView.setVisibility(View.GONE); - f.onViewCreated(f.mView, f.mSavedFragmentState); - } else { - f.mInnerView = null; - } - } - case Fragment.CREATED: - if (newState > Fragment.CREATED) { - if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f); - if (!f.mFromLayout) { - ViewGroup container = null; - if (f.mContainerId != 0) { - container = (ViewGroup)mActivity.findViewById(f.mContainerId); - if (container == null && !f.mRestored) { - throw new IllegalArgumentException("No view found for id 0x" - + Integer.toHexString(f.mContainerId) - + " for fragment " + f); - } - } - f.mContainer = container; - f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState), - container, f.mSavedFragmentState); - if (f.mView != null) { - f.mInnerView = f.mView; - f.mView = NoSaveStateFrameLayout.wrap(f.mView); - if (container != null) { - Animation anim = loadAnimation(f, transit, true, - transitionStyle); - if (anim != null) { - f.mView.startAnimation(anim); - } - container.addView(f.mView); - } - if (f.mHidden) f.mView.setVisibility(View.GONE); - f.onViewCreated(f.mView, f.mSavedFragmentState); - } else { - f.mInnerView = null; - } - } - - f.mCalled = false; - f.onActivityCreated(f.mSavedFragmentState); - if (!f.mCalled) { - throw new SuperNotCalledException("Fragment " + f - + " did not call through to super.onActivityCreated()"); - } - if (f.mView != null) { - f.restoreViewState(); - } - f.mSavedFragmentState = null; - } - case Fragment.ACTIVITY_CREATED: - case Fragment.STOPPED: - if (newState > Fragment.STOPPED) { - if (DEBUG) Log.v(TAG, "moveto STARTED: " + f); - f.mCalled = false; - f.performStart(); - if (!f.mCalled) { - throw new SuperNotCalledException("Fragment " + f - + " did not call through to super.onStart()"); - } - } - case Fragment.STARTED: - if (newState > Fragment.STARTED) { - if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f); - f.mCalled = false; - f.mResumed = true; - f.onResume(); - if (!f.mCalled) { - throw new SuperNotCalledException("Fragment " + f - + " did not call through to super.onResume()"); - } - } - } - } else if (f.mState > newState) { - switch (f.mState) { - case Fragment.RESUMED: - if (newState < Fragment.RESUMED) { - if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f); - f.mCalled = false; - f.onPause(); - if (!f.mCalled) { - throw new SuperNotCalledException("Fragment " + f - + " did not call through to super.onPause()"); - } - f.mResumed = false; - } - case Fragment.STARTED: - if (newState < Fragment.STARTED) { - if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f); - f.mCalled = false; - f.performStop(); - if (!f.mCalled) { - throw new SuperNotCalledException("Fragment " + f - + " did not call through to super.onStop()"); - } - } - case Fragment.STOPPED: - case Fragment.ACTIVITY_CREATED: - if (newState < Fragment.ACTIVITY_CREATED) { - if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f); - if (f.mView != null) { - // Need to save the current view state if not - // done already. - if (!mActivity.isFinishing() && f.mSavedViewState == null) { - saveFragmentViewState(f); - } - } - f.mCalled = false; - f.performDestroyView(); - if (!f.mCalled) { - throw new SuperNotCalledException("Fragment " + f - + " did not call through to super.onDestroyView()"); - } - if (f.mView != null && f.mContainer != null) { - Animation anim = null; - if (mCurState > Fragment.INITIALIZING && !mDestroyed) { - anim = loadAnimation(f, transit, false, - transitionStyle); - } - if (anim != null) { - final Fragment fragment = f; - f.mAnimatingAway = f.mView; - f.mStateAfterAnimating = newState; - anim.setAnimationListener(new AnimationListener() { - @Override - public void onAnimationEnd(Animation animation) { - if (fragment.mAnimatingAway != null) { - fragment.mAnimatingAway = null; - moveToState(fragment, fragment.mStateAfterAnimating, - 0, 0); - } - } - @Override - public void onAnimationRepeat(Animation animation) { - } - @Override - public void onAnimationStart(Animation animation) { - } - }); - f.mView.startAnimation(anim); - } - f.mContainer.removeView(f.mView); - } - f.mContainer = null; - f.mView = null; - f.mInnerView = null; - } - case Fragment.CREATED: - if (newState < Fragment.CREATED) { - if (mDestroyed) { - if (f.mAnimatingAway != null) { - // The fragment's containing activity is - // being destroyed, but this fragment is - // currently animating away. Stop the - // animation right now -- it is not needed, - // and we can't wait any more on destroying - // the fragment. - View v = f.mAnimatingAway; - f.mAnimatingAway = null; - v.clearAnimation(); - } - } - if (f.mAnimatingAway != null) { - // We are waiting for the fragment's view to finish - // animating away. Just make a note of the state - // the fragment now should move to once the animation - // is done. - f.mStateAfterAnimating = newState; - newState = Fragment.CREATED; - } else { - if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f); - if (!f.mRetaining) { - f.mCalled = false; - f.onDestroy(); - if (!f.mCalled) { - throw new SuperNotCalledException("Fragment " + f - + " did not call through to super.onDestroy()"); - } - } - - f.mCalled = false; - f.onDetach(); - if (!f.mCalled) { - throw new SuperNotCalledException("Fragment " + f - + " did not call through to super.onDetach()"); - } - if (!f.mRetaining) { - makeInactive(f); - } else { - f.mImmediateActivity = null; - f.mActivity = null; - f.mFragmentManager = null; - } - } - } - } - } - - f.mState = newState; - } - - void moveToState(Fragment f) { - moveToState(f, mCurState, 0, 0); - } - - void moveToState(int newState, boolean always) { - moveToState(newState, 0, 0, always); - } - - void moveToState(int newState, int transit, int transitStyle, boolean always) { - if (mActivity == null && newState != Fragment.INITIALIZING) { - throw new IllegalStateException("No activity"); - } - - if (!always && mCurState == newState) { - return; - } - - mCurState = newState; - if (mActive != null) { - for (int i=0; i= 0) { - return; - } - - if (mAvailIndices == null || mAvailIndices.size() <= 0) { - if (mActive == null) { - mActive = new ArrayList(); - } - f.setIndex(mActive.size()); - mActive.add(f); - - } else { - f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1)); - mActive.set(f.mIndex, f); - } - } - - void makeInactive(Fragment f) { - if (f.mIndex < 0) { - return; - } - - if (DEBUG) Log.v(TAG, "Freeing fragment index " + f.mIndex); - mActive.set(f.mIndex, null); - if (mAvailIndices == null) { - mAvailIndices = new ArrayList(); - } - mAvailIndices.add(f.mIndex); - mActivity.getInternalCallbacks().invalidateSupportFragmentIndex(f.mIndex); - f.initState(); - } - - public void addFragment(Fragment fragment, boolean moveToStateNow) { - if (mAdded == null) { - mAdded = new ArrayList(); - } - if (DEBUG) Log.v(TAG, "add: " + fragment); - makeActive(fragment); - if (!fragment.mDetached) { - mAdded.add(fragment); - fragment.mAdded = true; - fragment.mRemoving = false; - if (fragment.mHasMenu && fragment.mExposesMenu) { - mNeedMenuInvalidate = true; - } - if (moveToStateNow) { - moveToState(fragment); - } - } - } - - public void removeFragment(Fragment fragment, int transition, int transitionStyle) { - if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting); - final boolean inactive = !fragment.isInBackStack(); - if (!fragment.mDetached || inactive) { - mAdded.remove(fragment); - if (fragment.mHasMenu && fragment.mExposesMenu) { - mNeedMenuInvalidate = true; - } - fragment.mAdded = false; - fragment.mRemoving = true; - moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED, - transition, transitionStyle); - } - } - - public void hideFragment(Fragment fragment, int transition, int transitionStyle) { - if (DEBUG) Log.v(TAG, "hide: " + fragment); - if (!fragment.mHidden) { - fragment.mHidden = true; - if (fragment.mView != null) { - Animation anim = loadAnimation(fragment, transition, true, - transitionStyle); - if (anim != null) { - fragment.mView.startAnimation(anim); - } - fragment.mView.setVisibility(View.GONE); - } - if (fragment.mAdded && fragment.mHasMenu && fragment.mExposesMenu) { - mNeedMenuInvalidate = true; - } - fragment.onHiddenChanged(true); - } - } - - public void showFragment(Fragment fragment, int transition, int transitionStyle) { - if (DEBUG) Log.v(TAG, "show: " + fragment); - if (fragment.mHidden) { - fragment.mHidden = false; - if (fragment.mView != null) { - Animation anim = loadAnimation(fragment, transition, true, - transitionStyle); - if (anim != null) { - fragment.mView.startAnimation(anim); - } - fragment.mView.setVisibility(View.VISIBLE); - } - if (fragment.mAdded && fragment.mHasMenu && fragment.mExposesMenu) { - mNeedMenuInvalidate = true; - } - fragment.onHiddenChanged(false); - } - } - - public void detachFragment(Fragment fragment, int transition, int transitionStyle) { - if (DEBUG) Log.v(TAG, "detach: " + fragment); - if (!fragment.mDetached) { - fragment.mDetached = true; - if (fragment.mAdded) { - // We are not already in back stack, so need to remove the fragment. - mAdded.remove(fragment); - if (fragment.mHasMenu && fragment.mExposesMenu) { - mNeedMenuInvalidate = true; - } - fragment.mAdded = false; - moveToState(fragment, Fragment.CREATED, transition, transitionStyle); - } - } - } - - public void attachFragment(Fragment fragment, int transition, int transitionStyle) { - if (DEBUG) Log.v(TAG, "attach: " + fragment); - if (fragment.mDetached) { - fragment.mDetached = false; - if (!fragment.mAdded) { - mAdded.add(fragment); - fragment.mAdded = true; - if (fragment.mHasMenu && fragment.mExposesMenu) { - mNeedMenuInvalidate = true; - } - moveToState(fragment, mCurState, transition, transitionStyle); - } - } - } - - public Fragment findFragmentById(int id) { - if (mActive != null) { - // First look through added fragments. - for (int i=mAdded.size()-1; i>=0; i--) { - Fragment f = mAdded.get(i); - if (f != null && f.mFragmentId == id) { - return f; - } - } - // Now for any known fragment. - for (int i=mActive.size()-1; i>=0; i--) { - Fragment f = mActive.get(i); - if (f != null && f.mFragmentId == id) { - return f; - } - } - } - return null; - } - - public Fragment findFragmentByTag(String tag) { - if (mActive != null && tag != null) { - // First look through added fragments. - for (int i=mAdded.size()-1; i>=0; i--) { - Fragment f = mAdded.get(i); - if (f != null && tag.equals(f.mTag)) { - return f; - } - } - // Now for any known fragment. - for (int i=mActive.size()-1; i>=0; i--) { - Fragment f = mActive.get(i); - if (f != null && tag.equals(f.mTag)) { - return f; - } - } - } - return null; - } - - public Fragment findFragmentByWho(String who) { - if (mActive != null && who != null) { - for (int i=mActive.size()-1; i>=0; i--) { - Fragment f = mActive.get(i); - if (f != null && who.equals(f.mWho)) { - return f; - } - } - } - return null; - } - - private void checkStateLoss() { - if (mStateSaved) { - throw new IllegalStateException( - "Can not perform this action after onSaveInstanceState"); - } - if (mNoTransactionsBecause != null) { - throw new IllegalStateException( - "Can not perform this action inside of " + mNoTransactionsBecause); - } - } - - public void enqueueAction(Runnable action, boolean allowStateLoss) { - if (!allowStateLoss) { - checkStateLoss(); - } - synchronized (this) { - if (mActivity == null) { - throw new IllegalStateException("Activity has been destroyed"); - } - mActivity.getInternalCallbacks().ensureSupportActionBarAttached(); - if (mPendingActions == null) { - mPendingActions = new ArrayList(); - } - mPendingActions.add(action); - if (mPendingActions.size() == 1) { - mActivity.getInternalCallbacks().getHandler().removeCallbacks(mExecCommit); - mActivity.getInternalCallbacks().getHandler().post(mExecCommit); - } - } - } - - public int allocBackStackIndex(BackStackRecord bse) { - synchronized (this) { - if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) { - if (mBackStackIndices == null) { - mBackStackIndices = new ArrayList(); - } - int index = mBackStackIndices.size(); - if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse); - mBackStackIndices.add(bse); - return index; - - } else { - int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1); - if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse); - mBackStackIndices.set(index, bse); - return index; - } - } - } - - public void setBackStackIndex(int index, BackStackRecord bse) { - synchronized (this) { - if (mBackStackIndices == null) { - mBackStackIndices = new ArrayList(); - } - int N = mBackStackIndices.size(); - if (index < N) { - if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse); - mBackStackIndices.set(index, bse); - } else { - while (N < index) { - mBackStackIndices.add(null); - if (mAvailBackStackIndices == null) { - mAvailBackStackIndices = new ArrayList(); - } - if (DEBUG) Log.v(TAG, "Adding available back stack index " + N); - mAvailBackStackIndices.add(N); - N++; - } - if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse); - mBackStackIndices.add(bse); - } - } - } - - public void freeBackStackIndex(int index) { - synchronized (this) { - mBackStackIndices.set(index, null); - if (mAvailBackStackIndices == null) { - mAvailBackStackIndices = new ArrayList(); - } - if (DEBUG) Log.v(TAG, "Freeing back stack index " + index); - mAvailBackStackIndices.add(index); - } - } - - /** - * Only call from main thread! - */ - public boolean execPendingActions() { - if (mExecutingActions) { - throw new IllegalStateException("Recursive entry to executePendingTransactions"); - } - - if (Looper.myLooper() != mActivity.getInternalCallbacks().getHandler().getLooper()) { - throw new IllegalStateException("Must be called from main thread of process"); - } - - boolean didSomething = false; - - while (true) { - int numActions; - - synchronized (this) { - if (mPendingActions == null || mPendingActions.size() == 0) { - return didSomething; - } - - numActions = mPendingActions.size(); - if (mTmpActions == null || mTmpActions.length < numActions) { - mTmpActions = new Runnable[numActions]; - } - mPendingActions.toArray(mTmpActions); - mPendingActions.clear(); - mActivity.getInternalCallbacks().getHandler().removeCallbacks(mExecCommit); - } - - mExecutingActions = true; - for (int i=0; i(); - } - mBackStack.add(state); - reportBackStackChanged(); - } - - boolean popBackStackState(Handler handler, String name, int id, int flags) { - if (mBackStack == null) { - return false; - } - if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) { - int last = mBackStack.size()-1; - if (last < 0) { - return false; - } - final BackStackRecord bss = mBackStack.remove(last); - bss.popFromBackStack(true); - reportBackStackChanged(); - } else { - int index = -1; - if (name != null || id >= 0) { - // If a name or ID is specified, look for that place in - // the stack. - index = mBackStack.size()-1; - while (index >= 0) { - BackStackRecord bss = mBackStack.get(index); - if (name != null && name.equals(bss.getName())) { - break; - } - if (id >= 0 && id == bss.mIndex) { - break; - } - index--; - } - if (index < 0) { - return false; - } - if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) { - index--; - // Consume all following entries that match. - while (index >= 0) { - BackStackRecord bss = mBackStack.get(index); - if ((name != null && name.equals(bss.getName())) - || (id >= 0 && id == bss.mIndex)) { - index--; - continue; - } - break; - } - } - } - if (index == mBackStack.size()-1) { - return false; - } - final ArrayList states - = new ArrayList(); - for (int i=mBackStack.size()-1; i>index; i--) { - states.add(mBackStack.remove(i)); - } - final int LAST = states.size()-1; - for (int i=0; i<=LAST; i++) { - if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i)); - states.get(i).popFromBackStack(i == LAST); - } - reportBackStackChanged(); - } - return true; - } - - ArrayList retainNonConfig() { - ArrayList fragments = null; - if (mActive != null) { - for (int i=0; i(); - } - fragments.add(f); - f.mRetaining = true; - f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1; - } - } - } - return fragments; - } - - void saveFragmentViewState(Fragment f) { - if (f.mInnerView == null) { - return; - } - if (mStateArray == null) { - mStateArray = new SparseArray(); - } else { - mStateArray.clear(); - } - f.mInnerView.saveHierarchyState(mStateArray); - if (mStateArray.size() > 0) { - f.mSavedViewState = mStateArray; - mStateArray = null; - } - } - - Bundle saveFragmentBasicState(Fragment f) { - Bundle result = null; - - if (mStateBundle == null) { - mStateBundle = new Bundle(); - } - f.onSaveInstanceState(mStateBundle); - if (!mStateBundle.isEmpty()) { - result = mStateBundle; - mStateBundle = null; - } - - if (f.mView != null) { - saveFragmentViewState(f); - } - if (f.mSavedViewState != null) { - if (result == null) { - result = new Bundle(); - } - result.putSparseParcelableArray( - FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState); - } - - return result; - } - - Parcelable saveAllState() { - // Make sure all pending operations have now been executed to get - // our state update-to-date. - execPendingActions(); - - if (HONEYCOMB) { - // As of Honeycomb, we save state after pausing. Prior to that - // it is before pausing. With fragments this is an issue, since - // there are many things you may do after pausing but before - // stopping that change the fragment state. For those older - // devices, we will not at this point say that we have saved - // the state, so we will allow them to continue doing fragment - // transactions. This retains the same semantics as Honeycomb, - // though you do have the risk of losing the very most recent state - // if the process is killed... we'll live with that. - mStateSaved = true; - } - - if (mActive == null || mActive.size() <= 0) { - return null; - } - - // First collect all active fragments. - int N = mActive.size(); - FragmentState[] active = new FragmentState[N]; - boolean haveFragments = false; - for (int i=0; i Fragment.INITIALIZING && fs.mSavedFragmentState == null) { - fs.mSavedFragmentState = saveFragmentBasicState(f); - - if (f.mTarget != null) { - if (f.mTarget.mIndex < 0) { - String msg = "Failure saving state: " + f - + " has target not in fragment manager: " + f.mTarget; - Log.e(TAG, msg); - dump(" ", null, new PrintWriter(new LogWriter(TAG)), new String[] { }); - throw new IllegalStateException(msg); - } - if (fs.mSavedFragmentState == null) { - fs.mSavedFragmentState = new Bundle(); - } - putFragment(fs.mSavedFragmentState, - FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget); - if (f.mTargetRequestCode != 0) { - fs.mSavedFragmentState.putInt( - FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, - f.mTargetRequestCode); - } - } - - } else { - fs.mSavedFragmentState = f.mSavedFragmentState; - } - - if (DEBUG) Log.v(TAG, "Saved state of " + f + ": " - + fs.mSavedFragmentState); - } - } - - if (!haveFragments) { - if (DEBUG) Log.v(TAG, "saveAllState: no fragments!"); - return null; - } - - int[] added = null; - BackStackState[] backStack = null; - - // Build list of currently added fragments. - if (mAdded != null) { - N = mAdded.size(); - if (N > 0) { - added = new int[N]; - for (int i=0; i 0) { - backStack = new BackStackState[N]; - for (int i=0; i nonConfig) { - // If there is no saved state at all, then there can not be - // any nonConfig fragments either, so that is that. - if (state == null) return; - FragmentManagerState fms = (FragmentManagerState)state; - if (fms.mActive == null) return; - - // First re-attach any non-config instances we are retaining back - // to their saved state, so we don't try to instantiate them again. - if (nonConfig != null) { - for (int i=0; i(fms.mActive.length); - if (mAvailIndices != null) { - mAvailIndices.clear(); - } - for (int i=0; i(); - } - if (DEBUG) Log.v(TAG, "restoreAllState: adding avail #" + i); - mAvailIndices.add(i); - } - } - - // Update the target of all retained fragments. - if (nonConfig != null) { - for (int i=0; i= 0) { - if (f.mTargetIndex < mActive.size()) { - f.mTarget = mActive.get(f.mTargetIndex); - } else { - Log.w(TAG, "Re-attaching retained fragment " + f - + " target no longer exists: " + f.mTargetIndex); - f.mTarget = null; - } - } - } - } - - // Build the list of currently added fragments. - if (fms.mAdded != null) { - mAdded = new ArrayList(fms.mAdded.length); - for (int i=0; i(fms.mBackStack.length); - for (int i=0; i= 0) { - setBackStackIndex(bse.mIndex, bse); - } - } - } else { - mBackStack = null; - } - } - - public void attachActivity(SupportActivity activity) { - if (mActivity != null) throw new IllegalStateException(); - mActivity = activity; - } - - public void noteStateNotSaved() { - mStateSaved = false; - } - - public void dispatchCreate() { - mStateSaved = false; - moveToState(Fragment.CREATED, false); - } - - public void dispatchActivityCreated() { - mStateSaved = false; - moveToState(Fragment.ACTIVITY_CREATED, false); - } - - public void dispatchStart() { - mStateSaved = false; - moveToState(Fragment.STARTED, false); - } - - public void dispatchResume() { - mStateSaved = false; - moveToState(Fragment.RESUMED, false); - } - - public void dispatchPause() { - moveToState(Fragment.STARTED, false); - } - - public void dispatchStop() { - // See saveAllState() for the explanation of this. We do this for - // all platform versions, to keep our behavior more consistent between - // them. - mStateSaved = true; - - moveToState(Fragment.STOPPED, false); - } - - public void dispatchReallyStop(boolean retaining) { - if (mActive != null) { - for (int i=0; i newMenus = null; - if (mActive != null) { - for (int i=0; i(); - } - newMenus.add(f); - } - } - } - - if (mCreatedMenus != null) { - for (int i=0; i mLastFragment = null; - private int mLastPosition = -1; - private boolean mOptionsMenuPotentiallyStale; - - public FragmentPagerAdapter(FragmentManager fm) { - mFragmentManager = fm; - } - - /** - * Return the Fragment associated with a specified position. - */ - public abstract Fragment getItem(int position); - - @Override - public void startUpdate(View container) { - mOptionsMenuPotentiallyStale = false; - } - - @Override - public Object instantiateItem(View container, int position) { - if (mCurTransaction == null) { - mCurTransaction = mFragmentManager.beginTransaction(); - } - - // Do we already have this fragment? - String name = makeFragmentName(container.getId(), position); - Fragment fragment = mFragmentManager.findFragmentByTag(name); - if (fragment != null) { - if (DEBUG) Log.v(TAG, "Attaching item #" + position + ": f=" + fragment); - mCurTransaction.attach(fragment); - } else { - fragment = getItem(position); - if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); - mCurTransaction.add(container.getId(), fragment, - makeFragmentName(container.getId(), position)); - } - - fragment.mExposesMenu = false; - return fragment; - } - - @Override - public void destroyItem(View container, int position, Object object) { - if (mCurTransaction == null) { - mCurTransaction = mFragmentManager.beginTransaction(); - } - Fragment fragment = (Fragment)object; - fragment.mExposesMenu = true; - if (DEBUG) Log.v(TAG, "Detaching item #" + position + ": f=" + fragment - + " v=" + fragment.getView()); - mCurTransaction.detach(fragment); - } - - @Override - public void onItemSelected(int position, Object object) { - if (position == mLastPosition) { - return; - } - if ((mLastFragment != null) && (mLastFragment.get() != null)) { - mLastFragment.get().mExposesMenu = false; - } - Fragment fragment = (Fragment)object; - fragment.mExposesMenu = true; - mLastFragment = new WeakReference(fragment); - mLastPosition = position; - mOptionsMenuPotentiallyStale = true; - } - - @Override - public void finishUpdate(View container) { - if (mCurTransaction != null) { - mCurTransaction.commit(); - mCurTransaction = null; - mOptionsMenuPotentiallyStale = true; - } - if (mOptionsMenuPotentiallyStale) { - mFragmentManager.executePendingTransactions(); - ((FragmentManagerImpl)mFragmentManager).mActivity.invalidateOptionsMenu(); - } - } - - @Override - public boolean isViewFromObject(View view, Object object) { - return ((Fragment)object).getView() == view; - } - - @Override - public Parcelable saveState() { - return null; - } - - @Override - public void restoreState(Parcelable state, ClassLoader loader) { - } - - private static String makeFragmentName(int viewId, int index) { - return "android:switcher:" + viewId + ":" + index; - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentStatePagerAdapter.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentStatePagerAdapter.java deleted file mode 100644 index 8567e83d..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentStatePagerAdapter.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -import java.util.ArrayList; - -import android.os.Bundle; -import android.os.Parcelable; -import android.support.v4.view.PagerAdapter; -import android.util.Log; -import android.view.View; - -public abstract class FragmentStatePagerAdapter extends PagerAdapter { - private static final String TAG = "FragmentStatePagerAdapter"; - private static final boolean DEBUG = false; - - private final FragmentManager mFragmentManager; - private FragmentTransaction mCurTransaction = null; - - private ArrayList mSavedState = new ArrayList(); - private ArrayList mFragments = new ArrayList(); - - public FragmentStatePagerAdapter(FragmentManager fm) { - mFragmentManager = fm; - } - - /** - * Return the Fragment associated with a specified position. - */ - public abstract Fragment getItem(int position); - - @Override - public void startUpdate(View container) { - } - - @Override - public Object instantiateItem(View container, int position) { - // If we already have this item instantiated, there is nothing - // to do. This can happen when we are restoring the entire pager - // from its saved state, where the fragment manager has already - // taken care of restoring the fragments we previously had instantiated. - if (mFragments.size() > position) { - Fragment f = mFragments.get(position); - if (f != null) { - return f; - } - } - - if (mCurTransaction == null) { - mCurTransaction = mFragmentManager.beginTransaction(); - } - - Fragment fragment = getItem(position); - if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment); - if (mSavedState.size() > position) { - Fragment.SavedState fss = mSavedState.get(position); - if (fss != null) { - fragment.setInitialSavedState(fss); - } - } - while (mFragments.size() <= position) { - mFragments.add(null); - } - mFragments.set(position, fragment); - mCurTransaction.add(container.getId(), fragment); - - return fragment; - } - - @Override - public void destroyItem(View container, int position, Object object) { - Fragment fragment = (Fragment)object; - - if (mCurTransaction == null) { - mCurTransaction = mFragmentManager.beginTransaction(); - } - if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object - + " v=" + ((Fragment)object).getView()); - while (mSavedState.size() <= position) { - mSavedState.add(null); - } - mSavedState.set(position, mFragmentManager.saveFragmentInstanceState(fragment)); - mFragments.set(position, null); - - mCurTransaction.remove(fragment); - } - - @Override - public void finishUpdate(View container) { - if (mCurTransaction != null) { - mCurTransaction.commit(); - mCurTransaction = null; - mFragmentManager.executePendingTransactions(); - } - } - - @Override - public boolean isViewFromObject(View view, Object object) { - return ((Fragment)object).getView() == view; - } - - @Override - public Parcelable saveState() { - Bundle state = null; - if (mSavedState.size() > 0) { - state = new Bundle(); - Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()]; - mSavedState.toArray(fss); - state.putParcelableArray("states", fss); - } - for (int i=0; i keys = bundle.keySet(); - for (String key: keys) { - if (key.startsWith("f")) { - int index = Integer.parseInt(key.substring(1)); - Fragment f = mFragmentManager.getFragment(bundle, key); - if (f != null) { - while (mFragments.size() <= index) { - mFragments.add(null); - } - mFragments.set(index, f); - } else { - Log.w(TAG, "Bad fragment at key " + key); - } - } - } - } - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentTransaction.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentTransaction.java deleted file mode 100644 index b8dfd5f6..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/FragmentTransaction.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -/** - * Static library support version of the framework's {@link android.app.FragmentTransaction}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - */ -public abstract class FragmentTransaction { - /** - * Calls {@link #add(int, Fragment, String)} with a 0 containerViewId. - */ - public abstract FragmentTransaction add(Fragment fragment, String tag); - - /** - * Calls {@link #add(int, Fragment, String)} with a null tag. - */ - public abstract FragmentTransaction add(int containerViewId, Fragment fragment); - - /** - * Add a fragment to the activity state. This fragment may optionally - * also have its view (if {@link Fragment#onCreateView Fragment.onCreateView} - * returns non-null) into a container view of the activity. - * - * @param containerViewId Optional identifier of the container this fragment is - * to be placed in. If 0, it will not be placed in a container. - * @param fragment The fragment to be added. This fragment must not already - * be added to the activity. - * @param tag Optional tag name for the fragment, to later retrieve the - * fragment with {@link FragmentManager#findFragmentByTag(String) - * FragmentManager.findFragmentByTag(String)}. - * - * @return Returns the same FragmentTransaction instance. - */ - public abstract FragmentTransaction add(int containerViewId, Fragment fragment, String tag); - - /** - * Calls {@link #replace(int, Fragment, String)} with a null tag. - */ - public abstract FragmentTransaction replace(int containerViewId, Fragment fragment); - - /** - * Replace an existing fragment that was added to a container. This is - * essentially the same as calling {@link #remove(Fragment)} for all - * currently added fragments that were added with the same containerViewId - * and then {@link #add(int, Fragment, String)} with the same arguments - * given here. - * - * @param containerViewId Identifier of the container whose fragment(s) are - * to be replaced. - * @param fragment The new fragment to place in the container. - * @param tag Optional tag name for the fragment, to later retrieve the - * fragment with {@link FragmentManager#findFragmentByTag(String) - * FragmentManager.findFragmentByTag(String)}. - * - * @return Returns the same FragmentTransaction instance. - */ - public abstract FragmentTransaction replace(int containerViewId, Fragment fragment, String tag); - - /** - * Remove an existing fragment. If it was added to a container, its view - * is also removed from that container. - * - * @param fragment The fragment to be removed. - * - * @return Returns the same FragmentTransaction instance. - */ - public abstract FragmentTransaction remove(Fragment fragment); - - /** - * Hides an existing fragment. This is only relevant for fragments whose - * views have been added to a container, as this will cause the view to - * be hidden. - * - * @param fragment The fragment to be hidden. - * - * @return Returns the same FragmentTransaction instance. - */ - public abstract FragmentTransaction hide(Fragment fragment); - - /** - * Shows a previously hidden fragment. This is only relevant for fragments whose - * views have been added to a container, as this will cause the view to - * be shown. - * - * @param fragment The fragment to be shown. - * - * @return Returns the same FragmentTransaction instance. - */ - public abstract FragmentTransaction show(Fragment fragment); - - /** - * Detach the given fragment from the UI. This is the same state as - * when it is put on the back stack: the fragment is removed from - * the UI, however its state is still being actively managed by the - * fragment manager. When going into this state its view hierarchy - * is destroyed. - * - * @param fragment The fragment to be detached. - * - * @return Returns the same FragmentTransaction instance. - */ - public abstract FragmentTransaction detach(Fragment fragment); - - /** - * Re-attach a fragment after it had previously been deatched from - * the UI with {@link #detach(Fragment)}. This - * causes its view hierarchy to be re-created, attached to the UI, - * and displayed. - * - * @param fragment The fragment to be attached. - * - * @return Returns the same FragmentTransaction instance. - */ - public abstract FragmentTransaction attach(Fragment fragment); - - /** - * @return true if this transaction contains no operations, - * false otherwise. - */ - public abstract boolean isEmpty(); - - /** - * Bit mask that is set for all enter transitions. - */ - public static final int TRANSIT_ENTER_MASK = 0x1000; - - /** - * Bit mask that is set for all exit transitions. - */ - public static final int TRANSIT_EXIT_MASK = 0x2000; - - /** Not set up for a transition. */ - public static final int TRANSIT_UNSET = -1; - /** No animation for transition. */ - public static final int TRANSIT_NONE = 0; - /** Fragment is being added onto the stack */ - public static final int TRANSIT_FRAGMENT_OPEN = 1 | TRANSIT_ENTER_MASK; - /** Fragment is being removed from the stack */ - public static final int TRANSIT_FRAGMENT_CLOSE = 2 | TRANSIT_EXIT_MASK; - /** Fragment should simply fade in or out; that is, no strong navigation associated - * with it except that it is appearing or disappearing for some reason. */ - public static final int TRANSIT_FRAGMENT_FADE = 3 | TRANSIT_ENTER_MASK; - - /** - * Set specific animation resources to run for the fragments that are - * entering and exiting in this transaction. - */ - public abstract FragmentTransaction setCustomAnimations(int enter, int exit); - - /** - * Select a standard transition animation for this transaction. May be - * one of {@link #TRANSIT_NONE}, {@link #TRANSIT_FRAGMENT_OPEN}, - * or {@link #TRANSIT_FRAGMENT_CLOSE} - */ - public abstract FragmentTransaction setTransition(int transit); - - /** - * Set a custom style resource that will be used for resolving transit - * animations. - */ - public abstract FragmentTransaction setTransitionStyle(int styleRes); - - /** - * Add this transaction to the back stack. This means that the transaction - * will be remembered after it is committed, and will reverse its operation - * when later popped off the stack. - * - * @param name An optional name for this back stack state, or null. - */ - public abstract FragmentTransaction addToBackStack(String name); - - /** - * Returns true if this FragmentTransaction is allowed to be added to the back - * stack. If this method would return false, {@link #addToBackStack(String)} - * will throw {@link IllegalStateException}. - * - * @return True if {@link #addToBackStack(String)} is permitted on this transaction. - */ - public abstract boolean isAddToBackStackAllowed(); - - /** - * Disallow calls to {@link #addToBackStack(String)}. Any future calls to - * addToBackStack will throw {@link IllegalStateException}. If addToBackStack - * has already been called, this method will throw IllegalStateException. - */ - public abstract FragmentTransaction disallowAddToBackStack(); - - /** - * Set the full title to show as a bread crumb when this transaction - * is on the back stack, as used by {@link FragmentBreadCrumbs}. - * - * @param res A string resource containing the title. - */ - public abstract FragmentTransaction setBreadCrumbTitle(int res); - - /** - * Like {@link #setBreadCrumbTitle(int)} but taking a raw string; this - * method is not recommended, as the string can not be changed - * later if the locale changes. - */ - public abstract FragmentTransaction setBreadCrumbTitle(CharSequence text); - - /** - * Set the short title to show as a bread crumb when this transaction - * is on the back stack, as used by {@link FragmentBreadCrumbs}. - * - * @param res A string resource containing the title. - */ - public abstract FragmentTransaction setBreadCrumbShortTitle(int res); - - /** - * Like {@link #setBreadCrumbShortTitle(int)} but taking a raw string; this - * method is not recommended, as the string can not be changed - * later if the locale changes. - */ - public abstract FragmentTransaction setBreadCrumbShortTitle(CharSequence text); - - /** - * Schedules a commit of this transaction. The commit does - * not happen immediately; it will be scheduled as work on the main thread - * to be done the next time that thread is ready. - * - *

A transaction can only be committed with this method - * prior to its containing activity saving its state. If the commit is - * attempted after that point, an exception will be thrown. This is - * because the state after the commit can be lost if the activity needs to - * be restored from its state. See {@link #commitAllowingStateLoss()} for - * situations where it may be okay to lose the commit.

- * - * @return Returns the identifier of this transaction's back stack entry, - * if {@link #addToBackStack(String)} had been called. Otherwise, returns - * a negative number. - */ - public abstract int commit(); - - /** - * Like {@link #commit} but allows the commit to be executed after an - * activity's state is saved. This is dangerous because the commit can - * be lost if the activity needs to later be restored from its state, so - * this should only be used for cases where it is okay for the UI state - * to change unexpectedly on the user. - */ - public abstract int commitAllowingStateLoss(); -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/HCSparseArray.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/HCSparseArray.java deleted file mode 100644 index f6cf9fe2..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/HCSparseArray.java +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -/** - * A copy of Honeycomb's SparseArray, only so we can have the removeAt() method. - */ -public class HCSparseArray { - private static final Object DELETED = new Object(); - private boolean mGarbage = false; - - /** - * Creates a new SparseArray containing no mappings. - */ - public HCSparseArray() { - this(10); - } - - /** - * Creates a new SparseArray containing no mappings that will not - * require any additional memory allocation to store the specified - * number of mappings. - */ - public HCSparseArray(int initialCapacity) { - initialCapacity = idealIntArraySize(initialCapacity); - - mKeys = new int[initialCapacity]; - mValues = new Object[initialCapacity]; - mSize = 0; - } - - /** - * Gets the Object mapped from the specified key, or null - * if no such mapping has been made. - */ - public E get(int key) { - return get(key, null); - } - - /** - * Gets the Object mapped from the specified key, or the specified Object - * if no such mapping has been made. - */ - @SuppressWarnings("unchecked") - public E get(int key, E valueIfKeyNotFound) { - int i = binarySearch(mKeys, 0, mSize, key); - - if (i < 0 || mValues[i] == DELETED) { - return valueIfKeyNotFound; - } else { - return (E) mValues[i]; - } - } - - /** - * Removes the mapping from the specified key, if there was any. - */ - public void delete(int key) { - int i = binarySearch(mKeys, 0, mSize, key); - - if (i >= 0) { - if (mValues[i] != DELETED) { - mValues[i] = DELETED; - mGarbage = true; - } - } - } - - /** - * Alias for {@link #delete(int)}. - */ - public void remove(int key) { - delete(key); - } - - /** - * Removes the mapping at the specified index. - */ - public void removeAt(int index) { - if (mValues[index] != DELETED) { - mValues[index] = DELETED; - mGarbage = true; - } - } - - private void gc() { - // Log.e("SparseArray", "gc start with " + mSize); - - int n = mSize; - int o = 0; - int[] keys = mKeys; - Object[] values = mValues; - - for (int i = 0; i < n; i++) { - Object val = values[i]; - - if (val != DELETED) { - if (i != o) { - keys[o] = keys[i]; - values[o] = val; - } - - o++; - } - } - - mGarbage = false; - mSize = o; - - // Log.e("SparseArray", "gc end with " + mSize); - } - - /** - * Adds a mapping from the specified key to the specified value, - * replacing the previous mapping from the specified key if there - * was one. - */ - public void put(int key, E value) { - int i = binarySearch(mKeys, 0, mSize, key); - - if (i >= 0) { - mValues[i] = value; - } else { - i = ~i; - - if (i < mSize && mValues[i] == DELETED) { - mKeys[i] = key; - mValues[i] = value; - return; - } - - if (mGarbage && mSize >= mKeys.length) { - gc(); - - // Search again because indices may have changed. - i = ~binarySearch(mKeys, 0, mSize, key); - } - - if (mSize >= mKeys.length) { - int n = idealIntArraySize(mSize + 1); - - int[] nkeys = new int[n]; - Object[] nvalues = new Object[n]; - - // Log.e("SparseArray", "grow " + mKeys.length + " to " + n); - System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length); - System.arraycopy(mValues, 0, nvalues, 0, mValues.length); - - mKeys = nkeys; - mValues = nvalues; - } - - if (mSize - i != 0) { - // Log.e("SparseArray", "move " + (mSize - i)); - System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i); - System.arraycopy(mValues, i, mValues, i + 1, mSize - i); - } - - mKeys[i] = key; - mValues[i] = value; - mSize++; - } - } - - /** - * Returns the number of key-value mappings that this SparseArray - * currently stores. - */ - public int size() { - if (mGarbage) { - gc(); - } - - return mSize; - } - - /** - * Given an index in the range 0...size()-1, returns - * the key from the indexth key-value mapping that this - * SparseArray stores. - */ - public int keyAt(int index) { - if (mGarbage) { - gc(); - } - - return mKeys[index]; - } - - /** - * Given an index in the range 0...size()-1, returns - * the value from the indexth key-value mapping that this - * SparseArray stores. - */ - @SuppressWarnings("unchecked") - public E valueAt(int index) { - if (mGarbage) { - gc(); - } - - return (E) mValues[index]; - } - - /** - * Given an index in the range 0...size()-1, sets a new - * value for the indexth key-value mapping that this - * SparseArray stores. - */ - public void setValueAt(int index, E value) { - if (mGarbage) { - gc(); - } - - mValues[index] = value; - } - - /** - * Returns the index for which {@link #keyAt} would return the - * specified key, or a negative number if the specified - * key is not mapped. - */ - public int indexOfKey(int key) { - if (mGarbage) { - gc(); - } - - return binarySearch(mKeys, 0, mSize, key); - } - - /** - * Returns an index for which {@link #valueAt} would return the - * specified key, or a negative number if no keys map to the - * specified value. - * Beware that this is a linear search, unlike lookups by key, - * and that multiple keys can map to the same value and this will - * find only one of them. - */ - public int indexOfValue(E value) { - if (mGarbage) { - gc(); - } - - for (int i = 0; i < mSize; i++) - if (mValues[i] == value) - return i; - - return -1; - } - - /** - * Removes all key-value mappings from this SparseArray. - */ - public void clear() { - int n = mSize; - Object[] values = mValues; - - for (int i = 0; i < n; i++) { - values[i] = null; - } - - mSize = 0; - mGarbage = false; - } - - /** - * Puts a key/value pair into the array, optimizing for the case where - * the key is greater than all existing keys in the array. - */ - public void append(int key, E value) { - if (mSize != 0 && key <= mKeys[mSize - 1]) { - put(key, value); - return; - } - - if (mGarbage && mSize >= mKeys.length) { - gc(); - } - - int pos = mSize; - if (pos >= mKeys.length) { - int n = idealIntArraySize(pos + 1); - - int[] nkeys = new int[n]; - Object[] nvalues = new Object[n]; - - // Log.e("SparseArray", "grow " + mKeys.length + " to " + n); - System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length); - System.arraycopy(mValues, 0, nvalues, 0, mValues.length); - - mKeys = nkeys; - mValues = nvalues; - } - - mKeys[pos] = key; - mValues[pos] = value; - mSize = pos + 1; - } - - private static int binarySearch(int[] a, int start, int len, int key) { - int high = start + len, low = start - 1, guess; - - while (high - low > 1) { - guess = (high + low) / 2; - - if (a[guess] < key) - low = guess; - else - high = guess; - } - - if (high == start + len) - return ~(start + len); - else if (a[high] == key) - return high; - else - return ~high; - } - - /*private void checkIntegrity() { - for (int i = 1; i < mSize; i++) { - if (mKeys[i] <= mKeys[i - 1]) { - for (int j = 0; j < mSize; j++) { - Log.e("FAIL", j + ": " + mKeys[j] + " -> " + mValues[j]); - } - - throw new RuntimeException(); - } - } - }*/ - - static int idealByteArraySize(int need) { - for (int i = 4; i < 32; i++) - if (need <= (1 << i) - 12) - return (1 << i) - 12; - - return need; - } - - static int idealIntArraySize(int need) { - return idealByteArraySize(need * 4) / 4; - } - - private int[] mKeys; - private Object[] mValues; - private int mSize; -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/ListFragment.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/ListFragment.java deleted file mode 100644 index 7f8666ff..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/ListFragment.java +++ /dev/null @@ -1,375 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -import android.content.Context; -import android.os.Bundle; -import android.os.Handler; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.AnimationUtils; -import android.widget.AdapterView; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.ProgressBar; -import android.widget.TextView; - -/** - * Static library support version of the framework's {@link android.app.ListFragment}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - */ -public class ListFragment extends Fragment { - static final int INTERNAL_EMPTY_ID = 0x00ff0001; - static final int INTERNAL_PROGRESS_CONTAINER_ID = 0x00ff0002; - static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003; - - final private Handler mHandler = new Handler(); - - final private Runnable mRequestFocus = new Runnable() { - public void run() { - mList.focusableViewAvailable(mList); - } - }; - - final private AdapterView.OnItemClickListener mOnClickListener - = new AdapterView.OnItemClickListener() { - public void onItemClick(AdapterView parent, View v, int position, long id) { - onListItemClick((ListView)parent, v, position, id); - } - }; - - ListAdapter mAdapter; - ListView mList; - View mEmptyView; - TextView mStandardEmptyView; - View mProgressContainer; - View mListContainer; - CharSequence mEmptyText; - boolean mListShown; - - public ListFragment() { - } - - /** - * Provide default implementation to return a simple list view. Subclasses - * can override to replace with their own layout. If doing so, the - * returned view hierarchy must have a ListView whose id - * is {@link android.R.id#list android.R.id.list} and can optionally - * have a sibling view id {@link android.R.id#empty android.R.id.empty} - * that is to be shown when the list is empty. - * - *

If you are overriding this method with your own custom content, - * consider including the standard layout {@link android.R.layout#list_content} - * in your layout file, so that you continue to retain all of the standard - * behavior of ListFragment. In particular, this is currently the only - * way to have the built-in indeterminant progress state be shown. - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - final Context context = getActivity(); - - FrameLayout root = new FrameLayout(context); - - // ------------------------------------------------------------------ - - LinearLayout pframe = new LinearLayout(context); - pframe.setId(INTERNAL_PROGRESS_CONTAINER_ID); - pframe.setOrientation(LinearLayout.VERTICAL); - pframe.setVisibility(View.GONE); - pframe.setGravity(Gravity.CENTER); - - ProgressBar progress = new ProgressBar(context, null, - android.R.attr.progressBarStyleLarge); - pframe.addView(progress, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - - root.addView(pframe, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - - // ------------------------------------------------------------------ - - FrameLayout lframe = new FrameLayout(context); - lframe.setId(INTERNAL_LIST_CONTAINER_ID); - - TextView tv = new TextView(context); - tv.setId(INTERNAL_EMPTY_ID); - tv.setGravity(Gravity.CENTER); - lframe.addView(tv, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - - ListView lv = new ListView(context); - lv.setId(android.R.id.list); - lv.setDrawSelectorOnTop(false); - lframe.addView(lv, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - - root.addView(lframe, new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - - // ------------------------------------------------------------------ - - root.setLayoutParams(new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); - - return root; - } - - /** - * Attach to list view once the view hierarchy has been created. - */ - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - ensureList(); - } - - /** - * Detach from list view. - */ - @Override - public void onDestroyView() { - mHandler.removeCallbacks(mRequestFocus); - mList = null; - mListShown = false; - mEmptyView = mProgressContainer = mListContainer = null; - mStandardEmptyView = null; - super.onDestroyView(); - } - - /** - * This method will be called when an item in the list is selected. - * Subclasses should override. Subclasses can call - * getListView().getItemAtPosition(position) if they need to access the - * data associated with the selected item. - * - * @param l The ListView where the click happened - * @param v The view that was clicked within the ListView - * @param position The position of the view in the list - * @param id The row id of the item that was clicked - */ - public void onListItemClick(ListView l, View v, int position, long id) { - } - - /** - * Provide the cursor for the list view. - */ - public void setListAdapter(ListAdapter adapter) { - boolean hadAdapter = mAdapter != null; - mAdapter = adapter; - if (mList != null) { - mList.setAdapter(adapter); - if (!mListShown && !hadAdapter) { - // The list was hidden, and previously didn't have an - // adapter. It is now time to show it. - setListShown(true, getView().getWindowToken() != null); - } - } - } - - /** - * Set the currently selected list item to the specified - * position with the adapter's data - * - * @param position - */ - public void setSelection(int position) { - ensureList(); - mList.setSelection(position); - } - - /** - * Get the position of the currently selected list item. - */ - public int getSelectedItemPosition() { - ensureList(); - return mList.getSelectedItemPosition(); - } - - /** - * Get the cursor row ID of the currently selected list item. - */ - public long getSelectedItemId() { - ensureList(); - return mList.getSelectedItemId(); - } - - /** - * Get the activity's list view widget. - */ - public ListView getListView() { - ensureList(); - return mList; - } - - /** - * The default content for a ListFragment has a TextView that can - * be shown when the list is empty. If you would like to have it - * shown, call this method to supply the text it should use. - */ - public void setEmptyText(CharSequence text) { - ensureList(); - if (mStandardEmptyView == null) { - throw new IllegalStateException("Can't be used with a custom content view"); - } - mStandardEmptyView.setText(text); - if (mEmptyText == null) { - mList.setEmptyView(mStandardEmptyView); - } - mEmptyText = text; - } - - /** - * Control whether the list is being displayed. You can make it not - * displayed if you are waiting for the initial data to show in it. During - * this time an indeterminant progress indicator will be shown instead. - * - *

Applications do not normally need to use this themselves. The default - * behavior of ListFragment is to start with the list not being shown, only - * showing it once an adapter is given with {@link #setListAdapter(ListAdapter)}. - * If the list at that point had not been shown, when it does get shown - * it will be do without the user ever seeing the hidden state. - * - * @param shown If true, the list view is shown; if false, the progress - * indicator. The initial value is true. - */ - public void setListShown(boolean shown) { - setListShown(shown, true); - } - - /** - * Like {@link #setListShown(boolean)}, but no animation is used when - * transitioning from the previous state. - */ - public void setListShownNoAnimation(boolean shown) { - setListShown(shown, false); - } - - /** - * Control whether the list is being displayed. You can make it not - * displayed if you are waiting for the initial data to show in it. During - * this time an indeterminant progress indicator will be shown instead. - * - * @param shown If true, the list view is shown; if false, the progress - * indicator. The initial value is true. - * @param animate If true, an animation will be used to transition to the - * new state. - */ - private void setListShown(boolean shown, boolean animate) { - ensureList(); - if (mProgressContainer == null) { - throw new IllegalStateException("Can't be used with a custom content view"); - } - if (mListShown == shown) { - return; - } - mListShown = shown; - if (shown) { - if (animate) { - mProgressContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_out)); - mListContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_in)); - } else { - mProgressContainer.clearAnimation(); - mListContainer.clearAnimation(); - } - mProgressContainer.setVisibility(View.GONE); - mListContainer.setVisibility(View.VISIBLE); - } else { - if (animate) { - mProgressContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_in)); - mListContainer.startAnimation(AnimationUtils.loadAnimation( - getActivity(), android.R.anim.fade_out)); - } else { - mProgressContainer.clearAnimation(); - mListContainer.clearAnimation(); - } - mProgressContainer.setVisibility(View.VISIBLE); - mListContainer.setVisibility(View.GONE); - } - } - - /** - * Get the ListAdapter associated with this activity's ListView. - */ - public ListAdapter getListAdapter() { - return mAdapter; - } - - private void ensureList() { - if (mList != null) { - return; - } - View root = getView(); - if (root == null) { - throw new IllegalStateException("Content view not yet created"); - } - if (root instanceof ListView) { - mList = (ListView)root; - } else { - mStandardEmptyView = (TextView)root.findViewById(INTERNAL_EMPTY_ID); - if (mStandardEmptyView == null) { - mEmptyView = root.findViewById(android.R.id.empty); - } else { - mStandardEmptyView.setVisibility(View.GONE); - } - mProgressContainer = root.findViewById(INTERNAL_PROGRESS_CONTAINER_ID); - mListContainer = root.findViewById(INTERNAL_LIST_CONTAINER_ID); - View rawListView = root.findViewById(android.R.id.list); - if (!(rawListView instanceof ListView)) { - if (rawListView == null) { - throw new RuntimeException( - "Your content must have a ListView whose id attribute is " + - "'android.R.id.list'"); - } - throw new RuntimeException( - "Content has view with id attribute 'android.R.id.list' " - + "that is not a ListView class"); - } - mList = (ListView)rawListView; - if (mEmptyView != null) { - mList.setEmptyView(mEmptyView); - } else if (mEmptyText != null) { - mStandardEmptyView.setText(mEmptyText); - mList.setEmptyView(mStandardEmptyView); - } - } - mListShown = true; - mList.setOnItemClickListener(mOnClickListener); - if (mAdapter != null) { - ListAdapter adapter = mAdapter; - mAdapter = null; - setListAdapter(adapter); - } else { - // We are starting without an adapter, so assume we won't - // have our data right away and start with the progress indicator. - if (mProgressContainer != null) { - setListShown(false, false); - } - } - mHandler.post(mRequestFocus); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/LoaderManager.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/LoaderManager.java deleted file mode 100644 index 69258ce8..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/LoaderManager.java +++ /dev/null @@ -1,803 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -import android.os.Bundle; -import android.support.v4.content.Loader; -import android.support.v4.util.DebugUtils; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.lang.reflect.Modifier; - -/** - * Static library support version of the framework's {@link android.app.LoaderManager}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - * - *

Your activity must derive from {@link FragmentActivity} to use this. - */ -public abstract class LoaderManager { - /** - * Callback interface for a client to interact with the manager. - */ - public interface LoaderCallbacks { - /** - * Instantiate and return a new Loader for the given ID. - * - * @param id The ID whose loader is to be created. - * @param args Any arguments supplied by the caller. - * @return Return a new Loader instance that is ready to start loading. - */ - public Loader onCreateLoader(int id, Bundle args); - - /** - * Called when a previously created loader has finished its load. Note - * that normally an application is not allowed to commit fragment - * transactions while in this call, since it can happen after an - * activity's state is saved. See {@link FragmentManager#beginTransaction() - * FragmentManager.openTransaction()} for further discussion on this. - * - *

This function is guaranteed to be called prior to the release of - * the last data that was supplied for this Loader. At this point - * you should remove all use of the old data (since it will be released - * soon), but should not do your own release of the data since its Loader - * owns it and will take care of that. The Loader will take care of - * management of its data so you don't have to. In particular: - * - *

    - *
  • The Loader will monitor for changes to the data, and report - * them to you through new calls here. You should not monitor the - * data yourself. For example, if the data is a {@link android.database.Cursor} - * and you place it in a {@link android.widget.CursorAdapter}, use - * the {@link android.widget.CursorAdapter#CursorAdapter(android.content.Context, - * android.database.Cursor, int)} constructor without passing - * in either {@link android.widget.CursorAdapter#FLAG_AUTO_REQUERY} - * or {@link android.widget.CursorAdapter#FLAG_REGISTER_CONTENT_OBSERVER} - * (that is, use 0 for the flags argument). This prevents the CursorAdapter - * from doing its own observing of the Cursor, which is not needed since - * when a change happens you will get a new Cursor throw another call - * here. - *

  • The Loader will release the data once it knows the application - * is no longer using it. For example, if the data is - * a {@link android.database.Cursor} from a {@link android.content.CursorLoader}, - * you should not call close() on it yourself. If the Cursor is being placed in a - * {@link android.widget.CursorAdapter}, you should use the - * {@link android.widget.CursorAdapter#swapCursor(android.database.Cursor)} - * method so that the old Cursor is not closed. - *
- * - * @param loader The Loader that has finished. - * @param data The data generated by the Loader. - */ - public void onLoadFinished(Loader loader, D data); - - /** - * Called when a previously created loader is being reset, and thus - * making its data unavailable. The application should at this point - * remove any references it has to the Loader's data. - * - * @param loader The Loader that is being reset. - */ - public void onLoaderReset(Loader loader); - } - - /** - * Ensures a loader is initialized and active. If the loader doesn't - * already exist, one is created and (if the activity/fragment is currently - * started) starts the loader. Otherwise the last created - * loader is re-used. - * - *

In either case, the given callback is associated with the loader, and - * will be called as the loader state changes. If at the point of call - * the caller is in its started state, and the requested loader - * already exists and has generated its data, then - * callback {@link LoaderCallbacks#onLoadFinished} will - * be called immediately (inside of this function), so you must be prepared - * for this to happen. - * - * @param id A unique identifier for this loader. Can be whatever you want. - * Identifiers are scoped to a particular LoaderManager instance. - * @param args Optional arguments to supply to the loader at construction. - * If a loader already exists (a new one does not need to be created), this - * parameter will be ignored and the last arguments continue to be used. - * @param callback Interface the LoaderManager will call to report about - * changes in the state of the loader. Required. - */ - public abstract Loader initLoader(int id, Bundle args, - LoaderManager.LoaderCallbacks callback); - - /** - * Starts a new or restarts an existing {@link android.content.Loader} in - * this manager, registers the callbacks to it, - * and (if the activity/fragment is currently started) starts loading it. - * If a loader with the same id has previously been - * started it will automatically be destroyed when the new loader completes - * its work. The callback will be delivered before the old loader - * is destroyed. - * - * @param id A unique identifier for this loader. Can be whatever you want. - * Identifiers are scoped to a particular LoaderManager instance. - * @param args Optional arguments to supply to the loader at construction. - * @param callback Interface the LoaderManager will call to report about - * changes in the state of the loader. Required. - */ - public abstract Loader restartLoader(int id, Bundle args, - LoaderManager.LoaderCallbacks callback); - - /** - * Stops and removes the loader with the given ID. If this loader - * had previously reported data to the client through - * {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, a call - * will be made to {@link LoaderCallbacks#onLoaderReset(Loader)}. - */ - public abstract void destroyLoader(int id); - - /** - * Return the Loader with the given id or null if no matching Loader - * is found. - */ - public abstract Loader getLoader(int id); - - /** - * Print the LoaderManager's state into the given stream. - * - * @param prefix Text to print at the front of each line. - * @param fd The raw file descriptor that the dump is being sent to. - * @param writer A PrintWriter to which the dump is to be set. - * @param args Additional arguments to the dump request. - */ - public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args); - - /** - * Control whether the framework's internal loader manager debugging - * logs are turned on. If enabled, you will see output in logcat as - * the framework performs loader operations. - */ - public static void enableDebugLogging(boolean enabled) { - LoaderManagerImpl.DEBUG = enabled; - } -} - -class LoaderManagerImpl extends LoaderManager { - static final String TAG = "LoaderManager"; - static boolean DEBUG = false; - - // These are the currently active loaders. A loader is here - // from the time its load is started until it has been explicitly - // stopped or restarted by the application. - final HCSparseArray mLoaders = new HCSparseArray(); - - // These are previously run loaders. This list is maintained internally - // to avoid destroying a loader while an application is still using it. - // It allows an application to restart a loader, but continue using its - // previously run loader until the new loader's data is available. - final HCSparseArray mInactiveLoaders = new HCSparseArray(); - - SupportActivity mActivity; - boolean mStarted; - boolean mRetaining; - boolean mRetainingStarted; - - boolean mCreatingLoader; - - final class LoaderInfo implements Loader.OnLoadCompleteListener { - final int mId; - final Bundle mArgs; - LoaderManager.LoaderCallbacks mCallbacks; - Loader mLoader; - boolean mHaveData; - boolean mDeliveredData; - Object mData; - boolean mStarted; - boolean mRetaining; - boolean mRetainingStarted; - boolean mReportNextStart; - boolean mDestroyed; - boolean mListenerRegistered; - - LoaderInfo mPendingLoader; - - public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks callbacks) { - mId = id; - mArgs = args; - mCallbacks = callbacks; - } - - void start() { - if (mRetaining && mRetainingStarted) { - // Our owner is started, but we were being retained from a - // previous instance in the started state... so there is really - // nothing to do here, since the loaders are still started. - mStarted = true; - return; - } - - if (mStarted) { - // If loader already started, don't restart. - return; - } - - mStarted = true; - - if (DEBUG) Log.v(TAG, " Starting: " + this); - if (mLoader == null && mCallbacks != null) { - mLoader = mCallbacks.onCreateLoader(mId, mArgs); - } - if (mLoader != null) { - if (mLoader.getClass().isMemberClass() - && !Modifier.isStatic(mLoader.getClass().getModifiers())) { - throw new IllegalArgumentException( - "Object returned from onCreateLoader must not be a non-static inner member class: " - + mLoader); - } - if (!mListenerRegistered) { - mLoader.registerListener(mId, this); - mListenerRegistered = true; - } - mLoader.startLoading(); - } - } - - void retain() { - if (DEBUG) Log.v(TAG, " Retaining: " + this); - mRetaining = true; - mRetainingStarted = mStarted; - mStarted = false; - mCallbacks = null; - } - - void finishRetain() { - if (mRetaining) { - if (DEBUG) Log.v(TAG, " Finished Retaining: " + this); - mRetaining = false; - if (mStarted != mRetainingStarted) { - if (!mStarted) { - // This loader was retained in a started state, but - // at the end of retaining everything our owner is - // no longer started... so make it stop. - stop(); - } - } - } - - if (mStarted && mHaveData && !mReportNextStart) { - // This loader has retained its data, either completely across - // a configuration change or just whatever the last data set - // was after being restarted from a stop, and now at the point of - // finishing the retain we find we remain started, have - // our data, and the owner has a new callback... so - // let's deliver the data now. - callOnLoadFinished(mLoader, mData); - } - } - - void reportStart() { - if (mStarted) { - if (mReportNextStart) { - mReportNextStart = false; - if (mHaveData) { - callOnLoadFinished(mLoader, mData); - } - } - } - } - - void stop() { - if (DEBUG) Log.v(TAG, " Stopping: " + this); - mStarted = false; - if (!mRetaining) { - if (mLoader != null && mListenerRegistered) { - // Let the loader know we're done with it - mListenerRegistered = false; - mLoader.unregisterListener(this); - mLoader.stopLoading(); - } - } - } - - void destroy() { - if (DEBUG) Log.v(TAG, " Destroying: " + this); - mDestroyed = true; - boolean needReset = mDeliveredData; - mDeliveredData = false; - if (mCallbacks != null && mLoader != null && mHaveData && needReset) { - if (DEBUG) Log.v(TAG, " Reseting: " + this); - String lastBecause = null; - if (mActivity != null) { - lastBecause = mActivity.getInternalCallbacks().getFragments().mNoTransactionsBecause; - mActivity.getInternalCallbacks().getFragments().mNoTransactionsBecause = "onLoaderReset"; - } - try { - mCallbacks.onLoaderReset(mLoader); - } finally { - if (mActivity != null) { - mActivity.getInternalCallbacks().getFragments().mNoTransactionsBecause = lastBecause; - } - } - } - mCallbacks = null; - mData = null; - mHaveData = false; - if (mLoader != null) { - if (mListenerRegistered) { - mListenerRegistered = false; - mLoader.unregisterListener(this); - } - mLoader.reset(); - } - if (mPendingLoader != null) { - mPendingLoader.destroy(); - } - } - - @Override public void onLoadComplete(Loader loader, Object data) { - if (DEBUG) Log.v(TAG, "onLoadComplete: " + this); - - if (mDestroyed) { - if (DEBUG) Log.v(TAG, " Ignoring load complete -- destroyed"); - return; - } - - if (mLoaders.get(mId) != this) { - // This data is not coming from the current active loader. - // We don't care about it. - if (DEBUG) Log.v(TAG, " Ignoring load complete -- not active"); - return; - } - - LoaderInfo pending = mPendingLoader; - if (pending != null) { - // There is a new request pending and we were just - // waiting for the old one to complete before starting - // it. So now it is time, switch over to the new loader. - if (DEBUG) Log.v(TAG, " Switching to pending loader: " + pending); - mPendingLoader = null; - mLoaders.put(mId, null); - destroy(); - installLoader(pending); - return; - } - - // Notify of the new data so the app can switch out the old data before - // we try to destroy it. - if (mData != data || !mHaveData) { - mData = data; - mHaveData = true; - if (mStarted) { - callOnLoadFinished(loader, data); - } - } - - //if (DEBUG) Log.v(TAG, " onLoadFinished returned: " + this); - - // We have now given the application the new loader with its - // loaded data, so it should have stopped using the previous - // loader. If there is a previous loader on the inactive list, - // clean it up. - LoaderInfo info = mInactiveLoaders.get(mId); - if (info != null && info != this) { - info.mDeliveredData = false; - info.destroy(); - mInactiveLoaders.remove(mId); - } - } - - void callOnLoadFinished(Loader loader, Object data) { - if (mCallbacks != null) { - String lastBecause = null; - if (mActivity != null) { - lastBecause = mActivity.getInternalCallbacks().getFragments().mNoTransactionsBecause; - mActivity.getInternalCallbacks().getFragments().mNoTransactionsBecause = "onLoadFinished"; - } - try { - if (DEBUG) Log.v(TAG, " onLoadFinished in " + loader + ": " - + loader.dataToString(data)); - mCallbacks.onLoadFinished(loader, data); - } finally { - if (mActivity != null) { - mActivity.getInternalCallbacks().getFragments().mNoTransactionsBecause = lastBecause; - } - } - mDeliveredData = true; - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(64); - sb.append("LoaderInfo{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(" #"); - sb.append(mId); - sb.append(" : "); - DebugUtils.buildShortClassTag(mLoader, sb); - sb.append("}}"); - return sb.toString(); - } - - public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { - writer.print(prefix); writer.print("mId="); writer.print(mId); - writer.print(" mArgs="); writer.println(mArgs); - writer.print(prefix); writer.print("mCallbacks="); writer.println(mCallbacks); - writer.print(prefix); writer.print("mLoader="); writer.println(mLoader); - if (mLoader != null) { - mLoader.dump(prefix + " ", fd, writer, args); - } - if (mHaveData || mDeliveredData) { - writer.print(prefix); writer.print("mHaveData="); writer.print(mHaveData); - writer.print(" mDeliveredData="); writer.println(mDeliveredData); - writer.print(prefix); writer.print("mData="); writer.println(mData); - } - writer.print(prefix); writer.print("mStarted="); writer.print(mStarted); - writer.print(" mReportNextStart="); writer.print(mReportNextStart); - writer.print(" mDestroyed="); writer.println(mDestroyed); - writer.print(prefix); writer.print("mRetaining="); writer.print(mRetaining); - writer.print(" mRetainingStarted="); writer.print(mRetainingStarted); - writer.print(" mListenerRegistered="); writer.println(mListenerRegistered); - if (mPendingLoader != null) { - writer.print(prefix); writer.println("Pending Loader "); - writer.print(mPendingLoader); writer.println(":"); - mPendingLoader.dump(prefix + " ", fd, writer, args); - } - } - } - - LoaderManagerImpl(SupportActivity activity, boolean started) { - mActivity = activity; - mStarted = started; - } - - void updateActivity(SupportActivity activity) { - mActivity = activity; - } - - private LoaderInfo createLoader(int id, Bundle args, - LoaderManager.LoaderCallbacks callback) { - LoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacks)callback); - Loader loader = callback.onCreateLoader(id, args); - info.mLoader = (Loader)loader; - return info; - } - - private LoaderInfo createAndInstallLoader(int id, Bundle args, - LoaderManager.LoaderCallbacks callback) { - try { - mCreatingLoader = true; - LoaderInfo info = createLoader(id, args, callback); - installLoader(info); - return info; - } finally { - mCreatingLoader = false; - } - } - - void installLoader(LoaderInfo info) { - mLoaders.put(info.mId, info); - if (mStarted) { - // The activity will start all existing loaders in it's onStart(), - // so only start them here if we're past that point of the activitiy's - // life cycle - info.start(); - } - } - - /** - * Call to initialize a particular ID with a Loader. If this ID already - * has a Loader associated with it, it is left unchanged and any previous - * callbacks replaced with the newly provided ones. If there is not currently - * a Loader for the ID, a new one is created and started. - * - *

This function should generally be used when a component is initializing, - * to ensure that a Loader it relies on is created. This allows it to re-use - * an existing Loader's data if there already is one, so that for example - * when an {@link Activity} is re-created after a configuration change it - * does not need to re-create its loaders. - * - *

Note that in the case where an existing Loader is re-used, the - * args given here will be ignored because you will - * continue using the previous Loader. - * - * @param id A unique (to this LoaderManager instance) identifier under - * which to manage the new Loader. - * @param args Optional arguments that will be propagated to - * {@link LoaderCallbacks#onCreateLoader(int, Bundle) LoaderCallbacks.onCreateLoader()}. - * @param callback Interface implementing management of this Loader. Required. - * Its onCreateLoader() method will be called while inside of the function to - * instantiate the Loader object. - */ - @SuppressWarnings("unchecked") - public Loader initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks callback) { - if (mCreatingLoader) { - throw new IllegalStateException("Called while creating a loader"); - } - - LoaderInfo info = mLoaders.get(id); - - if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args); - - if (info == null) { - // Loader doesn't already exist; create. - info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks)callback); - if (DEBUG) Log.v(TAG, " Created new loader " + info); - } else { - if (DEBUG) Log.v(TAG, " Re-using existing loader " + info); - info.mCallbacks = (LoaderManager.LoaderCallbacks)callback; - } - - if (info.mHaveData && mStarted) { - // If the loader has already generated its data, report it now. - info.callOnLoadFinished(info.mLoader, info.mData); - } - - return (Loader)info.mLoader; - } - - /** - * Call to re-create the Loader associated with a particular ID. If there - * is currently a Loader associated with this ID, it will be - * canceled/stopped/destroyed as appropriate. A new Loader with the given - * arguments will be created and its data delivered to you once available. - * - *

This function does some throttling of Loaders. If too many Loaders - * have been created for the given ID but not yet generated their data, - * new calls to this function will create and return a new Loader but not - * actually start it until some previous loaders have completed. - * - *

After calling this function, any previous Loaders associated with - * this ID will be considered invalid, and you will receive no further - * data updates from them. - * - * @param id A unique (to this LoaderManager instance) identifier under - * which to manage the new Loader. - * @param args Optional arguments that will be propagated to - * {@link LoaderCallbacks#onCreateLoader(int, Bundle) LoaderCallbacks.onCreateLoader()}. - * @param callback Interface implementing management of this Loader. Required. - * Its onCreateLoader() method will be called while inside of the function to - * instantiate the Loader object. - */ - @SuppressWarnings("unchecked") - public Loader restartLoader(int id, Bundle args, LoaderManager.LoaderCallbacks callback) { - if (mCreatingLoader) { - throw new IllegalStateException("Called while creating a loader"); - } - - LoaderInfo info = mLoaders.get(id); - if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args); - if (info != null) { - LoaderInfo inactive = mInactiveLoaders.get(id); - if (inactive != null) { - if (info.mHaveData) { - // This loader now has data... we are probably being - // called from within onLoadComplete, where we haven't - // yet destroyed the last inactive loader. So just do - // that now. - if (DEBUG) Log.v(TAG, " Removing last inactive loader: " + info); - inactive.mDeliveredData = false; - inactive.destroy(); - info.mLoader.abandon(); - mInactiveLoaders.put(id, info); - } else { - // We already have an inactive loader for this ID that we are - // waiting for! What to do, what to do... - if (!info.mStarted) { - // The current Loader has not been started... we thus - // have no reason to keep it around, so bam, slam, - // thank-you-ma'am. - if (DEBUG) Log.v(TAG, " Current loader is stopped; replacing"); - mLoaders.put(id, null); - info.destroy(); - } else { - // Now we have three active loaders... we'll queue - // up this request to be processed once one of the other loaders - // finishes. - if (info.mPendingLoader != null) { - if (DEBUG) Log.v(TAG, " Removing pending loader: " + info.mPendingLoader); - info.mPendingLoader.destroy(); - info.mPendingLoader = null; - } - if (DEBUG) Log.v(TAG, " Enqueuing as new pending loader"); - info.mPendingLoader = createLoader(id, args, - (LoaderManager.LoaderCallbacks)callback); - return (Loader)info.mPendingLoader.mLoader; - } - } - } else { - // Keep track of the previous instance of this loader so we can destroy - // it when the new one completes. - if (DEBUG) Log.v(TAG, " Making last loader inactive: " + info); - info.mLoader.abandon(); - mInactiveLoaders.put(id, info); - } - } - - info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks)callback); - return (Loader)info.mLoader; - } - - /** - * Rip down, tear apart, shred to pieces a current Loader ID. After returning - * from this function, any Loader objects associated with this ID are - * destroyed. Any data associated with them is destroyed. You better not - * be using it when you do this. - * @param id Identifier of the Loader to be destroyed. - */ - public void destroyLoader(int id) { - if (mCreatingLoader) { - throw new IllegalStateException("Called while creating a loader"); - } - - if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id); - int idx = mLoaders.indexOfKey(id); - if (idx >= 0) { - LoaderInfo info = mLoaders.valueAt(idx); - mLoaders.removeAt(idx); - info.destroy(); - } - idx = mInactiveLoaders.indexOfKey(id); - if (idx >= 0) { - LoaderInfo info = mInactiveLoaders.valueAt(idx); - mInactiveLoaders.removeAt(idx); - info.destroy(); - } - } - - /** - * Return the most recent Loader object associated with the - * given ID. - */ - @SuppressWarnings("unchecked") - public Loader getLoader(int id) { - if (mCreatingLoader) { - throw new IllegalStateException("Called while creating a loader"); - } - - LoaderInfo loaderInfo = mLoaders.get(id); - if (loaderInfo != null) { - if (loaderInfo.mPendingLoader != null) { - return (Loader)loaderInfo.mPendingLoader.mLoader; - } - return (Loader)loaderInfo.mLoader; - } - return null; - } - - void doStart() { - if (DEBUG) Log.v(TAG, "Starting in " + this); - if (mStarted) { - RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); - Log.w(TAG, "Called doStart when already started: " + this, e); - return; - } - - mStarted = true; - - // Call out to sub classes so they can start their loaders - // Let the existing loaders know that we want to be notified when a load is complete - for (int i = mLoaders.size()-1; i >= 0; i--) { - mLoaders.valueAt(i).start(); - } - } - - void doStop() { - if (DEBUG) Log.v(TAG, "Stopping in " + this); - if (!mStarted) { - RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); - Log.w(TAG, "Called doStop when not started: " + this, e); - return; - } - - for (int i = mLoaders.size()-1; i >= 0; i--) { - mLoaders.valueAt(i).stop(); - } - mStarted = false; - } - - void doRetain() { - if (DEBUG) Log.v(TAG, "Retaining in " + this); - if (!mStarted) { - RuntimeException e = new RuntimeException("here"); - e.fillInStackTrace(); - Log.w(TAG, "Called doRetain when not started: " + this, e); - return; - } - - mRetaining = true; - mStarted = false; - for (int i = mLoaders.size()-1; i >= 0; i--) { - mLoaders.valueAt(i).retain(); - } - } - - void finishRetain() { - if (mRetaining) { - if (DEBUG) Log.v(TAG, "Finished Retaining in " + this); - - mRetaining = false; - for (int i = mLoaders.size()-1; i >= 0; i--) { - mLoaders.valueAt(i).finishRetain(); - } - } - } - - void doReportNextStart() { - for (int i = mLoaders.size()-1; i >= 0; i--) { - mLoaders.valueAt(i).mReportNextStart = true; - } - } - - void doReportStart() { - for (int i = mLoaders.size()-1; i >= 0; i--) { - mLoaders.valueAt(i).reportStart(); - } - } - - void doDestroy() { - if (!mRetaining) { - if (DEBUG) Log.v(TAG, "Destroying Active in " + this); - for (int i = mLoaders.size()-1; i >= 0; i--) { - mLoaders.valueAt(i).destroy(); - } - } - - if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this); - for (int i = mInactiveLoaders.size()-1; i >= 0; i--) { - mInactiveLoaders.valueAt(i).destroy(); - } - mInactiveLoaders.clear(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(128); - sb.append("LoaderManager{"); - sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(" in "); - DebugUtils.buildShortClassTag(mActivity, sb); - sb.append("}}"); - return sb.toString(); - } - - @Override - public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { - if (mLoaders.size() > 0) { - writer.print(prefix); writer.println("Active Loaders:"); - String innerPrefix = prefix + " "; - for (int i=0; i < mLoaders.size(); i++) { - LoaderInfo li = mLoaders.valueAt(i); - writer.print(prefix); writer.print(" #"); writer.print(mLoaders.keyAt(i)); - writer.print(": "); writer.println(li.toString()); - li.dump(innerPrefix, fd, writer, args); - } - } - if (mInactiveLoaders.size() > 0) { - writer.print(prefix); writer.println("Inactive Loaders:"); - String innerPrefix = prefix + " "; - for (int i=0; i < mInactiveLoaders.size(); i++) { - LoaderInfo li = mInactiveLoaders.valueAt(i); - writer.print(prefix); writer.print(" #"); writer.print(mInactiveLoaders.keyAt(i)); - writer.print(": "); writer.println(li.toString()); - li.dump(innerPrefix, fd, writer, args); - } - } - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/NoSaveStateFrameLayout.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/NoSaveStateFrameLayout.java deleted file mode 100644 index a2177e32..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/NoSaveStateFrameLayout.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -import android.content.Context; -import android.os.Parcelable; -import android.util.SparseArray; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; - -/** - * Pre-Honeycomb versions of the platform don't have View.setSaveFromParentEnabled(), - * so instead we insert this between the view and its parent. - */ -public class NoSaveStateFrameLayout extends FrameLayout { - static ViewGroup wrap(View child) { - NoSaveStateFrameLayout wrapper = new NoSaveStateFrameLayout(child.getContext()); - ViewGroup.LayoutParams childParams = child.getLayoutParams(); - if (childParams != null) { - wrapper.setLayoutParams(childParams); - } - NoSaveStateFrameLayout.LayoutParams lp = new NoSaveStateFrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT); - child.setLayoutParams(lp); - wrapper.addView(child); - return wrapper; - } - - public NoSaveStateFrameLayout(Context context) { - super(context); - } - - /** - * Override to prevent freezing of any child views. - */ - @Override - protected void dispatchSaveInstanceState(SparseArray container) { - dispatchFreezeSelfOnly(container); - } - - /** - * Override to prevent thawing of any child views. - */ - @Override - protected void dispatchRestoreInstanceState(SparseArray container) { - dispatchThawSelfOnly(container); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/SuperNotCalledException.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/SuperNotCalledException.java deleted file mode 100644 index d306b965..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/SuperNotCalledException.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.app; - -import android.util.AndroidRuntimeException; - -final class SuperNotCalledException extends AndroidRuntimeException { - private static final long serialVersionUID = -5247191382770859874L; - - public SuperNotCalledException(String msg) { - super(msg); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/SupportActivity.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/SupportActivity.java deleted file mode 100644 index 3d956684..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/SupportActivity.java +++ /dev/null @@ -1,295 +0,0 @@ -package android.support.v4.app; - -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import android.app.Activity; -import android.app.Application; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.content.SharedPreferences; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.AssetManager; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.support.v4.view.ActionMode; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuItem; -import android.util.AttributeSet; -import android.view.ContextMenu; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.MenuInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.view.accessibility.AccessibilityEvent; - -/** - *

Instances of this interface represent an activity provided by the support - * library (e.g., {@link FragmentActivity}).

- * - *

Provided are all of the methods which would be available if you were - * accessing the underlying activity directly and you can safely assume that - * any instances of this interface can be cast to an {@link Activity}. It is - * preferred, however, that you call {@link #asActivity()} instead.

- */ -public interface SupportActivity { - public static abstract class InternalCallbacks { - abstract void ensureSupportActionBarAttached(); - abstract Handler getHandler(); - abstract FragmentManagerImpl getFragments(); - abstract LoaderManagerImpl getLoaderManager(int index, boolean started, boolean create); - abstract void invalidateSupportFragmentIndex(int index); - } - - InternalCallbacks getInternalCallbacks(); - Activity asActivity(); - - /*** Activity methods ***/ - void addContentView(View view, ViewGroup.LayoutParams params); - void closeContextMenu(); - void closeOptionsMenu(); - PendingIntent createPendingResult(int requestCode, Intent data, int flags); - void dismissDialog(int id); - boolean dispatchKeyEvent(KeyEvent event); - boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event); - boolean dispatchTouchEvent(MotionEvent ev); - boolean dispatchTrackballEvent(MotionEvent ev); - View findViewById(int id); - void finish(); - void finishActivity(int requestCode); - void finishActivityFromChild(Activity child, int requestCode); - void finishFromChild(Activity child); - Application getApplication(); - ComponentName getCallingActivity(); - String getCallingPackage(); - int getChangingConfigurations(); - ComponentName getComponentName(); - View getCurrentFocus(); - Intent getIntent(); - Object getLastNonConfigurationInstance(); - LayoutInflater getLayoutInflater(); - String getLocalClassName(); - MenuInflater getMenuInflater(); - Activity getParent(); - SharedPreferences getPreferences(int mode); - int getRequestedOrientation(); - Object getSystemService(String name); - int getTaskId(); - CharSequence getTitle(); - int getTitleColor(); - int getVolumeControlStream(); - Window getWindow(); - WindowManager getWindowManager(); - boolean hasWindowFocus(); - boolean isChild(); - boolean isFinishing(); - boolean isTaskRoot(); - Cursor managedQuery(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder); - boolean moveTaskToBack(boolean nonRoot); - void onConfigurationChanged(Configuration newConfig); - void onContentChanged(); - boolean onContextItemSelected(android.view.MenuItem item); - void onContextMenuClosed(android.view.Menu menu); - void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo); - CharSequence onCreateDescription(); - boolean onCreateOptionsMenu(android.view.Menu menu); - boolean onCreatePanelMenu(int featureId, android.view.Menu menu); - View onCreatePanelView(int featureId); - boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas); - View onCreateView(String name, Context context, AttributeSet attrs); - boolean onKeyDown(int keyCode, KeyEvent event); - boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event); - boolean onKeyUp(int keyCode, KeyEvent event); - void onLowMemory(); - boolean onMenuItemSelected(int featureId, android.view.MenuItem item); - boolean onMenuOpened(int featureId, android.view.Menu menu); - boolean onOptionsItemSelected(android.view.MenuItem item); - void onOptionsMenuClosed(android.view.Menu menu); - void onPanelClosed(int featureId, android.view.Menu menu); - boolean onPrepareOptionsMenu(android.view.Menu menu); - boolean onPreparePanel(int featureId, View view, android.view.Menu menu); - Object onRetainNonConfigurationInstance(); - boolean onSearchRequested(); - boolean onTouchEvent(MotionEvent event); - boolean onTrackballEvent(MotionEvent event); - void onUserInteraction(); - void onWindowAttributesChanged(WindowManager.LayoutParams params); - void onWindowFocusChanged(boolean hasFocus); - void openContextMenu(View view); - void openOptionsMenu(); - void registerForContextMenu(View view); - void removeDialog(int id); - boolean requestWindowFeature(int featureId); - void runOnUiThread(Runnable action); - void setContentView(int layoutResId); - void setContentView(View view); - void setContentView(View view, ViewGroup.LayoutParams params); - void setDefaultKeyMode(int mode); - void setFeatureDrawable(int featureId, Drawable drawable); - void setFeatureDrawableAlpha(int featureId, int alpha); - void setFeatureDrawableResource(int featureId, int resId); - void setFeatureDrawableUri(int featureId, Uri uri); - void setIntent(Intent newIntent); - void setProgress(int progress); - void setProgressBarIndeterminate(boolean indeterminate); - void setProgressBarIndeterminateVisibility(boolean visible); - void setProgressBarVisibility(boolean visible); - void setRequestedOrientation(int requestedOrientation); - void setResult(int resultCode); - void setResult(int resultCode, Intent data); - void setSecondaryProgress(int secondaryProgress); - void setTitle(int titleId); - void setTitle(CharSequence title); - void setTitleColor(int textColor); - void setVisible(boolean visible); - void setVolumeControlStream(int streamType); - void showDialog(int id); - void startActivity(Intent intent); - void startActivityForResult(Intent intent, int requestCode); - void startActivityFromChild(Activity child, Intent intent, int requestCode); - boolean startActivityIfNeeded(Intent intent, int requestCode); - void startManagingCursor(Cursor c); - boolean startNextMatchingActivity(Intent intent); - void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchDate, boolean globalSearch); - void stopManagingCursor(Cursor c); - void takeKeyEvents(boolean get); - void unregisterForContextMenu(View view); - - /*** ContextThemeWrapper methods ***/ - //Object getSystemService(String name); - Resources.Theme getTheme(); - void setTheme(int resId); - - /*** ContextWrapper methods ***/ - //void attachBaseContext(Context base); - boolean bindService(Intent service, ServiceConnection conn, int flags); - int checkCallingOrSelfPermission(String permission); - int checkCallingOrSelfUriPermission(Uri uri, int modeFlags); - int checkCallingPermission(String permission); - int checkCallingUriPermission(Uri uri, int modeFlags); - int checkPermission(String permission, int pid, int uid); - int checkUriPermission(Uri uri, int pid, int uid, int modeFlags); - int checkUriPermission(Uri uri, String readPermission, String writePermission, int pid, int uid, int modeFlags); - @Deprecated void clearWallpaper() throws IOException; - Context createPackageContext(String packageName, int flags) throws NameNotFoundException; - String[] databaseList(); - boolean deleteDatabase(String name); - boolean deleteFile(String name); - void enforceCallingOrSelfPermission(String permission, String message); - void enforceCallingOrSelfUriPermission(Uri uri, int modeFlags, String message); - void enforceCallingPermission(String permission, String message); - void enforceCallingUriPermission(Uri uri, int modeFlags, String message); - void enforcePermission(String permission, int pid, int uid, String message); - void enforceUriPermission(Uri uri, int pid, int uid, int modeFlags, String message); - void enforceUriPermission(Uri uri, String readPermission, String writePermission, int pid, int uid, int modeFlags, String message); - String[] fileList(); - Context getApplicationContext(); - ApplicationInfo getApplicationInfo(); - AssetManager getAssets(); - Context getBaseContext(); - File getCacheDir(); - ClassLoader getClassLoader(); - ContentResolver getContentResolver(); - File getDatabasePath(String name); - File getDir(String name, int mode); - File getFileStreamPath(String name); - File getFilesDir(); - Looper getMainLooper(); - String getPackageCodePath(); - PackageManager getPackageManager(); - String getPackageName(); - String getPackageResourcePath(); - Resources getResources(); - SharedPreferences getSharedPreferences(String name, int mode); - //Object getSystemService(String name); - //Resources.Theme getTheme(); - Drawable getWallpaper(); - int getWallpaperDesiredMinimumHeight(); - int getWallpaperDesiredMinimumWidth(); - void grantUriPermission(String toPackage, Uri uri, int modeFlags); - boolean isRestricted(); - FileInputStream openFileInput(String name) throws FileNotFoundException; - FileOutputStream openFileOutput(String name, int mode) throws FileNotFoundException; - SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory); - @Deprecated Drawable peekWallpaper(); - Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter); - Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler); - void removeStickyBroadcast(Intent intent); - void revokeUriPermission(Uri uri, int modeFlags); - void sendBroadcast(Intent intent); - void sendBroadcast(Intent intent, String receiverPermission); - void sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras); - void sendOrderedBroadcast(Intent intent, String receiverPermission); - void sendStickyBroadcast(Intent intent); - //void setTheme(int resid); - void setWallpaper(Bitmap bitmap) throws IOException; - void setWallpaper(InputStream data) throws IOException; - //void startActivity(Intent intent); - boolean startInstrumentation(ComponentName className, String profileFile, Bundle arguments); - ComponentName startService(Intent service); - boolean stopService(Intent name); - void unbindService(ServiceConnection conn); - void unregisterReceiver(BroadcastReceiver receiver); - - /*** Context methods ***/ - String getString(int resId); - String getString(int resId, Object... formatArgs); - CharSequence getText(int resId); - //boolean isRestricted(); - TypedArray obtainStyledAttributes(int[] attrs); - TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs); - TypedArray obtainStyledAttributes(int resId, int[] attrs); - TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes); - - /*** Activity methods (emulated API 5+) ***/ - void onBackPressed(); - - /*** Activity methods (emulated API 11+) ***/ - void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args); - ActionBar getSupportActionBar(); //getActionBar() - FragmentManager getSupportFragmentManager(); //getFragmentManager() - LoaderManager getSupportLoaderManager(); //getLoaderManager() - void invalidateOptionsMenu(); - void onActionModeFinished(ActionMode mode); - void onActionModeStarted(ActionMode mode); - void onAttachFragment(Fragment fragment); - boolean onCreateOptionsMenu(Menu menu); - boolean onMenuItemSelected(int featureId, MenuItem item); - boolean onOptionsItemSelected(MenuItem item); - boolean onPrepareOptionsMenu(Menu menu); - ActionMode onWindowStartingActionMode(ActionMode.Callback callback); - void recreate(); - ActionMode startActionMode(ActionMode.Callback callback); - void startActivityFromFragment(Fragment fragment, Intent intent, int requestCode); - - /*** Parallel helper methods ***/ - boolean requestWindowFeature(long featureId); - void setProgressBarIndeterminateVisibility(Boolean visible); -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/Watson.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/Watson.java new file mode 100644 index 00000000..d93de4c6 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/app/Watson.java @@ -0,0 +1,144 @@ +package android.support.v4.app; + +import android.util.Log; +import android.view.View; +import android.view.Window; +import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener; +import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener; +import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +import java.util.ArrayList; + +/** I'm in ur package. Stealing ur variables. */ +public abstract class Watson extends FragmentActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener { + private static final boolean DEBUG = false; + private static final String TAG = "Watson"; + + /** Fragment interface for menu creation callback. */ + public interface OnCreateOptionsMenuListener { + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater); + } + /** Fragment interface for menu preparation callback. */ + public interface OnPrepareOptionsMenuListener { + public void onPrepareOptionsMenu(Menu menu); + } + /** Fragment interface for menu item selection callback. */ + public interface OnOptionsItemSelectedListener { + public boolean onOptionsItemSelected(MenuItem item); + } + + private ArrayList mCreatedMenus; + + + /////////////////////////////////////////////////////////////////////////// + // Sherlock menu handling + /////////////////////////////////////////////////////////////////////////// + + @Override + public boolean onCreatePanelMenu(int featureId, Menu menu) { + if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] featureId: " + featureId + ", menu: " + menu); + + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + boolean result = onCreateOptionsMenu(menu); + if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] activity create result: " + result); + + MenuInflater inflater = getSupportMenuInflater(); + boolean show = false; + ArrayList newMenus = null; + if (mFragments.mAdded != null) { + for (int i = 0; i < mFragments.mAdded.size(); i++) { + Fragment f = mFragments.mAdded.get(i); + if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnCreateOptionsMenuListener) { + show = true; + ((OnCreateOptionsMenuListener)f).onCreateOptionsMenu(menu, inflater); + if (newMenus == null) { + newMenus = new ArrayList(); + } + newMenus.add(f); + } + } + } + + if (mCreatedMenus != null) { + for (int i = 0; i < mCreatedMenus.size(); i++) { + Fragment f = mCreatedMenus.get(i); + if (newMenus == null || !newMenus.contains(f)) { + f.onDestroyOptionsMenu(); + } + } + } + + mCreatedMenus = newMenus; + + if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] fragments create result: " + show); + result |= show; + + if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] returning " + result); + return result; + } + return false; + } + + @Override + public boolean onPreparePanel(int featureId, View view, Menu menu) { + if (DEBUG) Log.d(TAG, "[onPreparePanel] featureId: " + featureId + ", view: " + view + " menu: " + menu); + + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + boolean result = onPrepareOptionsMenu(menu); + if (DEBUG) Log.d(TAG, "[onPreparePanel] activity prepare result: " + result); + + boolean show = false; + if (mFragments.mAdded != null) { + for (int i = 0; i < mFragments.mAdded.size(); i++) { + Fragment f = mFragments.mAdded.get(i); + if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnPrepareOptionsMenuListener) { + show = true; + ((OnPrepareOptionsMenuListener)f).onPrepareOptionsMenu(menu); + } + } + } + + if (DEBUG) Log.d(TAG, "[onPreparePanel] fragments prepare result: " + show); + result |= show; + + result &= menu.hasVisibleItems(); + if (DEBUG) Log.d(TAG, "[onPreparePanel] returning " + result); + return result; + } + return false; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + if (DEBUG) Log.d(TAG, "[onMenuItemSelected] featureId: " + featureId + ", item: " + item); + + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + if (onOptionsItemSelected(item)) { + return true; + } + + if (mFragments.mAdded != null) { + for (int i = 0; i < mFragments.mAdded.size(); i++) { + Fragment f = mFragments.mAdded.get(i); + if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnOptionsItemSelectedListener) { + if (((OnOptionsItemSelectedListener)f).onOptionsItemSelected(item)) { + return true; + } + } + } + } + } + return false; + } + + public abstract boolean onCreateOptionsMenu(Menu menu); + + public abstract boolean onPrepareOptionsMenu(Menu menu); + + public abstract boolean onOptionsItemSelected(MenuItem item); + + public abstract MenuInflater getSupportMenuInflater(); +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/AsyncTaskLoader.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/AsyncTaskLoader.java deleted file mode 100644 index 08debdd6..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/AsyncTaskLoader.java +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.content; - -import android.content.Context; -import android.os.AsyncTask; -import android.os.Handler; -import android.os.SystemClock; -import android.support.v4.util.TimeUtils; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.concurrent.CountDownLatch; - -/** - * Static library support version of the framework's {@link android.content.AsyncTaskLoader}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - */ -public abstract class AsyncTaskLoader extends Loader { - static final String TAG = "AsyncTaskLoader"; - static final boolean DEBUG = false; - - final class LoadTask extends AsyncTask implements Runnable { - - D result; - boolean waiting; - - private CountDownLatch done = new CountDownLatch(1); - - /* Runs on a worker thread */ - @Override - protected D doInBackground(Void... params) { - if (DEBUG) Log.v(TAG, this + " >>> doInBackground"); - result = AsyncTaskLoader.this.onLoadInBackground(); - if (DEBUG) Log.v(TAG, this + " <<< doInBackground"); - return result; - } - - /* Runs on the UI thread */ - @Override - protected void onPostExecute(D data) { - if (DEBUG) Log.v(TAG, this + " onPostExecute"); - try { - AsyncTaskLoader.this.dispatchOnLoadComplete(this, data); - } finally { - done.countDown(); - } - } - - @Override - protected void onCancelled() { - if (DEBUG) Log.v(TAG, this + " onCancelled"); - try { - AsyncTaskLoader.this.dispatchOnCancelled(this, result); - } finally { - done.countDown(); - } - } - - @Override - public void run() { - waiting = false; - AsyncTaskLoader.this.executePendingTask(); - } - } - - volatile LoadTask mTask; - volatile LoadTask mCancellingTask; - - long mUpdateThrottle; - long mLastLoadCompleteTime = -10000; - Handler mHandler; - - public AsyncTaskLoader(Context context) { - super(context); - } - - /** - * Set amount to throttle updates by. This is the minimum time from - * when the last {@link #onLoadInBackground()} call has completed until - * a new load is scheduled. - * - * @param delayMS Amount of delay, in milliseconds. - */ - public void setUpdateThrottle(long delayMS) { - mUpdateThrottle = delayMS; - if (delayMS != 0) { - mHandler = new Handler(); - } - } - - @Override - protected void onForceLoad() { - super.onForceLoad(); - cancelLoad(); - mTask = new LoadTask(); - if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask); - executePendingTask(); - } - - /** - * Attempt to cancel the current load task. See {@link AsyncTask#cancel(boolean)} - * for more info. Must be called on the main thread of the process. - * - *

Cancelling is not an immediate operation, since the load is performed - * in a background thread. If there is currently a load in progress, this - * method requests that the load be cancelled, and notes this is the case; - * once the background thread has completed its work its remaining state - * will be cleared. If another load request comes in during this time, - * it will be held until the cancelled load is complete. - * - * @return Returns false if the task could not be cancelled, - * typically because it has already completed normally, or - * because {@link #startLoading()} hasn't been called; returns - * true otherwise. - */ - public boolean cancelLoad() { - if (DEBUG) Log.v(TAG, "cancelLoad: mTask=" + mTask); - if (mTask != null) { - if (mCancellingTask != null) { - // There was a pending task already waiting for a previous - // one being canceled; just drop it. - if (DEBUG) Log.v(TAG, - "cancelLoad: still waiting for cancelled task; dropping next"); - if (mTask.waiting) { - mTask.waiting = false; - mHandler.removeCallbacks(mTask); - } - mTask = null; - return false; - } else if (mTask.waiting) { - // There is a task, but it is waiting for the time it should - // execute. We can just toss it. - if (DEBUG) Log.v(TAG, "cancelLoad: task is waiting, dropping it"); - mTask.waiting = false; - mHandler.removeCallbacks(mTask); - mTask = null; - return false; - } else { - boolean cancelled = mTask.cancel(false); - if (DEBUG) Log.v(TAG, "cancelLoad: cancelled=" + cancelled); - if (cancelled) { - mCancellingTask = mTask; - } - mTask = null; - return cancelled; - } - } - return false; - } - - /** - * Called if the task was canceled before it was completed. Gives the class a chance - * to properly dispose of the result. - */ - public void onCanceled(D data) { - } - - void executePendingTask() { - if (mCancellingTask == null && mTask != null) { - if (mTask.waiting) { - mTask.waiting = false; - mHandler.removeCallbacks(mTask); - } - if (mUpdateThrottle > 0) { - long now = SystemClock.uptimeMillis(); - if (now < (mLastLoadCompleteTime+mUpdateThrottle)) { - // Not yet time to do another load. - if (DEBUG) Log.v(TAG, "Waiting until " - + (mLastLoadCompleteTime+mUpdateThrottle) - + " to execute: " + mTask); - mTask.waiting = true; - mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle); - return; - } - } - if (DEBUG) Log.v(TAG, "Executing: " + mTask); - mTask.execute((Void[]) null); - // XXX TO DO: use reflection to call this version. - //mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null); - } - } - - void dispatchOnCancelled(LoadTask task, D data) { - onCanceled(data); - if (mCancellingTask == task) { - if (DEBUG) Log.v(TAG, "Cancelled task is now canceled!"); - mLastLoadCompleteTime = SystemClock.uptimeMillis(); - mCancellingTask = null; - executePendingTask(); - } - } - - void dispatchOnLoadComplete(LoadTask task, D data) { - if (mTask != task) { - if (DEBUG) Log.v(TAG, "Load complete of old task, trying to cancel"); - dispatchOnCancelled(task, data); - } else { - if (isAbandoned()) { - // This cursor has been abandoned; just cancel the new data. - onCanceled(data); - } else { - mLastLoadCompleteTime = SystemClock.uptimeMillis(); - mTask = null; - if (DEBUG) Log.v(TAG, "Delivering result"); - deliverResult(data); - } - } - } - - /** - */ - public abstract D loadInBackground(); - - /** - * Called on a worker thread to perform the actual load. Implementations should not deliver the - * result directly, but should return them from this method, which will eventually end up - * calling {@link #deliverResult} on the UI thread. If implementations need to process - * the results on the UI thread they may override {@link #deliverResult} and do so - * there. - * - * @return Implementations must return the result of their load operation. - */ - protected D onLoadInBackground() { - return loadInBackground(); - } - - /** - * Locks the current thread until the loader completes the current load - * operation. Returns immediately if there is no load operation running. - * Should not be called from the UI thread: calling it from the UI - * thread would cause a deadlock. - *

- * Use for testing only. Never call this from a UI thread. - * - * @hide - */ - public void waitForLoader() { - LoadTask task = mTask; - if (task != null) { - try { - task.done.await(); - } catch (InterruptedException e) { - // Ignore - } - } - } - - @Override - public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { - super.dump(prefix, fd, writer, args); - if (mTask != null) { - writer.print(prefix); writer.print("mTask="); writer.print(mTask); - writer.print(" waiting="); writer.println(mTask.waiting); - } - if (mCancellingTask != null) { - writer.print(prefix); writer.print("mCancellingTask="); writer.print(mCancellingTask); - writer.print(" waiting="); writer.println(mCancellingTask.waiting); - } - if (mUpdateThrottle != 0) { - writer.print(prefix); writer.print("mUpdateThrottle="); - TimeUtils.formatDuration(mUpdateThrottle, writer); - writer.print(" mLastLoadCompleteTime="); - TimeUtils.formatDuration(mLastLoadCompleteTime, - SystemClock.uptimeMillis(), writer); - writer.println(); - } - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/CursorLoader.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/CursorLoader.java deleted file mode 100644 index 51ad8b54..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/CursorLoader.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.content; - -import android.content.Context; -import android.database.ContentObserver; -import android.database.Cursor; -import android.net.Uri; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.Arrays; - -/** - * Static library support version of the framework's {@link android.content.CursorLoader}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - */ -public class CursorLoader extends AsyncTaskLoader { - final ForceLoadContentObserver mObserver; - - Uri mUri; - String[] mProjection; - String mSelection; - String[] mSelectionArgs; - String mSortOrder; - - Cursor mCursor; - - /* Runs on a worker thread */ - @Override - public Cursor loadInBackground() { - Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection, - mSelectionArgs, mSortOrder); - if (cursor != null) { - // Ensure the cursor window is filled - cursor.getCount(); - registerContentObserver(cursor, mObserver); - } - return cursor; - } - - /** - * Registers an observer to get notifications from the content provider - * when the cursor needs to be refreshed. - */ - void registerContentObserver(Cursor cursor, ContentObserver observer) { - cursor.registerContentObserver(mObserver); - } - - /* Runs on the UI thread */ - @Override - public void deliverResult(Cursor cursor) { - if (isReset()) { - // An async query came in while the loader is stopped - if (cursor != null) { - cursor.close(); - } - return; - } - Cursor oldCursor = mCursor; - mCursor = cursor; - - if (isStarted()) { - super.deliverResult(cursor); - } - - if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) { - oldCursor.close(); - } - } - - /** - * Creates an empty unspecified CursorLoader. You must follow this with - * calls to {@link #setUri(Uri)}, {@link #setSelection(String)}, etc - * to specify the query to perform. - */ - public CursorLoader(Context context) { - super(context); - mObserver = new ForceLoadContentObserver(); - } - - /** - * Creates a fully-specified CursorLoader. See - * {@link ContentResolver#query(Uri, String[], String, String[], String) - * ContentResolver.query()} for documentation on the meaning of the - * parameters. These will be passed as-is to that call. - */ - public CursorLoader(Context context, Uri uri, String[] projection, String selection, - String[] selectionArgs, String sortOrder) { - super(context); - mObserver = new ForceLoadContentObserver(); - mUri = uri; - mProjection = projection; - mSelection = selection; - mSelectionArgs = selectionArgs; - mSortOrder = sortOrder; - } - - /** - * Starts an asynchronous load of the contacts list data. When the result is ready the callbacks - * will be called on the UI thread. If a previous load has been completed and is still valid - * the result may be passed to the callbacks immediately. - * - * Must be called from the UI thread - */ - @Override - protected void onStartLoading() { - if (mCursor != null) { - deliverResult(mCursor); - } - if (takeContentChanged() || mCursor == null) { - forceLoad(); - } - } - - /** - * Must be called from the UI thread - */ - @Override - protected void onStopLoading() { - // Attempt to cancel the current load task if possible. - cancelLoad(); - } - - @Override - public void onCanceled(Cursor cursor) { - if (cursor != null && !cursor.isClosed()) { - cursor.close(); - } - } - - @Override - protected void onReset() { - super.onReset(); - - // Ensure the loader is stopped - onStopLoading(); - - if (mCursor != null && !mCursor.isClosed()) { - mCursor.close(); - } - mCursor = null; - } - - public Uri getUri() { - return mUri; - } - - public void setUri(Uri uri) { - mUri = uri; - } - - public String[] getProjection() { - return mProjection; - } - - public void setProjection(String[] projection) { - mProjection = projection; - } - - public String getSelection() { - return mSelection; - } - - public void setSelection(String selection) { - mSelection = selection; - } - - public String[] getSelectionArgs() { - return mSelectionArgs; - } - - public void setSelectionArgs(String[] selectionArgs) { - mSelectionArgs = selectionArgs; - } - - public String getSortOrder() { - return mSortOrder; - } - - public void setSortOrder(String sortOrder) { - mSortOrder = sortOrder; - } - - @Override - public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { - super.dump(prefix, fd, writer, args); - writer.print(prefix); writer.print("mUri="); writer.println(mUri); - writer.print(prefix); writer.print("mProjection="); - writer.println(Arrays.toString(mProjection)); - writer.print(prefix); writer.print("mSelection="); writer.println(mSelection); - writer.print(prefix); writer.print("mSelectionArgs="); - writer.println(Arrays.toString(mSelectionArgs)); - writer.print(prefix); writer.print("mSortOrder="); writer.println(mSortOrder); - writer.print(prefix); writer.print("mCursor="); writer.println(mCursor); - writer.print(prefix); writer.print("mContentChanged="); writer.println(mContentChanged); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/Loader.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/Loader.java deleted file mode 100644 index b9f2c6a8..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/content/Loader.java +++ /dev/null @@ -1,358 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.content; - -import android.content.Context; -import android.database.ContentObserver; -import android.os.Handler; -import android.support.v4.util.DebugUtils; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * Static library support version of the framework's {@link android.content.Loader}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - */ -public class Loader { - int mId; - OnLoadCompleteListener mListener; - Context mContext; - boolean mStarted = false; - boolean mAbandoned = false; - boolean mReset = true; - boolean mContentChanged = false; - - public final class ForceLoadContentObserver extends ContentObserver { - public ForceLoadContentObserver() { - super(new Handler()); - } - - @Override - public boolean deliverSelfNotifications() { - return true; - } - - @Override - public void onChange(boolean selfChange) { - onContentChanged(); - } - } - - public interface OnLoadCompleteListener { - /** - * Called on the thread that created the Loader when the load is complete. - * - * @param loader the loader that completed the load - * @param data the result of the load - */ - public void onLoadComplete(Loader loader, D data); - } - - /** - * Stores away the application context associated with context. Since Loaders can be used - * across multiple activities it's dangerous to store the context directly. - * - * @param context used to retrieve the application context. - */ - public Loader(Context context) { - mContext = context.getApplicationContext(); - } - - /** - * Sends the result of the load to the registered listener. Should only be called by subclasses. - * - * Must be called from the process's main thread. - * - * @param data the result of the load - */ - public void deliverResult(D data) { - if (mListener != null) { - mListener.onLoadComplete(this, data); - } - } - - /** - * @return an application context retrieved from the Context passed to the constructor. - */ - public Context getContext() { - return mContext; - } - - /** - * @return the ID of this loader - */ - public int getId() { - return mId; - } - - /** - * Registers a class that will receive callbacks when a load is complete. - * The callback will be called on the process's main thread so it's safe to - * pass the results to widgets. - * - *

Must be called from the process's main thread. - */ - public void registerListener(int id, OnLoadCompleteListener listener) { - if (mListener != null) { - throw new IllegalStateException("There is already a listener registered"); - } - mListener = listener; - mId = id; - } - - /** - * Remove a listener that was previously added with {@link #registerListener}. - * - * Must be called from the process's main thread. - */ - public void unregisterListener(OnLoadCompleteListener listener) { - if (mListener == null) { - throw new IllegalStateException("No listener register"); - } - if (mListener != listener) { - throw new IllegalArgumentException("Attempting to unregister the wrong listener"); - } - mListener = null; - } - - /** - * Return whether this load has been started. That is, its {@link #startLoading()} - * has been called and no calls to {@link #stopLoading()} or - * {@link #reset()} have yet been made. - */ - public boolean isStarted() { - return mStarted; - } - - /** - * Return whether this loader has been abandoned. In this state, the - * loader must not report any new data, and must keep - * its last reported data valid until it is finally reset. - */ - public boolean isAbandoned() { - return mAbandoned; - } - - /** - * Return whether this load has been reset. That is, either the loader - * has not yet been started for the first time, or its {@link #reset()} - * has been called. - */ - public boolean isReset() { - return mReset; - } - - /** - * Starts an asynchronous load of the Loader's data. When the result - * is ready the callbacks will be called on the process's main thread. - * If a previous load has been completed and is still valid - * the result may be passed to the callbacks immediately. - * The loader will monitor the source of - * the data set and may deliver future callbacks if the source changes. - * Calling {@link #stopLoading} will stop the delivery of callbacks. - * - *

This updates the Loader's internal state so that - * {@link #isStarted()} and {@link #isReset()} will return the correct - * values, and then calls the implementation's {@link #onStartLoading()}. - * - *

Must be called from the process's main thread. - */ - public final void startLoading() { - mStarted = true; - mReset = false; - mAbandoned = false; - onStartLoading(); - } - - /** - * Subclasses must implement this to take care of loading their data, - * as per {@link #startLoading()}. This is not called by clients directly, - * but as a result of a call to {@link #startLoading()}. - */ - protected void onStartLoading() { - } - - /** - * Force an asynchronous load. Unlike {@link #startLoading()} this will ignore a previously - * loaded data set and load a new one. This simply calls through to the - * implementation's {@link #onForceLoad()}. You generally should only call this - * when the loader is started -- that is, {@link #isStarted()} returns true. - * - *

Must be called from the process's main thread. - */ - public void forceLoad() { - onForceLoad(); - } - - /** - * Subclasses must implement this to take care of requests to {@link #forceLoad()}. - * This will always be called from the process's main thread. - */ - protected void onForceLoad() { - } - - /** - * Stops delivery of updates until the next time {@link #startLoading()} is called. - * Implementations should not invalidate their data at this point -- - * clients are still free to use the last data the loader reported. They will, - * however, typically stop reporting new data if the data changes; they can - * still monitor for changes, but must not report them to the client until and - * if {@link #startLoading()} is later called. - * - *

This updates the Loader's internal state so that - * {@link #isStarted()} will return the correct - * value, and then calls the implementation's {@link #onStopLoading()}. - * - *

Must be called from the process's main thread. - */ - public void stopLoading() { - mStarted = false; - onStopLoading(); - } - - /** - * Subclasses must implement this to take care of stopping their loader, - * as per {@link #stopLoading()}. This is not called by clients directly, - * but as a result of a call to {@link #stopLoading()}. - * This will always be called from the process's main thread. - */ - protected void onStopLoading() { - } - - /** - * Tell the Loader that it is being abandoned. This is called prior - * to {@link #reset} to have it retain its current data but not report - * any new data. - */ - public void abandon() { - mAbandoned = true; - onAbandon(); - } - - /** - * Subclasses implement this to take care of being abandoned. This is - * an optional intermediate state prior to {@link #onReset()} -- it means that - * the client is no longer interested in any new data from the loader, - * so the loader must not report any further updates. However, the - * loader must keep its last reported data valid until the final - * {@link #onReset()} happens. You can retrieve the current abandoned - * state with {@link #isAbandoned}. - */ - protected void onAbandon() { - } - - /** - * Resets the state of the Loader. The Loader should at this point free - * all of its resources, since it may never be called again; however, its - * {@link #startLoading()} may later be called at which point it must be - * able to start running again. - * - *

This updates the Loader's internal state so that - * {@link #isStarted()} and {@link #isReset()} will return the correct - * values, and then calls the implementation's {@link #onReset()}. - * - *

Must be called from the process's main thread. - */ - public void reset() { - onReset(); - mReset = true; - mStarted = false; - mAbandoned = false; - mContentChanged = false; - } - - /** - * Subclasses must implement this to take care of resetting their loader, - * as per {@link #reset()}. This is not called by clients directly, - * but as a result of a call to {@link #reset()}. - * This will always be called from the process's main thread. - */ - protected void onReset() { - } - - /** - * Take the current flag indicating whether the loader's content had - * changed while it was stopped. If it had, true is returned and the - * flag is cleared. - */ - public boolean takeContentChanged() { - boolean res = mContentChanged; - mContentChanged = false; - return res; - } - - /** - * Called when {@link ForceLoadContentObserver} detects a change. The - * default implementation checks to see if the loader is currently started; - * if so, it simply calls {@link #forceLoad()}; otherwise, it sets a flag - * so that {@link #takeContentChanged()} returns true. - * - *

Must be called from the process's main thread. - */ - public void onContentChanged() { - if (mStarted) { - forceLoad(); - } else { - // This loader has been stopped, so we don't want to load - // new data right now... but keep track of it changing to - // refresh later if we start again. - mContentChanged = true; - } - } - - /** - * For debugging, converts an instance of the Loader's data class to - * a string that can be printed. Must handle a null data. - */ - public String dataToString(D data) { - StringBuilder sb = new StringBuilder(64); - DebugUtils.buildShortClassTag(data, sb); - sb.append("}"); - return sb.toString(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(64); - DebugUtils.buildShortClassTag(this, sb); - sb.append(" id="); - sb.append(mId); - sb.append("}"); - return sb.toString(); - } - - /** - * Print the Loader's state into the given stream. - * - * @param prefix Text to print at the front of each line. - * @param fd The raw file descriptor that the dump is being sent to. - * @param writer A PrintWriter to which the dump is to be set. - * @param args Additional arguments to the dump request. - */ - public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) { - writer.print(prefix); writer.print("mId="); writer.print(mId); - writer.print(" mListener="); writer.println(mListener); - writer.print(prefix); writer.print("mStarted="); writer.print(mStarted); - writer.print(" mContentChanged="); writer.print(mContentChanged); - writer.print(" mAbandoned="); writer.print(mAbandoned); - writer.print(" mReset="); writer.println(mReset); - } -} \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompat.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompat.java deleted file mode 100644 index 714af337..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompat.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.os; - -import android.os.Parcel; -import android.os.Parcelable; - -public class ParcelableCompat { - public static Parcelable.Creator newCreator( - ParcelableCompatCreatorCallbacks callbacks) { - if (android.os.Build.VERSION.SDK_INT >= 13) { - ParcelableCompatCreatorHoneycombMR2Stub.instantiate(callbacks); - } - return new CompatCreator(callbacks); - } - - static class CompatCreator implements Parcelable.Creator { - final ParcelableCompatCreatorCallbacks mCallbacks; - - public CompatCreator(ParcelableCompatCreatorCallbacks callbacks) { - mCallbacks = callbacks; - } - - @Override - public T createFromParcel(Parcel source) { - return mCallbacks.createFromParcel(source, null); - } - - @Override - public T[] newArray(int size) { - return mCallbacks.newArray(size); - } - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompatCreatorCallbacks.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompatCreatorCallbacks.java deleted file mode 100644 index 8678cfb7..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompatCreatorCallbacks.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.os; - -import android.os.Parcel; - -public interface ParcelableCompatCreatorCallbacks { - public T createFromParcel(Parcel in, ClassLoader loader); - public T[] newArray(int size); -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompatHoneycombMR2.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompatHoneycombMR2.java deleted file mode 100644 index 08acb550..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/os/ParcelableCompatHoneycombMR2.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.os; - -import android.os.Parcel; -import android.os.Parcelable; - -class ParcelableCompatCreatorHoneycombMR2Stub { - static Parcelable.Creator instantiate(ParcelableCompatCreatorCallbacks callbacks) { - return new ParcelableCompatCreatorHoneycombMR2(callbacks); - } -} - -class ParcelableCompatCreatorHoneycombMR2 implements Parcelable.ClassLoaderCreator { - private final ParcelableCompatCreatorCallbacks mCallbacks; - - public ParcelableCompatCreatorHoneycombMR2(ParcelableCompatCreatorCallbacks callbacks) { - mCallbacks = callbacks; - } - - public T createFromParcel(Parcel in) { - return mCallbacks.createFromParcel(in, null); - } - - public T createFromParcel(Parcel in, ClassLoader loader) { - return mCallbacks.createFromParcel(in, loader); - } - - public T[] newArray(int size) { - return mCallbacks.newArray(size); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/DebugUtils.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/DebugUtils.java deleted file mode 100644 index 16c63a9f..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/DebugUtils.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.util; - -/** - * Useful debugging utilities that are not available on all versions of Android. - */ -public class DebugUtils { - public static void buildShortClassTag(Object cls, StringBuilder out) { - if (cls == null) { - out.append("null"); - } else { - String simpleName = cls.getClass().getSimpleName(); - if (simpleName == null || simpleName.length() <= 0) { - simpleName = cls.getClass().getName(); - int end = simpleName.lastIndexOf('.'); - if (end > 0) { - simpleName = simpleName.substring(end+1); - } - } - out.append(simpleName); - out.append('{'); - out.append(Integer.toHexString(System.identityHashCode(cls))); - } - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/LogWriter.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/LogWriter.java deleted file mode 100644 index 3b9d12b0..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/LogWriter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.util; - -import android.util.Log; - -import java.io.Writer; - -/** - * Useful logging utility that is not available on all versions of Android. - */ -public class LogWriter extends Writer { - private final String mTag; - private StringBuilder mBuilder = new StringBuilder(128); - - /** - * Create a new Writer that sends to the log with the given priority - * and tag. - * - * @param priority The desired log priority: - * {@link android.util.Log#VERBOSE Log.VERBOSE}, - * {@link android.util.Log#DEBUG Log.DEBUG}, - * {@link android.util.Log#INFO Log.INFO}, - * {@link android.util.Log#WARN Log.WARN}, or - * {@link android.util.Log#ERROR Log.ERROR}. - * @param tag A string tag to associate with each printed log statement. - */ - public LogWriter(String tag) { - mTag = tag; - } - - @Override public void close() { - flushBuilder(); - } - - @Override public void flush() { - flushBuilder(); - } - - @Override public void write(char[] buf, int offset, int count) { - for(int i = 0; i < count; i++) { - char c = buf[offset + i]; - if ( c == '\n') { - flushBuilder(); - } - else { - mBuilder.append(c); - } - } - } - - private void flushBuilder() { - if (mBuilder.length() > 0) { - Log.d(mTag, mBuilder.toString()); - mBuilder.delete(0, mBuilder.length()); - } - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/LruCache.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/LruCache.java deleted file mode 100644 index a7a2ee27..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/LruCache.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.util; - -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * Static library version of {@code android.util.LruCache}. Used to write apps - * that run on API levels prior to 12. When running on API level 12 or above, - * this implementation is still used; it does not try to switch to the - * framework's implementation. See the framework SDK documentation for a class - * overview. - */ -public class LruCache { - private final LinkedHashMap map; - - /** Size of this cache in units. Not necessarily the number of elements. */ - private int size; - private int maxSize; - - private int putCount; - private int createCount; - private int evictionCount; - private int hitCount; - private int missCount; - - /** - * @param maxSize for caches that do not override {@link #sizeOf}, this is - * the maximum number of entries in the cache. For all other caches, - * this is the maximum sum of the sizes of the entries in this cache. - */ - public LruCache(int maxSize) { - if (maxSize <= 0) { - throw new IllegalArgumentException("maxSize <= 0"); - } - this.maxSize = maxSize; - this.map = new LinkedHashMap(0, 0.75f, true); - } - - /** - * Returns the value for {@code key} if it exists in the cache or can be - * created by {@code #create}. If a value was returned, it is moved to the - * head of the queue. This returns null if a value is not cached and cannot - * be created. - */ - public final V get(K key) { - if (key == null) { - throw new NullPointerException("key == null"); - } - - V mapValue; - synchronized (this) { - mapValue = map.get(key); - if (mapValue != null) { - hitCount++; - return mapValue; - } - missCount++; - } - - /* - * Attempt to create a value. This may take a long time, and the map - * may be different when create() returns. If a conflicting value was - * added to the map while create() was working, we leave that value in - * the map and release the created value. - */ - - V createdValue = create(key); - if (createdValue == null) { - return null; - } - - synchronized (this) { - createCount++; - mapValue = map.put(key, createdValue); - - if (mapValue != null) { - // There was a conflict so undo that last put - map.put(key, mapValue); - } else { - size += safeSizeOf(key, createdValue); - } - } - - if (mapValue != null) { - entryRemoved(false, key, createdValue, mapValue); - return mapValue; - } else { - trimToSize(maxSize); - return createdValue; - } - } - - /** - * Caches {@code value} for {@code key}. The value is moved to the head of - * the queue. - * - * @return the previous value mapped by {@code key}. - */ - public final V put(K key, V value) { - if (key == null || value == null) { - throw new NullPointerException("key == null || value == null"); - } - - V previous; - synchronized (this) { - putCount++; - size += safeSizeOf(key, value); - previous = map.put(key, value); - if (previous != null) { - size -= safeSizeOf(key, previous); - } - } - - if (previous != null) { - entryRemoved(false, key, previous, value); - } - - trimToSize(maxSize); - return previous; - } - - /** - * @param maxSize the maximum size of the cache before returning. May be -1 - * to evict even 0-sized elements. - */ - private void trimToSize(int maxSize) { - while (true) { - K key; - V value; - synchronized (this) { - if (size < 0 || (map.isEmpty() && size != 0)) { - throw new IllegalStateException(getClass().getName() - + ".sizeOf() is reporting inconsistent results!"); - } - - if (size <= maxSize || map.isEmpty()) { - break; - } - - Map.Entry toEvict = map.entrySet().iterator().next(); - key = toEvict.getKey(); - value = toEvict.getValue(); - map.remove(key); - size -= safeSizeOf(key, value); - evictionCount++; - } - - entryRemoved(true, key, value, null); - } - } - - /** - * Removes the entry for {@code key} if it exists. - * - * @return the previous value mapped by {@code key}. - */ - public final V remove(K key) { - if (key == null) { - throw new NullPointerException("key == null"); - } - - V previous; - synchronized (this) { - previous = map.remove(key); - if (previous != null) { - size -= safeSizeOf(key, previous); - } - } - - if (previous != null) { - entryRemoved(false, key, previous, null); - } - - return previous; - } - - /** - * Called for entries that have been evicted or removed. This method is - * invoked when a value is evicted to make space, removed by a call to - * {@link #remove}, or replaced by a call to {@link #put}. The default - * implementation does nothing. - * - *

The method is called without synchronization: other threads may - * access the cache while this method is executing. - * - * @param evicted true if the entry is being removed to make space, false - * if the removal was caused by a {@link #put} or {@link #remove}. - * @param newValue the new value for {@code key}, if it exists. If non-null, - * this removal was caused by a {@link #put}. Otherwise it was caused by - * an eviction or a {@link #remove}. - */ - protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {} - - /** - * Called after a cache miss to compute a value for the corresponding key. - * Returns the computed value or null if no value can be computed. The - * default implementation returns null. - * - *

The method is called without synchronization: other threads may - * access the cache while this method is executing. - * - *

If a value for {@code key} exists in the cache when this method - * returns, the created value will be released with {@link #entryRemoved} - * and discarded. This can occur when multiple threads request the same key - * at the same time (causing multiple values to be created), or when one - * thread calls {@link #put} while another is creating a value for the same - * key. - */ - protected V create(K key) { - return null; - } - - private int safeSizeOf(K key, V value) { - int result = sizeOf(key, value); - if (result < 0) { - throw new IllegalStateException("Negative size: " + key + "=" + value); - } - return result; - } - - /** - * Returns the size of the entry for {@code key} and {@code value} in - * user-defined units. The default implementation returns 1 so that size - * is the number of entries and max size is the maximum number of entries. - * - *

An entry's size must not change while it is in the cache. - */ - protected int sizeOf(K key, V value) { - return 1; - } - - /** - * Clear the cache, calling {@link #entryRemoved} on each removed entry. - */ - public final void evictAll() { - trimToSize(-1); // -1 will evict 0-sized elements - } - - /** - * For caches that do not override {@link #sizeOf}, this returns the number - * of entries in the cache. For all other caches, this returns the sum of - * the sizes of the entries in this cache. - */ - public synchronized final int size() { - return size; - } - - /** - * For caches that do not override {@link #sizeOf}, this returns the maximum - * number of entries in the cache. For all other caches, this returns the - * maximum sum of the sizes of the entries in this cache. - */ - public synchronized final int maxSize() { - return maxSize; - } - - /** - * Returns the number of times {@link #get} returned a value. - */ - public synchronized final int hitCount() { - return hitCount; - } - - /** - * Returns the number of times {@link #get} returned null or required a new - * value to be created. - */ - public synchronized final int missCount() { - return missCount; - } - - /** - * Returns the number of times {@link #create(Object)} returned a value. - */ - public synchronized final int createCount() { - return createCount; - } - - /** - * Returns the number of times {@link #put} was called. - */ - public synchronized final int putCount() { - return putCount; - } - - /** - * Returns the number of values that have been evicted. - */ - public synchronized final int evictionCount() { - return evictionCount; - } - - /** - * Returns a copy of the current contents of the cache, ordered from least - * recently accessed to most recently accessed. - */ - public synchronized final Map snapshot() { - return new LinkedHashMap(map); - } - - @Override public synchronized final String toString() { - int accesses = hitCount + missCount; - int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0; - return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]", - maxSize, hitCount, missCount, hitPercent); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/TimeUtils.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/TimeUtils.java deleted file mode 100644 index 65ac8544..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/util/TimeUtils.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.util; - -import java.io.PrintWriter; - -/** - * Useful time utilities that are not available on all versions of Android. - */ -public class TimeUtils { - /** @hide Field length that can hold 999 days of time */ - public static final int HUNDRED_DAY_FIELD_LEN = 19; - - private static final int SECONDS_PER_MINUTE = 60; - private static final int SECONDS_PER_HOUR = 60 * 60; - private static final int SECONDS_PER_DAY = 24 * 60 * 60; - - private static final Object sFormatSync = new Object(); - private static char[] sFormatStr = new char[HUNDRED_DAY_FIELD_LEN+5]; - - static private int accumField(int amt, int suffix, boolean always, int zeropad) { - if (amt > 99 || (always && zeropad >= 3)) { - return 3+suffix; - } - if (amt > 9 || (always && zeropad >= 2)) { - return 2+suffix; - } - if (always || amt > 0) { - return 1+suffix; - } - return 0; - } - - static private int printField(char[] formatStr, int amt, char suffix, int pos, - boolean always, int zeropad) { - if (always || amt > 0) { - final int startPos = pos; - if ((always && zeropad >= 3) || amt > 99) { - int dig = amt/100; - formatStr[pos] = (char)(dig + '0'); - pos++; - amt -= (dig*100); - } - if ((always && zeropad >= 2) || amt > 9 || startPos != pos) { - int dig = amt/10; - formatStr[pos] = (char)(dig + '0'); - pos++; - amt -= (dig*10); - } - formatStr[pos] = (char)(amt + '0'); - pos++; - formatStr[pos] = suffix; - pos++; - } - return pos; - } - - private static int formatDurationLocked(long duration, int fieldLen) { - if (sFormatStr.length < fieldLen) { - sFormatStr = new char[fieldLen]; - } - - char[] formatStr = sFormatStr; - - if (duration == 0) { - int pos = 0; - fieldLen -= 1; - while (pos < fieldLen) { - formatStr[pos] = ' '; - } - formatStr[pos] = '0'; - return pos+1; - } - - char prefix; - if (duration > 0) { - prefix = '+'; - } else { - prefix = '-'; - duration = -duration; - } - - int millis = (int)(duration%1000); - int seconds = (int) Math.floor(duration / 1000); - int days = 0, hours = 0, minutes = 0; - - if (seconds > SECONDS_PER_DAY) { - days = seconds / SECONDS_PER_DAY; - seconds -= days * SECONDS_PER_DAY; - } - if (seconds > SECONDS_PER_HOUR) { - hours = seconds / SECONDS_PER_HOUR; - seconds -= hours * SECONDS_PER_HOUR; - } - if (seconds > SECONDS_PER_MINUTE) { - minutes = seconds / SECONDS_PER_MINUTE; - seconds -= minutes * SECONDS_PER_MINUTE; - } - - int pos = 0; - - if (fieldLen != 0) { - int myLen = accumField(days, 1, false, 0); - myLen += accumField(hours, 1, myLen > 0, 2); - myLen += accumField(minutes, 1, myLen > 0, 2); - myLen += accumField(seconds, 1, myLen > 0, 2); - myLen += accumField(millis, 2, true, myLen > 0 ? 3 : 0) + 1; - while (myLen < fieldLen) { - formatStr[pos] = ' '; - pos++; - myLen++; - } - } - - formatStr[pos] = prefix; - pos++; - - int start = pos; - boolean zeropad = fieldLen != 0; - pos = printField(formatStr, days, 'd', pos, false, 0); - pos = printField(formatStr, hours, 'h', pos, pos != start, zeropad ? 2 : 0); - pos = printField(formatStr, minutes, 'm', pos, pos != start, zeropad ? 2 : 0); - pos = printField(formatStr, seconds, 's', pos, pos != start, zeropad ? 2 : 0); - pos = printField(formatStr, millis, 'm', pos, true, (zeropad && pos != start) ? 3 : 0); - formatStr[pos] = 's'; - return pos + 1; - } - - /** @hide Just for debugging; not internationalized. */ - public static void formatDuration(long duration, StringBuilder builder) { - synchronized (sFormatSync) { - int len = formatDurationLocked(duration, 0); - builder.append(sFormatStr, 0, len); - } - } - - /** @hide Just for debugging; not internationalized. */ - public static void formatDuration(long duration, PrintWriter pw, int fieldLen) { - synchronized (sFormatSync) { - int len = formatDurationLocked(duration, fieldLen); - pw.print(new String(sFormatStr, 0, len)); - } - } - - /** @hide Just for debugging; not internationalized. */ - public static void formatDuration(long duration, PrintWriter pw) { - formatDuration(duration, pw, 0); - } - - /** @hide Just for debugging; not internationalized. */ - public static void formatDuration(long time, long now, PrintWriter pw) { - if (time == 0) { - pw.print("--"); - return; - } - formatDuration(time-now, pw, 0); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/Menu.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/Menu.java deleted file mode 100644 index 39a69718..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/Menu.java +++ /dev/null @@ -1,33 +0,0 @@ -package android.support.v4.view; - -public interface Menu extends android.view.Menu { - @Override - MenuItem add(CharSequence title); - - @Override - MenuItem add(int groupId, int itemId, int order, int titleRes); - - @Override - MenuItem add(int titleRes); - - @Override - MenuItem add(int groupId, int itemId, int order, CharSequence title); - - @Override - SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title); - - @Override - SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes); - - @Override - SubMenu addSubMenu(CharSequence title); - - @Override - SubMenu addSubMenu(int titleRes); - - @Override - MenuItem findItem(int id); - - @Override - MenuItem getItem(int index); -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MenuItem.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MenuItem.java deleted file mode 100644 index 49740ea4..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MenuItem.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * 2011 Jake Wharton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.view; - -import com.actionbarsherlock.internal.view.menu.MenuItemWrapper; -import android.content.Intent; -import android.graphics.drawable.Drawable; -import android.view.View; - -/** - *

Interface for direct access to a previously created menu item.

- * - *

An Item is returned by calling one of the {@link Menu#add(int)} - * methods.

- * - *

For a feature set of specific menu types, see {@link Menu}.

- */ -public interface MenuItem extends android.view.MenuItem { - /** - * Interface definition for a callback to be invoked when a menu item is - * clicked. - */ - public static abstract class OnMenuItemClickListener implements android.view.MenuItem.OnMenuItemClickListener { - /** - * Called when a menu item has been invoked. This is the first code - * that is executed; if it returns true, no other callbacks will be - * executed. - * - * @param item The menu item that was invoked. - * @return Return true to consume this click and prevent others from - * executing. - */ - public abstract boolean onMenuItemClick(MenuItem item); - - @Override - public final boolean onMenuItemClick(android.view.MenuItem item) { - return this.onMenuItemClick(new MenuItemWrapper(item)); - } - } - - - - /** - * Always show this item as a button in an Action Bar. Use sparingly! If too - * many items are set to always show in the Action Bar it can crowd the - * Action Bar and degrade the user experience on devices with smaller - * screens. A good rule of thumb is to have no more than 2 items set to - * always show at a time. - */ - public static final int SHOW_AS_ACTION_ALWAYS = android.view.MenuItem.SHOW_AS_ACTION_ALWAYS; - - /** - * Show this item as a button in an Action Bar if the system decides there - * is room for it. - */ - public static final int SHOW_AS_ACTION_IF_ROOM = android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM; - - /** - * Never show this item as a button in an Action Bar. - */ - public static final int SHOW_AS_ACTION_NEVER = android.view.MenuItem.SHOW_AS_ACTION_NEVER; - - /** - * When this item is in the action bar, always show it with a text label - * even if it also has an icon specified. - */ - public static final int SHOW_AS_ACTION_WITH_TEXT = android.view.MenuItem.SHOW_AS_ACTION_WITH_TEXT; - - - - /** - * Returns the currently set action view for this menu item. - * - * @return The item's action view - * @see #setActionView(int) - * @see #setActionView(View) - * @see #setShowAsAction(int) - */ - View getActionView(); - - /** - * Set an action view for this menu item. An action view will be displayed - * in place of an automatically generated menu item element in the UI when - * this item is shown as an action within a parent. - * - * @param resId Layout resource to use for presenting this item to the user. - * @return This Item so additional setters can be called. - * @see #setActionView(View) - */ - MenuItem setActionView(int resId); - - /** - * Set an action view for this menu item. An action view will be displayed - * in place of an automatically generated menu item element in the UI when - * this item is shown as an action within a parent. - * - * @param view View to use for presenting this item to the user. - * @return This Item so additional setters can be called. - * @see #setActionView(int) - */ - MenuItem setActionView(View view); - - /** - * Sets how this item should display in the presence of an Action Bar. The - * parameter actionEnum is a flag set. One of - * {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or - * {@link #SHOW_AS_ACTION_NEVER} should be used, and you may optionally OR - * the value with {@link #SHOW_AS_ACTION_WITH_TEXT}. - * {@link #SHOW_AS_ACTION_WITH_TEXT} requests that when the item is shown as - * an action, it should be shown with a text label. - * - * @param actionEnum How the item should display. One of - * {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or - * {@link #SHOW_AS_ACTION_NEVER}. {@link #SHOW_AS_ACTION_NEVER} is the - * default. - */ - void setShowAsAction(int actionEnum); - - // --------------------------------------------------------------------- - // MENU ITEM SUPPORT - // --------------------------------------------------------------------- - - @Override - SubMenu getSubMenu(); - - @Override - MenuItem setAlphabeticShortcut(char alphaChar); - - @Override - MenuItem setCheckable(boolean checkable); - - @Override - MenuItem setChecked(boolean checked); - - @Override - MenuItem setEnabled(boolean enabled); - - @Override - MenuItem setIcon(Drawable icon); - - @Override - MenuItem setIcon(int iconRes); - - @Override - MenuItem setIntent(Intent intent); - - @Override - MenuItem setNumericShortcut(char numericChar); - - /** - * Set a custom listener for invocation of this menu item. - * - * @param menuItemClickListener The object to receive invokations. - * @return This Item so additional setters can be called. - */ - MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener); - - @Override - MenuItem setShortcut(char numericChar, char alphaChar); - - @Override - MenuItem setTitle(CharSequence title); - - @Override - MenuItem setTitle(int title); - - @Override - MenuItem setTitleCondensed(CharSequence title); - - @Override - MenuItem setVisible(boolean visible); -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MotionEventCompat.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MotionEventCompat.java deleted file mode 100644 index 3e5e13e1..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MotionEventCompat.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.view; - -import android.view.MotionEvent; - -/** - * Helper for accessing newer features in MotionEvent. - */ -public class MotionEventCompat { - /** - * Interface for the full API. - */ - interface MotionEventVersionImpl { - public int findPointerIndex(MotionEvent event, int pointerId); - public int getPointerId(MotionEvent event, int pointerIndex); - public float getX(MotionEvent event, int pointerIndex); - public float getY(MotionEvent event, int pointerIndex); - } - - /** - * Interface implementation that doesn't use anything about v4 APIs. - */ - static class BaseMotionEventVersionImpl implements MotionEventVersionImpl { - @Override - public int findPointerIndex(MotionEvent event, int pointerId) { - return -1; - } - @Override - public int getPointerId(MotionEvent event, int pointerIndex) { - return -1; - } - @Override - public float getX(MotionEvent event, int pointerIndex) { - return event.getX(); - } - @Override - public float getY(MotionEvent event, int pointerIndex) { - return event.getY(); - } - } - - /** - * Interface implementation for devices with at least v11 APIs. - */ - static class EclairMotionEventVersionImpl implements MotionEventVersionImpl { - @Override - public int findPointerIndex(MotionEvent event, int pointerId) { - return MotionEventCompatEclair.findPointerIndex(event, pointerId); - } - @Override - public int getPointerId(MotionEvent event, int pointerIndex) { - return MotionEventCompatEclair.getPointerId(event, pointerIndex); - } - @Override - public float getX(MotionEvent event, int pointerIndex) { - return MotionEventCompatEclair.getX(event, pointerIndex); - } - @Override - public float getY(MotionEvent event, int pointerIndex) { - return MotionEventCompatEclair.getY(event, pointerIndex); - } - } - - /** - * Select the correct implementation to use for the current platform. - */ - static final MotionEventVersionImpl IMPL; - static { - if (android.os.Build.VERSION.SDK_INT >= 5) { - IMPL = new EclairMotionEventVersionImpl(); - } else { - IMPL = new BaseMotionEventVersionImpl(); - } - } - - // ------------------------------------------------------------------- - - /** - * Synonym for {@link MotionEvent#ACTION_MASK}. - */ - public static final int ACTION_MASK = 0xff; - - /** - * Synonym for {@link MotionEvent#ACTION_POINTER_DOWN}. - */ - public static final int ACTION_POINTER_DOWN = 5; - - /** - * Synonym for {@link MotionEvent#ACTION_POINTER_UP}. - */ - public static final int ACTION_POINTER_UP = 6; - - /** - * Synonym for {@link MotionEvent#ACTION_HOVER_MOVE}. - */ - public static final int ACTION_HOVER_MOVE = 7; - - /** - * Synonym for {@link MotionEvent#ACTION_SCROLL}. - */ - public static final int ACTION_SCROLL = 8; - - /** - * Synonym for {@link MotionEvent#ACTION_POINTER_INDEX_MASK}. - */ - public static final int ACTION_POINTER_INDEX_MASK = 0xff00; - - /** - * Synonym for {@link MotionEvent#ACTION_POINTER_INDEX_SHIFT}. - */ - public static final int ACTION_POINTER_INDEX_SHIFT = 8; - - /** - * Call {@link MotionEvent#getAction}, returning only the {@link #ACTION_MASK} - * portion. - */ - public static int getActionMasked(MotionEvent event) { - return event.getAction() & ACTION_MASK; - } - - /** - * Call {@link MotionEvent#getAction}, returning only the pointer index - * portion - */ - public static int getActionIndex(MotionEvent event) { - return (event.getAction() & ACTION_POINTER_INDEX_MASK) - >> ACTION_POINTER_INDEX_SHIFT; - } - - /** - * Call {@link MotionEvent#findPointerIndex(int)}. - * If running on a pre-{@android.os.Build.VERSION_CODES#HONEYCOMB} device, - * does nothing and returns -1. - */ - public static int findPointerIndex(MotionEvent event, int pointerId) { - return IMPL.findPointerIndex(event, pointerId); - } - - /** - * Call {@link MotionEvent#getPointerId(int)}. - * If running on a pre-{@android.os.Build.VERSION_CODES#HONEYCOMB} device, - * {@link IndexOutOfBoundsException} is thrown. - */ - public static int getPointerId(MotionEvent event, int pointerIndex) { - return IMPL.getPointerId(event, pointerIndex); - } - - /** - * Call {@link MotionEvent#getX(int)}. - * If running on a pre-{@android.os.Build.VERSION_CODES#HONEYCOMB} device, - * {@link IndexOutOfBoundsException} is thrown. - */ - public static float getX(MotionEvent event, int pointerIndex) { - return IMPL.getX(event, pointerIndex); - } - - /** - * Call {@link MotionEvent#getY(int)}. - * If running on a pre-{@android.os.Build.VERSION_CODES#HONEYCOMB} device, - * {@link IndexOutOfBoundsException} is thrown. - */ - public static float getY(MotionEvent event, int pointerIndex) { - return IMPL.getY(event, pointerIndex); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MotionEventCompatEclair.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MotionEventCompatEclair.java deleted file mode 100644 index dedb1d1d..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MotionEventCompatEclair.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.view; - -import android.view.MotionEvent; - -/** - * Implementation of motion event compatibility that can call Eclair APIs. - */ -class MotionEventCompatEclair { - public static int findPointerIndex(MotionEvent event, int pointerId) { - return event.findPointerIndex(pointerId); - } - public static int getPointerId(MotionEvent event, int pointerIndex) { - return event.getPointerId(pointerIndex); - } - public static float getX(MotionEvent event, int pointerIndex) { - return event.getX(pointerIndex); - } - public static float getY(MotionEvent event, int pointerIndex) { - return event.getY(pointerIndex); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/PagerAdapter.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/PagerAdapter.java deleted file mode 100644 index 5b2e8a5a..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/PagerAdapter.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.view; - -import android.os.Parcelable; -import android.view.View; - -/** - * Base class providing the adapter to populate pages inside of - * a {@link ViewPager}. You will most likely want to use a more - * specific implementation of this, such as - * {@link android.support.v4.app.FragmentPagerAdapter} or - * {@link android.support.v4.app.FragmentStatePagerAdapter}. - */ -public abstract class PagerAdapter { - private DataSetObserver mObserver; - - public static final int POSITION_UNCHANGED = -1; - public static final int POSITION_NONE = -2; - - /** - * Used to watch for changes within the adapter. - */ - interface DataSetObserver { - public void onDataSetChanged(); - } - - /** - * Return the number of views available. - */ - public abstract int getCount(); - - /** - * Called when a change in the shown pages is going to start being made. - * @param container The containing View which is displaying this adapter's - * page views. - */ - public abstract void startUpdate(View container); - - /** - * Create the page for the given position. The adapter is responsible - * for adding the view to the container given here, although it only - * must ensure this is done by the time it returns from - * {@link #finishUpdate()}. - * - * @param container The containing View in which the page will be shown. - * @param position The page position to be instantiated. - * @return Returns an Object representing the new page. This does not - * need to be a View, but can be some other container of the page. - */ - public abstract Object instantiateItem(View container, int position); - - /** - * Remove a page for the given position. The adapter is responsible - * for removing the view from its container, although it only must ensure - * this is done by the time it returns from {@link #finishUpdate()}. - * - * @param container The containing View from which the page will be removed. - * @param position The page position to be removed. - * @param object The same object that was returned by - * {@link #instantiateItem(View, int)}. - */ - public abstract void destroyItem(View container, int position, Object object); - - /** - * Notification for when an item has been selected in the associated pager. - * This can be used to update the state of the item or activity based on which - * item is currently selected. - * - * @param position The selected page position. - * @param object The object of the selected page. - */ - public void onItemSelected(int position, Object object) { - //For rent. Call 1-800-VIEW-PGR. - } - - /** - * Called when the a change in the shown pages has been completed. At this - * point you must ensure that all of the pages have actually been added or - * removed from the container as appropriate. - * @param container The containing View which is displaying this adapter's - * page views. - */ - public abstract void finishUpdate(View container); - - public abstract boolean isViewFromObject(View view, Object object); - - public abstract Parcelable saveState(); - - public abstract void restoreState(Parcelable state, ClassLoader loader); - - /** - * Called when the host view is attempting to determine if an item's position - * has changed. Returns {@link #POSITION_UNCHANGED} if the position of the given - * item has not changed or {@link #POSITION_NONE} if the item is no longer present - * in the adapter. - * - *

The default implementation assumes that items will never - * change position and always returns {@link #POSITION_UNCHANGED}. - * - * @param object Object representing an item, previously returned by a call to - * {@link #instantiateItem(View, int)}. - * @return object's new position index from [0, {@link #getCount()}), - * {@link #POSITION_UNCHANGED} if the object's position has not changed, - * or {@link #POSITION_NONE} if the item is no longer present. - */ - public int getItemPosition(Object object) { - return POSITION_UNCHANGED; - } - - /** - * This method should be called by the application if the data backing this adapter has changed - * and associated views should update. - */ - public void notifyDataSetChanged() { - if (mObserver != null) { - mObserver.onDataSetChanged(); - } - } - - void setDataSetObserver(DataSetObserver observer) { - mObserver = observer; - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/SubMenu.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/SubMenu.java deleted file mode 100644 index 724f0ff5..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/SubMenu.java +++ /dev/null @@ -1,30 +0,0 @@ -package android.support.v4.view; - -import android.graphics.drawable.Drawable; -import android.view.View; - -public interface SubMenu extends android.view.SubMenu { - @Override - MenuItem getItem(); - - @Override - SubMenu setHeaderIcon(Drawable icon); - - @Override - SubMenu setHeaderIcon(int iconRes); - - @Override - SubMenu setHeaderTitle(CharSequence title); - - @Override - SubMenu setHeaderTitle(int titleRes); - - @Override - SubMenu setHeaderView(View view); - - @Override - SubMenu setIcon(Drawable icon); - - @Override - SubMenu setIcon(int iconRes); -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/VelocityTrackerCompat.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/VelocityTrackerCompat.java deleted file mode 100644 index 8c874906..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/VelocityTrackerCompat.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.view; - -import android.view.VelocityTracker; - -/** - * Helper for accessing newer features in VelocityTracker. - */ -public class VelocityTrackerCompat { - /** - * Interface for the full API. - */ - interface VelocityTrackerVersionImpl { - public float getXVelocity(VelocityTracker tracker, int pointerId); - public float getYVelocity(VelocityTracker tracker, int pointerId); - } - - /** - * Interface implementation that doesn't use anything about v4 APIs. - */ - static class BaseVelocityTrackerVersionImpl implements VelocityTrackerVersionImpl { - @Override - public float getXVelocity(VelocityTracker tracker, int pointerId) { - return tracker.getXVelocity(); - } - @Override - public float getYVelocity(VelocityTracker tracker, int pointerId) { - return tracker.getYVelocity(); - } - } - - /** - * Interface implementation for devices with at least v11 APIs. - */ - static class HoneycombVelocityTrackerVersionImpl implements VelocityTrackerVersionImpl { - @Override - public float getXVelocity(VelocityTracker tracker, int pointerId) { - return VelocityTrackerCompatHoneycomb.getXVelocity(tracker, pointerId); - } - @Override - public float getYVelocity(VelocityTracker tracker, int pointerId) { - return VelocityTrackerCompatHoneycomb.getYVelocity(tracker, pointerId); - } - } - - /** - * Select the correct implementation to use for the current platform. - */ - static final VelocityTrackerVersionImpl IMPL; - static { - if (android.os.Build.VERSION.SDK_INT >= 11) { - IMPL = new HoneycombVelocityTrackerVersionImpl(); - } else { - IMPL = new BaseVelocityTrackerVersionImpl(); - } - } - - // ------------------------------------------------------------------- - - /** - * Call {@link VelocityTracker#getXVelocity(int)}. - * If running on a pre-{@android.os.Build.VERSION_CODES#HONEYCOMB} device, - * returns {@link VelocityTracker#getXVelocity()}. - */ - public static float getXVelocity(VelocityTracker tracker, int pointerId) { - return IMPL.getXVelocity(tracker, pointerId); - } - - /** - * Call {@link VelocityTracker#getYVelocity(int)}. - * If running on a pre-{@android.os.Build.VERSION_CODES#HONEYCOMB} device, - * returns {@link VelocityTracker#getYVelocity()}. - */ - public static float getYVelocity(VelocityTracker tracker, int pointerId) { - return IMPL.getYVelocity(tracker, pointerId); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/VelocityTrackerCompatHoneycomb.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/VelocityTrackerCompatHoneycomb.java deleted file mode 100644 index 4f9d326c..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/VelocityTrackerCompatHoneycomb.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.view; - -import android.view.VelocityTracker; - -/** - * Implementation of velocity tracker compatibility that can call Honeycomb APIs. - */ -class VelocityTrackerCompatHoneycomb { - public static float getXVelocity(VelocityTracker tracker, int pointerId) { - return tracker.getXVelocity(pointerId); - } - public static float getYVelocity(VelocityTracker tracker, int pointerId) { - return tracker.getYVelocity(pointerId); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewConfigurationCompat.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewConfigurationCompat.java deleted file mode 100644 index 14446621..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewConfigurationCompat.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.view; - -import android.view.ViewConfiguration; - -/** - * Helper for accessing newer features in ViewConfiguration. - */ -public class ViewConfigurationCompat { - /** - * Interface for the full API. - */ - interface ViewConfigurationVersionImpl { - public int getScaledPagingTouchSlop(ViewConfiguration config); - } - - /** - * Interface implementation that doesn't use anything about v4 APIs. - */ - static class BaseViewConfigurationVersionImpl implements ViewConfigurationVersionImpl { - @Override - public int getScaledPagingTouchSlop(ViewConfiguration config) { - return config.getScaledTouchSlop(); - } - } - - /** - * Interface implementation for devices with at least v11 APIs. - */ - static class FroyoViewConfigurationVersionImpl implements ViewConfigurationVersionImpl { - @Override - public int getScaledPagingTouchSlop(ViewConfiguration config) { - return ViewConfigurationCompatFroyo.getScaledPagingTouchSlop(config); - } - } - - /** - * Select the correct implementation to use for the current platform. - */ - static final ViewConfigurationVersionImpl IMPL; - static { - if (android.os.Build.VERSION.SDK_INT >= 11) { - IMPL = new FroyoViewConfigurationVersionImpl(); - } else { - IMPL = new BaseViewConfigurationVersionImpl(); - } - } - - // ------------------------------------------------------------------- - - /** - * Call {@link ViewConfiguration#getScaledPagingTouchSlop()}. - * If running on a pre-{@android.os.Build.VERSION_CODES#FROYO} device, - * returns {@link ViewConfiguration#getScaledTouchSlop()}. - */ - public static int getScaledPagingTouchSlop(ViewConfiguration config) { - return IMPL.getScaledPagingTouchSlop(config); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewConfigurationCompatFroyo.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewConfigurationCompatFroyo.java deleted file mode 100644 index e97a2a2e..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewConfigurationCompatFroyo.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.view; - -import android.view.ViewConfiguration; - -/** - * Implementation of menu compatibility that can call Honeycomb APIs. - */ -class ViewConfigurationCompatFroyo { - public static int getScaledPagingTouchSlop(ViewConfiguration config) { - return config.getScaledPagingTouchSlop(); - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewPager.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewPager.java deleted file mode 100644 index 9d69975a..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ViewPager.java +++ /dev/null @@ -1,996 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.view; - -import android.os.Build; -import android.os.Parcel; -import android.os.Parcelable; - -import android.content.Context; -import android.support.v4.os.ParcelableCompat; -import android.support.v4.os.ParcelableCompatCreatorCallbacks; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.VelocityTracker; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.widget.Scroller; - -import java.util.ArrayList; - -/** - * Layout manager that allows the user to flip left and right - * through pages of data. You supply an implementation of a - * {@link PagerAdapter} to generate the pages that the view shows. - * - *

Note this class is currently under early design and - * development. The API will likely change in later updates of - * the compatibility library, requiring changes to the source code - * of apps when they are compiled against the newer version.

- */ -public class ViewPager extends ViewGroup { - private static final String TAG = "ViewPager"; - private static final boolean DEBUG = false; - - private static final boolean USE_CACHE = false; - - static class ItemInfo { - Object object; - int position; - boolean scrolling; - } - - private final ArrayList mItems = new ArrayList(); - - private PagerAdapter mAdapter; - private int mCurItem; // Index of currently displayed page. - private int mRestoredCurItem = -1; - private Parcelable mRestoredAdapterState = null; - private ClassLoader mRestoredClassLoader = null; - private Scroller mScroller; - private PagerAdapter.DataSetObserver mObserver; - - private int mChildWidthMeasureSpec; - private int mChildHeightMeasureSpec; - private boolean mInLayout; - - private boolean mScrollingCacheEnabled; - - private boolean mPopulatePending; - private boolean mScrolling; - - private boolean mIsBeingDragged; - private boolean mIsUnableToDrag; - private int mTouchSlop; - private float mInitialMotionX; - /** - * Position of the last motion event. - */ - private float mLastMotionX; - private float mLastMotionY; - /** - * ID of the active pointer. This is used to retain consistency during - * drags/flings if multiple pointers are used. - */ - private int mActivePointerId = INVALID_POINTER; - /** - * Sentinel value for no current active pointer. - * Used by {@link #mActivePointerId}. - */ - private static final int INVALID_POINTER = -1; - - /** - * Determines speed during touch scrolling - */ - private VelocityTracker mVelocityTracker; - private int mMinimumVelocity; - private int mMaximumVelocity; - - private OnPageChangeListener mOnPageChangeListener; - - /** - * Indicates that the pager is in an idle, settled state. The current page - * is fully in view and no animation is in progress. - */ - public static final int SCROLL_STATE_IDLE = 0; - - /** - * Indicates that the pager is currently being dragged by the user. - */ - public static final int SCROLL_STATE_DRAGGING = 1; - - /** - * Indicates that the pager is in the process of settling to a final position. - */ - public static final int SCROLL_STATE_SETTLING = 2; - - private int mScrollState = SCROLL_STATE_IDLE; - - /** - * Callback interface for responding to changing state of the selected page. - */ - public interface OnPageChangeListener { - - /** - * This method will be invoked when the current page is scrolled, either as part - * of a programmatically initiated smooth scroll or a user initiated touch scroll. - * - * @param position Position index of the first page currently being displayed. - * Page position+1 will be visible if positionOffset is nonzero. - * @param positionOffset Value from [0, 1) indicating the offset from the page at position. - * @param positionOffsetPixels Value in pixels indicating the offset from position. - */ - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels); - - /** - * This method will be invoked when a new page becomes selected. Animation is not - * necessarily complete. - * - * @param position Position index of the new selected page. - */ - public void onPageSelected(int position); - - /** - * Called when the scroll state changes. Useful for discovering when the user - * begins dragging, when the pager is automatically settling to the current page, - * or when it is fully stopped/idle. - * - * @param state The new scroll state. - * @see ViewPager#SCROLL_STATE_IDLE - * @see ViewPager#SCROLL_STATE_DRAGGING - * @see ViewPager#SCROLL_STATE_SETTLING - */ - public void onPageScrollStateChanged(int state); - } - - /** - * Simple implementation of the {@link OnPageChangeListener} interface with stub - * implementations of each method. Extend this if you do not intend to override - * every method of {@link OnPageChangeListener}. - */ - public static class SimpleOnPageChangeListener implements OnPageChangeListener { - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - // This space for rent - } - - @Override - public void onPageSelected(int position) { - // This space for rent - } - - @Override - public void onPageScrollStateChanged(int state) { - // This space for rent - } - } - - public ViewPager(Context context) { - super(context); - initViewPager(); - } - - public ViewPager(Context context, AttributeSet attrs) { - super(context, attrs); - initViewPager(); - } - - void initViewPager() { - setWillNotDraw(false); - mScroller = new Scroller(getContext()); - final ViewConfiguration configuration = ViewConfiguration.get(getContext()); - mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); - mMinimumVelocity = configuration.getScaledMinimumFlingVelocity(); - mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); - } - - private void setScrollState(int newState) { - if (mScrollState == newState) { - return; - } - - mScrollState = newState; - if (mOnPageChangeListener != null) { - mOnPageChangeListener.onPageScrollStateChanged(newState); - } - } - - public void setAdapter(PagerAdapter adapter) { - if (mAdapter != null) { - mAdapter.setDataSetObserver(null); - } - - mAdapter = adapter; - - if (mAdapter != null) { - if (mObserver == null) { - mObserver = new DataSetObserver(); - } - mAdapter.setDataSetObserver(mObserver); - mPopulatePending = false; - if (mRestoredCurItem >= 0) { - mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader); - setCurrentItemInternal(mRestoredCurItem, false, true); - mRestoredCurItem = -1; - mRestoredAdapterState = null; - mRestoredClassLoader = null; - } else { - populate(); - } - } - } - - public PagerAdapter getAdapter() { - return mAdapter; - } - - public void setCurrentItem(int item) { - mPopulatePending = false; - setCurrentItemInternal(item, true, false); - } - - void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) { - if (mAdapter == null || mAdapter.getCount() <= 0) { - setScrollingCacheEnabled(false); - return; - } - if (!always && mCurItem == item && mItems.size() != 0) { - setScrollingCacheEnabled(false); - return; - } - if (item < 0) { - item = 0; - } else if (item >= mAdapter.getCount()) { - item = mAdapter.getCount() - 1; - } - if (item > (mCurItem+1) || item < (mCurItem-1)) { - // We are doing a jump by more than one page. To avoid - // glitches, we want to keep all current pages in the view - // until the scroll ends. - for (int i=0; i 0; - int newCurrItem = -1; - - for (int i = 0; i < mItems.size(); i++) { - final ItemInfo ii = mItems.get(i); - final int newPos = mAdapter.getItemPosition(ii.object); - - if (newPos == PagerAdapter.POSITION_UNCHANGED) { - continue; - } - - if (newPos == PagerAdapter.POSITION_NONE) { - mItems.remove(i); - i--; - mAdapter.destroyItem(this, ii.position, ii.object); - needPopulate = true; - - if (mCurItem == ii.position) { - // Keep the current item in the valid range - newCurrItem = Math.max(0, Math.min(mCurItem, mAdapter.getCount() - 1)); - } - continue; - } - - if (ii.position != newPos) { - if (ii.position == mCurItem) { - // Our current item changed position. Follow it. - newCurrItem = newPos; - } - - ii.position = newPos; - needPopulate = true; - } - } - - if (newCurrItem >= 0) { - // TODO This currently causes a jump. - setCurrentItemInternal(newCurrItem, false, true); - needPopulate = true; - } - if (needPopulate) { - populate(); - requestLayout(); - } - } - - void populate() { - if (mAdapter == null) { - return; - } - - // Bail now if we are waiting to populate. This is to hold off - // on creating views from the time the user releases their finger to - // fling to a new position until we have finished the scroll to - // that position, avoiding glitches from happening at that point. - if (mPopulatePending) { - if (DEBUG) Log.i(TAG, "populate is pending, skipping for now..."); - return; - } - - // Also, don't populate until we are attached to a window. This is to - // avoid trying to populate before we have restored our view hierarchy - // state and conflicting with what is restored. - if (getWindowToken() == null) { - return; - } - - mAdapter.startUpdate(this); - - final int startPos = mCurItem > 0 ? mCurItem - 1 : mCurItem; - final int N = mAdapter.getCount(); - final int endPos = mCurItem < (N-1) ? mCurItem+1 : N-1; - - if (DEBUG) Log.v(TAG, "populating: startPos=" + startPos + " endPos=" + endPos); - - // Add and remove pages in the existing list. - int lastPos = -1; - for (int i=0; i endPos) && !ii.scrolling) { - if (DEBUG) Log.i(TAG, "removing: " + ii.position + " @ " + i); - mItems.remove(i); - i--; - mAdapter.destroyItem(this, ii.position, ii.object); - } else if (lastPos < endPos && ii.position > startPos) { - // The next item is outside of our range, but we have a gap - // between it and the last item where we want to have a page - // shown. Fill in the gap. - lastPos++; - if (lastPos < startPos) { - lastPos = startPos; - } - while (lastPos <= endPos && lastPos < ii.position) { - if (DEBUG) Log.i(TAG, "inserting: " + lastPos + " @ " + i); - addNewItem(lastPos, i); - lastPos++; - i++; - } - } - lastPos = ii.position; - } - - // Add any new pages we need at the end. - lastPos = mItems.size() > 0 ? mItems.get(mItems.size()-1).position : -1; - boolean first = (lastPos == -1); - if (lastPos < endPos) { - lastPos++; - lastPos = lastPos > startPos ? lastPos : startPos; - while (lastPos <= endPos) { - if (DEBUG) Log.i(TAG, "appending: " + lastPos); - addNewItem(lastPos, -1); - if (first && (lastPos == mCurItem)) { - //Creating first item for the first time - mAdapter.onItemSelected(mCurItem, mItems.get(mItems.size() - 1).object); - first = false; - } - lastPos++; - } - } - - if (DEBUG) { - Log.i(TAG, "Current page list:"); - for (int i=0; i CREATOR - = ParcelableCompat.newCreator(new ParcelableCompatCreatorCallbacks() { - @Override - public SavedState createFromParcel(Parcel in, ClassLoader loader) { - return new SavedState(in, loader); - } - @Override - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }); - - SavedState(Parcel in, ClassLoader loader) { - super(in); - if (loader == null) { - loader = getClass().getClassLoader(); - } - position = in.readInt(); - adapterState = in.readParcelable(loader); - this.loader = loader; - } - } - - @Override - public Parcelable onSaveInstanceState() { - Parcelable superState = super.onSaveInstanceState(); - SavedState ss = new SavedState(superState); - ss.position = mCurItem; - ss.adapterState = mAdapter.saveState(); - return ss; - } - - @Override - public void onRestoreInstanceState(Parcelable state) { - if (!(state instanceof SavedState)) { - super.onRestoreInstanceState(state); - return; - } - - SavedState ss = (SavedState)state; - super.onRestoreInstanceState(ss.getSuperState()); - - if (mAdapter != null) { - mAdapter.restoreState(ss.adapterState, ss.loader); - setCurrentItemInternal(ss.position, false, true); - } else { - mRestoredCurItem = ss.position; - mRestoredAdapterState = ss.adapterState; - mRestoredClassLoader = ss.loader; - } - } - - @Override - public void addView(View child, int index, LayoutParams params) { - if (mInLayout) { - addViewInLayout(child, index, params); - child.measure(mChildWidthMeasureSpec, mChildHeightMeasureSpec); - } else { - super.addView(child, index, params); - } - - if (USE_CACHE) { - if (child.getVisibility() != GONE) { - child.setDrawingCacheEnabled(mScrollingCacheEnabled); - } else { - child.setDrawingCacheEnabled(false); - } - } - } - - ItemInfo infoForChild(View child) { - for (int i=0; i Build.VERSION_CODES.DONUT) { - // If we don't have a valid id, the touch down wasn't on content. - break; - } - - final int pointerIndex = MotionEventCompat.findPointerIndex(ev, activePointerId); - final float x = MotionEventCompat.getX(ev, pointerIndex); - final float dx = x - mLastMotionX; - final float xDiff = Math.abs(dx); - final float y = MotionEventCompat.getY(ev, pointerIndex); - final float yDiff = Math.abs(y - mLastMotionY); - if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); - - if (xDiff > mTouchSlop && xDiff > yDiff) { - if (DEBUG) Log.v(TAG, "Starting drag!"); - mIsBeingDragged = true; - setScrollState(SCROLL_STATE_DRAGGING); - mLastMotionX = x; - setScrollingCacheEnabled(true); - } else { - if (yDiff > mTouchSlop) { - // The finger has moved enough in the vertical - // direction to be counted as a drag... abort - // any attempt to drag horizontally, to work correctly - // with children that have scrolling containers. - if (DEBUG) Log.v(TAG, "Starting unable to drag!"); - mIsUnableToDrag = true; - } - } - break; - } - - case MotionEvent.ACTION_DOWN: { - /* - * Remember location of down touch. - * ACTION_DOWN always refers to pointer index 0. - */ - mLastMotionX = mInitialMotionX = ev.getX(); - mLastMotionY = ev.getY(); - mActivePointerId = MotionEventCompat.getPointerId(ev, 0); - - if (mScrollState == SCROLL_STATE_SETTLING) { - // Let the user 'catch' the pager as it animates. - mIsBeingDragged = true; - mIsUnableToDrag = false; - setScrollState(SCROLL_STATE_DRAGGING); - } else { - completeScroll(); - mIsBeingDragged = false; - mIsUnableToDrag = false; - } - - if (DEBUG) Log.v(TAG, "Down at " + mLastMotionX + "," + mLastMotionY - + " mIsBeingDragged=" + mIsBeingDragged - + "mIsUnableToDrag=" + mIsUnableToDrag); - break; - } - - case MotionEventCompat.ACTION_POINTER_UP: - onSecondaryPointerUp(ev); - break; - } - - /* - * The only time we want to intercept motion events is if we are in the - * drag mode. - */ - return mIsBeingDragged; - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - - if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) { - // Don't handle edge touches immediately -- they may actually belong to one of our - // descendants. - return false; - } - - if (mAdapter == null || mAdapter.getCount() == 0) { - // Nothing to present or scroll; nothing to touch. - return false; - } - - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain(); - } - mVelocityTracker.addMovement(ev); - - final int action = ev.getAction(); - - switch (action & MotionEventCompat.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: { - /* - * If being flinged and user touches, stop the fling. isFinished - * will be false if being flinged. - */ - completeScroll(); - - // Remember where the motion event started - mLastMotionX = mInitialMotionX = ev.getX(); - mActivePointerId = MotionEventCompat.getPointerId(ev, 0); - break; - } - case MotionEvent.ACTION_MOVE: - if (!mIsBeingDragged) { - final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); - final float x = MotionEventCompat.getX(ev, pointerIndex); - final float xDiff = Math.abs(x - mLastMotionX); - final float y = MotionEventCompat.getY(ev, pointerIndex); - final float yDiff = Math.abs(y - mLastMotionY); - if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff); - if (xDiff > mTouchSlop && xDiff > yDiff) { - if (DEBUG) Log.v(TAG, "Starting drag!"); - mIsBeingDragged = true; - mLastMotionX = x; - setScrollState(SCROLL_STATE_DRAGGING); - setScrollingCacheEnabled(true); - } - } - if (mIsBeingDragged) { - // Scroll to follow the motion event - final int activePointerIndex = MotionEventCompat.findPointerIndex( - ev, mActivePointerId); - final float x = MotionEventCompat.getX(ev, activePointerIndex); - final float deltaX = mLastMotionX - x; - mLastMotionX = x; - float scrollX = getScrollX() + deltaX; - final int width = getWidth(); - - final float leftBound = Math.max(0, (mCurItem - 1) * width); - final float rightBound = - Math.min(mCurItem + 1, mAdapter.getCount() - 1) * width; - if (scrollX < leftBound) { - scrollX = leftBound; - } else if (scrollX > rightBound) { - scrollX = rightBound; - } - // Don't lose the rounded component - mLastMotionX += scrollX - (int) scrollX; - scrollTo((int) scrollX, getScrollY()); - if (mOnPageChangeListener != null) { - final int position = (int) scrollX / width; - final int positionOffsetPixels = (int) scrollX % width; - final float positionOffset = (float) positionOffsetPixels / width; - mOnPageChangeListener.onPageScrolled(position, positionOffset, - positionOffsetPixels); - } - } - break; - case MotionEvent.ACTION_UP: - if (mIsBeingDragged) { - final VelocityTracker velocityTracker = mVelocityTracker; - velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); - int initialVelocity = (int)VelocityTrackerCompat.getYVelocity( - velocityTracker, mActivePointerId); - mPopulatePending = true; - if ((Math.abs(initialVelocity) > mMinimumVelocity) - || Math.abs(mInitialMotionX-mLastMotionX) >= (getWidth()/3)) { - if (mLastMotionX > mInitialMotionX) { - setCurrentItemInternal(mCurItem-1, true, true); - } else { - setCurrentItemInternal(mCurItem+1, true, true); - } - } else { - setCurrentItemInternal(mCurItem, true, true); - } - - mActivePointerId = INVALID_POINTER; - endDrag(); - } - break; - case MotionEvent.ACTION_CANCEL: - if (mIsBeingDragged) { - setCurrentItemInternal(mCurItem, true, true); - mActivePointerId = INVALID_POINTER; - endDrag(); - } - break; - case MotionEventCompat.ACTION_POINTER_DOWN: { - final int index = MotionEventCompat.getActionIndex(ev); - final float x = MotionEventCompat.getX(ev, index); - mLastMotionX = x; - mActivePointerId = MotionEventCompat.getPointerId(ev, index); - break; - } - case MotionEventCompat.ACTION_POINTER_UP: - onSecondaryPointerUp(ev); - mLastMotionX = MotionEventCompat.getX(ev, - MotionEventCompat.findPointerIndex(ev, mActivePointerId)); - break; - } - return true; - } - - private void onSecondaryPointerUp(MotionEvent ev) { - final int pointerIndex = MotionEventCompat.getActionIndex(ev); - final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); - if (pointerId == mActivePointerId) { - // This was our active pointer going up. Choose a new - // active pointer and adjust accordingly. - final int newPointerIndex = pointerIndex == 0 ? 1 : 0; - mLastMotionX = MotionEventCompat.getX(ev, newPointerIndex); - mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); - if (mVelocityTracker != null) { - mVelocityTracker.clear(); - } - } - } - - private void endDrag() { - mIsBeingDragged = false; - mIsUnableToDrag = false; - - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } - } - - private void setScrollingCacheEnabled(boolean enabled) { - if (mScrollingCacheEnabled != enabled) { - mScrollingCacheEnabled = enabled; - if (USE_CACHE) { - final int size = getChildCount(); - for (int i = 0; i < size; ++i) { - final View child = getChildAt(i); - if (child.getVisibility() != GONE) { - child.setDrawingCacheEnabled(enabled); - } - } - } - } - } - - private class DataSetObserver implements PagerAdapter.DataSetObserver { - @Override - public void onDataSetChanged() { - dataSetChanged(); - } - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/CursorAdapter.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/CursorAdapter.java deleted file mode 100644 index 9c6b8184..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/CursorAdapter.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.widget; - -import android.content.Context; -import android.database.ContentObserver; -import android.database.Cursor; -import android.database.DataSetObserver; -import android.os.Handler; -import android.util.Config; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.Filter; -import android.widget.FilterQueryProvider; -import android.widget.Filterable; - -/** - * Static library support version of the framework's {@link android.widget.CursorAdapter}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - */ -public abstract class CursorAdapter extends BaseAdapter implements Filterable, - CursorFilter.CursorFilterClient { - /** - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected boolean mDataValid; - /** - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected boolean mAutoRequery; - /** - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected Cursor mCursor; - /** - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected Context mContext; - /** - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected int mRowIDColumn; - /** - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected ChangeObserver mChangeObserver; - /** - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected DataSetObserver mDataSetObserver; - /** - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected CursorFilter mCursorFilter; - /** - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected FilterQueryProvider mFilterQueryProvider; - - /** - * If set the adapter will call requery() on the cursor whenever a content change - * notification is delivered. Implies {@link #FLAG_REGISTER_CONTENT_OBSERVER}. - * - * @deprecated This option is discouraged, as it results in Cursor queries - * being performed on the application's UI thread and thus can cause poor - * responsiveness or even Application Not Responding errors. As an alternative, - * use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}. - */ - @Deprecated - public static final int FLAG_AUTO_REQUERY = 0x01; - - /** - * If set the adapter will register a content observer on the cursor and will call - * {@link #onContentChanged()} when a notification comes in. Be careful when - * using this flag: you will need to unset the current Cursor from the adapter - * to avoid leaks due to its registered observers. This flag is not needed - * when using a CursorAdapter with a - * {@link android.content.CursorLoader}. - */ - public static final int FLAG_REGISTER_CONTENT_OBSERVER = 0x02; - - /** - * Constructor that always enables auto-requery. - * - * @deprecated This option is discouraged, as it results in Cursor queries - * being performed on the application's UI thread and thus can cause poor - * responsiveness or even Application Not Responding errors. As an alternative, - * use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}. - * - * @param c The cursor from which to get the data. - * @param context The context - */ - @Deprecated - public CursorAdapter(Context context, Cursor c) { - init(context, c, FLAG_AUTO_REQUERY); - } - - /** - * Constructor that allows control over auto-requery. It is recommended - * you not use this, but instead {@link #CursorAdapter(Context, Cursor, int)}. - * When using this constructor, {@link #FLAG_REGISTER_CONTENT_OBSERVER} - * will always be set. - * - * @param c The cursor from which to get the data. - * @param context The context - * @param autoRequery If true the adapter will call requery() on the - * cursor whenever it changes so the most recent - * data is always displayed. Using true here is discouraged. - */ - public CursorAdapter(Context context, Cursor c, boolean autoRequery) { - init(context, c, autoRequery ? FLAG_AUTO_REQUERY : FLAG_REGISTER_CONTENT_OBSERVER); - } - - /** - * Recommended constructor. - * - * @param c The cursor from which to get the data. - * @param context The context - * @param flags Flags used to determine the behavior of the adapter; may - * be any combination of {@link #FLAG_AUTO_REQUERY} and - * {@link #FLAG_REGISTER_CONTENT_OBSERVER}. - */ - public CursorAdapter(Context context, Cursor c, int flags) { - init(context, c, flags); - } - - /** - * @deprecated Don't use this, use the normal constructor. This will - * be removed in the future. - */ - @Deprecated - protected void init(Context context, Cursor c, boolean autoRequery) { - init(context, c, autoRequery ? FLAG_AUTO_REQUERY : FLAG_REGISTER_CONTENT_OBSERVER); - } - - void init(Context context, Cursor c, int flags) { - if ((flags & FLAG_AUTO_REQUERY) == FLAG_AUTO_REQUERY) { - flags |= FLAG_REGISTER_CONTENT_OBSERVER; - mAutoRequery = true; - } else { - mAutoRequery = false; - } - boolean cursorPresent = c != null; - mCursor = c; - mDataValid = cursorPresent; - mContext = context; - mRowIDColumn = cursorPresent ? c.getColumnIndexOrThrow("_id") : -1; - if ((flags & FLAG_REGISTER_CONTENT_OBSERVER) == FLAG_REGISTER_CONTENT_OBSERVER) { - mChangeObserver = new ChangeObserver(); - mDataSetObserver = new MyDataSetObserver(); - } else { - mChangeObserver = null; - mDataSetObserver = null; - } - - if (cursorPresent) { - if (mChangeObserver != null) c.registerContentObserver(mChangeObserver); - if (mDataSetObserver != null) c.registerDataSetObserver(mDataSetObserver); - } - } - - /** - * Returns the cursor. - * @return the cursor. - */ - public Cursor getCursor() { - return mCursor; - } - - /** - * @see android.widget.ListAdapter#getCount() - */ - public int getCount() { - if (mDataValid && mCursor != null) { - return mCursor.getCount(); - } else { - return 0; - } - } - - /** - * @see android.widget.ListAdapter#getItem(int) - */ - public Object getItem(int position) { - if (mDataValid && mCursor != null) { - mCursor.moveToPosition(position); - return mCursor; - } else { - return null; - } - } - - /** - * @see android.widget.ListAdapter#getItemId(int) - */ - public long getItemId(int position) { - if (mDataValid && mCursor != null) { - if (mCursor.moveToPosition(position)) { - return mCursor.getLong(mRowIDColumn); - } else { - return 0; - } - } else { - return 0; - } - } - - @Override - public boolean hasStableIds() { - return true; - } - - /** - * @see android.widget.ListAdapter#getView(int, View, ViewGroup) - */ - public View getView(int position, View convertView, ViewGroup parent) { - if (!mDataValid) { - throw new IllegalStateException("this should only be called when the cursor is valid"); - } - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("couldn't move cursor to position " + position); - } - View v; - if (convertView == null) { - v = newView(mContext, mCursor, parent); - } else { - v = convertView; - } - bindView(v, mContext, mCursor); - return v; - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - if (mDataValid) { - mCursor.moveToPosition(position); - View v; - if (convertView == null) { - v = newDropDownView(mContext, mCursor, parent); - } else { - v = convertView; - } - bindView(v, mContext, mCursor); - return v; - } else { - return null; - } - } - - /** - * Makes a new view to hold the data pointed to by cursor. - * @param context Interface to application's global information - * @param cursor The cursor from which to get the data. The cursor is already - * moved to the correct position. - * @param parent The parent to which the new view is attached to - * @return the newly created view. - */ - public abstract View newView(Context context, Cursor cursor, ViewGroup parent); - - /** - * Makes a new drop down view to hold the data pointed to by cursor. - * @param context Interface to application's global information - * @param cursor The cursor from which to get the data. The cursor is already - * moved to the correct position. - * @param parent The parent to which the new view is attached to - * @return the newly created view. - */ - public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) { - return newView(context, cursor, parent); - } - - /** - * Bind an existing view to the data pointed to by cursor - * @param view Existing view, returned earlier by newView - * @param context Interface to application's global information - * @param cursor The cursor from which to get the data. The cursor is already - * moved to the correct position. - */ - public abstract void bindView(View view, Context context, Cursor cursor); - - /** - * Change the underlying cursor to a new cursor. If there is an existing cursor it will be - * closed. - * - * @param cursor The new cursor to be used - */ - public void changeCursor(Cursor cursor) { - Cursor old = swapCursor(cursor); - if (old != null) { - old.close(); - } - } - - /** - * Swap in a new Cursor, returning the old Cursor. Unlike - * {@link #changeCursor(Cursor)}, the returned old Cursor is not - * closed. - * - * @param newCursor The new cursor to be used. - * @return Returns the previously set Cursor, or null if there wasa not one. - * If the given new Cursor is the same instance is the previously set - * Cursor, null is also returned. - */ - public Cursor swapCursor(Cursor newCursor) { - if (newCursor == mCursor) { - return null; - } - Cursor oldCursor = mCursor; - if (oldCursor != null) { - if (mChangeObserver != null) oldCursor.unregisterContentObserver(mChangeObserver); - if (mDataSetObserver != null) oldCursor.unregisterDataSetObserver(mDataSetObserver); - } - mCursor = newCursor; - if (newCursor != null) { - if (mChangeObserver != null) newCursor.registerContentObserver(mChangeObserver); - if (mDataSetObserver != null) newCursor.registerDataSetObserver(mDataSetObserver); - mRowIDColumn = newCursor.getColumnIndexOrThrow("_id"); - mDataValid = true; - // notify the observers about the new cursor - notifyDataSetChanged(); - } else { - mRowIDColumn = -1; - mDataValid = false; - // notify the observers about the lack of a data set - notifyDataSetInvalidated(); - } - return oldCursor; - } - - /** - *

Converts the cursor into a CharSequence. Subclasses should override this - * method to convert their results. The default implementation returns an - * empty String for null values or the default String representation of - * the value.

- * - * @param cursor the cursor to convert to a CharSequence - * @return a CharSequence representing the value - */ - public CharSequence convertToString(Cursor cursor) { - return cursor == null ? "" : cursor.toString(); - } - - /** - * Runs a query with the specified constraint. This query is requested - * by the filter attached to this adapter. - * - * The query is provided by a - * {@link android.widget.FilterQueryProvider}. - * If no provider is specified, the current cursor is not filtered and returned. - * - * After this method returns the resulting cursor is passed to {@link #changeCursor(Cursor)} - * and the previous cursor is closed. - * - * This method is always executed on a background thread, not on the - * application's main thread (or UI thread.) - * - * Contract: when constraint is null or empty, the original results, - * prior to any filtering, must be returned. - * - * @param constraint the constraint with which the query must be filtered - * - * @return a Cursor representing the results of the new query - * - * @see #getFilter() - * @see #getFilterQueryProvider() - * @see #setFilterQueryProvider(android.widget.FilterQueryProvider) - */ - public Cursor runQueryOnBackgroundThread(CharSequence constraint) { - if (mFilterQueryProvider != null) { - return mFilterQueryProvider.runQuery(constraint); - } - - return mCursor; - } - - public Filter getFilter() { - if (mCursorFilter == null) { - mCursorFilter = new CursorFilter(this); - } - return mCursorFilter; - } - - /** - * Returns the query filter provider used for filtering. When the - * provider is null, no filtering occurs. - * - * @return the current filter query provider or null if it does not exist - * - * @see #setFilterQueryProvider(android.widget.FilterQueryProvider) - * @see #runQueryOnBackgroundThread(CharSequence) - */ - public FilterQueryProvider getFilterQueryProvider() { - return mFilterQueryProvider; - } - - /** - * Sets the query filter provider used to filter the current Cursor. - * The provider's - * {@link android.widget.FilterQueryProvider#runQuery(CharSequence)} - * method is invoked when filtering is requested by a client of - * this adapter. - * - * @param filterQueryProvider the filter query provider or null to remove it - * - * @see #getFilterQueryProvider() - * @see #runQueryOnBackgroundThread(CharSequence) - */ - public void setFilterQueryProvider(FilterQueryProvider filterQueryProvider) { - mFilterQueryProvider = filterQueryProvider; - } - - /** - * Called when the {@link ContentObserver} on the cursor receives a change notification. - * The default implementation provides the auto-requery logic, but may be overridden by - * sub classes. - * - * @see ContentObserver#onChange(boolean) - */ - protected void onContentChanged() { - if (mAutoRequery && mCursor != null && !mCursor.isClosed()) { - if (Config.LOGV) Log.v("Cursor", "Auto requerying " + mCursor + " due to update"); - mDataValid = mCursor.requery(); - } - } - - private class ChangeObserver extends ContentObserver { - public ChangeObserver() { - super(new Handler()); - } - - @Override - public boolean deliverSelfNotifications() { - return true; - } - - @Override - public void onChange(boolean selfChange) { - onContentChanged(); - } - } - - private class MyDataSetObserver extends DataSetObserver { - @Override - public void onChanged() { - mDataValid = true; - notifyDataSetChanged(); - } - - @Override - public void onInvalidated() { - mDataValid = false; - notifyDataSetInvalidated(); - } - } - -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/CursorFilter.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/CursorFilter.java deleted file mode 100644 index 69b87be2..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/CursorFilter.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.widget; - -import android.database.Cursor; -import android.widget.Filter; - -/** - *

The CursorFilter delegates most of the work to the CursorAdapter. - * Subclasses should override these delegate methods to run the queries - * and convert the results into String that can be used by auto-completion - * widgets.

- */ -class CursorFilter extends Filter { - - CursorFilterClient mClient; - - interface CursorFilterClient { - CharSequence convertToString(Cursor cursor); - Cursor runQueryOnBackgroundThread(CharSequence constraint); - Cursor getCursor(); - void changeCursor(Cursor cursor); - } - - CursorFilter(CursorFilterClient client) { - mClient = client; - } - - @Override - public CharSequence convertResultToString(Object resultValue) { - return mClient.convertToString((Cursor) resultValue); - } - - @Override - protected FilterResults performFiltering(CharSequence constraint) { - Cursor cursor = mClient.runQueryOnBackgroundThread(constraint); - - FilterResults results = new FilterResults(); - if (cursor != null) { - results.count = cursor.getCount(); - results.values = cursor; - } else { - results.count = 0; - results.values = null; - } - return results; - } - - @Override - protected void publishResults(CharSequence constraint, FilterResults results) { - Cursor oldCursor = mClient.getCursor(); - - if (results.values != null && results.values != oldCursor) { - mClient.changeCursor((Cursor) results.values); - } - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/ResourceCursorAdapter.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/ResourceCursorAdapter.java deleted file mode 100644 index 12dce787..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/ResourceCursorAdapter.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.widget; - -import android.content.Context; -import android.database.Cursor; -import android.view.View; -import android.view.ViewGroup; -import android.view.LayoutInflater; - -/** - * Static library support version of the framework's {@link android.widget.ResourceCursorAdapter}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - */ -public abstract class ResourceCursorAdapter extends CursorAdapter { - private int mLayout; - - private int mDropDownLayout; - - private LayoutInflater mInflater; - - /** - * Constructor the enables auto-requery. - * - * @deprecated This option is discouraged, as it results in Cursor queries - * being performed on the application's UI thread and thus can cause poor - * responsiveness or even Application Not Responding errors. As an alternative, - * use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}. - * - * @param context The context where the ListView associated with this adapter is running - * @param layout resource identifier of a layout file that defines the views - * for this list item. Unless you override them later, this will - * define both the item views and the drop down views. - */ - @Deprecated - public ResourceCursorAdapter(Context context, int layout, Cursor c) { - super(context, c); - mLayout = mDropDownLayout = layout; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - /** - * Constructor with default behavior as per - * {@link CursorAdapter#CursorAdapter(Context, Cursor, boolean)}; it is recommended - * you not use this, but instead {@link #ResourceCursorAdapter(Context, int, Cursor, int)}. - * When using this constructor, {@link #FLAG_REGISTER_CONTENT_OBSERVER} - * will always be set. - * - * @param context The context where the ListView associated with this adapter is running - * @param layout resource identifier of a layout file that defines the views - * for this list item. Unless you override them later, this will - * define both the item views and the drop down views. - * @param c The cursor from which to get the data. - * @param autoRequery If true the adapter will call requery() on the - * cursor whenever it changes so the most recent - * data is always displayed. Using true here is discouraged. - */ - public ResourceCursorAdapter(Context context, int layout, Cursor c, boolean autoRequery) { - super(context, c, autoRequery); - mLayout = mDropDownLayout = layout; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - /** - * Standard constructor. - * - * @param context The context where the ListView associated with this adapter is running - * @param layout Resource identifier of a layout file that defines the views - * for this list item. Unless you override them later, this will - * define both the item views and the drop down views. - * @param c The cursor from which to get the data. - * @param flags Flags used to determine the behavior of the adapter, - * as per {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}. - */ - public ResourceCursorAdapter(Context context, int layout, Cursor c, int flags) { - super(context, c, flags); - mLayout = mDropDownLayout = layout; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - /** - * Inflates view(s) from the specified XML file. - * - * @see android.widget.CursorAdapter#newView(android.content.Context, - * android.database.Cursor, ViewGroup) - */ - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(mLayout, parent, false); - } - - @Override - public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(mDropDownLayout, parent, false); - } - - /** - *

Sets the layout resource of the item views.

- * - * @param layout the layout resources used to create item views - */ - public void setViewResource(int layout) { - mLayout = layout; - } - - /** - *

Sets the layout resource of the drop down views.

- * - * @param dropDownLayout the layout resources used to create drop down views - */ - public void setDropDownViewResource(int dropDownLayout) { - mDropDownLayout = dropDownLayout; - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/SimpleCursorAdapter.java b/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/SimpleCursorAdapter.java deleted file mode 100644 index 4b81b11f..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/widget/SimpleCursorAdapter.java +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.widget; - -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -/** - * Static library support version of the framework's {@link android.widget.SimpleCursorAdapter}. - * Used to write apps that run on platforms prior to Android 3.0. When running - * on Android 3.0 or above, this implementation is still used; it does not try - * to switch to the framework's implementation. See the framework SDK - * documentation for a class overview. - */ -public class SimpleCursorAdapter extends ResourceCursorAdapter { - /** - * A list of columns containing the data to bind to the UI. - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected int[] mFrom; - /** - * A list of View ids representing the views to which the data must be bound. - * This field should be made private, so it is hidden from the SDK. - * {@hide} - */ - protected int[] mTo; - - private int mStringConversionColumn = -1; - private CursorToStringConverter mCursorToStringConverter; - private ViewBinder mViewBinder; - - String[] mOriginalFrom; - - /** - * Constructor the enables auto-requery. - * - * @deprecated This option is discouraged, as it results in Cursor queries - * being performed on the application's UI thread and thus can cause poor - * responsiveness or even Application Not Responding errors. As an alternative, - * use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}. - */ - @Deprecated - public SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { - super(context, layout, c); - mTo = to; - mOriginalFrom = from; - findColumns(from); - } - - /** - * Standard constructor. - * - * @param context The context where the ListView associated with this - * SimpleListItemFactory is running - * @param layout resource identifier of a layout file that defines the views - * for this list item. The layout file should include at least - * those named views defined in "to" - * @param c The database cursor. Can be null if the cursor is not available yet. - * @param from A list of column names representing the data to bind to the UI. Can be null - * if the cursor is not available yet. - * @param to The views that should display column in the "from" parameter. - * These should all be TextViews. The first N views in this list - * are given the values of the first N columns in the from - * parameter. Can be null if the cursor is not available yet. - * @param flags Flags used to determine the behavior of the adapter, - * as per {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}. - */ - public SimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, - int[] to, int flags) { - super(context, layout, c, flags); - mTo = to; - mOriginalFrom = from; - findColumns(from); - } - - /** - * Binds all of the field names passed into the "to" parameter of the - * constructor with their corresponding cursor columns as specified in the - * "from" parameter. - * - * Binding occurs in two phases. First, if a - * {@link android.widget.SimpleCursorAdapter.ViewBinder} is available, - * {@link ViewBinder#setViewValue(android.view.View, android.database.Cursor, int)} - * is invoked. If the returned value is true, binding has occured. If the - * returned value is false and the view to bind is a TextView, - * {@link #setViewText(TextView, String)} is invoked. If the returned value is - * false and the view to bind is an ImageView, - * {@link #setViewImage(ImageView, String)} is invoked. If no appropriate - * binding can be found, an {@link IllegalStateException} is thrown. - * - * @throws IllegalStateException if binding cannot occur - * - * @see android.widget.CursorAdapter#bindView(android.view.View, - * android.content.Context, android.database.Cursor) - * @see #getViewBinder() - * @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder) - * @see #setViewImage(ImageView, String) - * @see #setViewText(TextView, String) - */ - @Override - public void bindView(View view, Context context, Cursor cursor) { - final ViewBinder binder = mViewBinder; - final int count = mTo.length; - final int[] from = mFrom; - final int[] to = mTo; - - for (int i = 0; i < count; i++) { - final View v = view.findViewById(to[i]); - if (v != null) { - boolean bound = false; - if (binder != null) { - bound = binder.setViewValue(v, cursor, from[i]); - } - - if (!bound) { - String text = cursor.getString(from[i]); - if (text == null) { - text = ""; - } - - if (v instanceof TextView) { - setViewText((TextView) v, text); - } else if (v instanceof ImageView) { - setViewImage((ImageView) v, text); - } else { - throw new IllegalStateException(v.getClass().getName() + " is not a " + - " view that can be bounds by this SimpleCursorAdapter"); - } - } - } - } - } - - /** - * Returns the {@link ViewBinder} used to bind data to views. - * - * @return a ViewBinder or null if the binder does not exist - * - * @see #bindView(android.view.View, android.content.Context, android.database.Cursor) - * @see #setViewBinder(android.widget.SimpleCursorAdapter.ViewBinder) - */ - public ViewBinder getViewBinder() { - return mViewBinder; - } - - /** - * Sets the binder used to bind data to views. - * - * @param viewBinder the binder used to bind data to views, can be null to - * remove the existing binder - * - * @see #bindView(android.view.View, android.content.Context, android.database.Cursor) - * @see #getViewBinder() - */ - public void setViewBinder(ViewBinder viewBinder) { - mViewBinder = viewBinder; - } - - /** - * Called by bindView() to set the image for an ImageView but only if - * there is no existing ViewBinder or if the existing ViewBinder cannot - * handle binding to an ImageView. - * - * By default, the value will be treated as an image resource. If the - * value cannot be used as an image resource, the value is used as an - * image Uri. - * - * Intended to be overridden by Adapters that need to filter strings - * retrieved from the database. - * - * @param v ImageView to receive an image - * @param value the value retrieved from the cursor - */ - public void setViewImage(ImageView v, String value) { - try { - v.setImageResource(Integer.parseInt(value)); - } catch (NumberFormatException nfe) { - v.setImageURI(Uri.parse(value)); - } - } - - /** - * Called by bindView() to set the text for a TextView but only if - * there is no existing ViewBinder or if the existing ViewBinder cannot - * handle binding to an TextView. - * - * Intended to be overridden by Adapters that need to filter strings - * retrieved from the database. - * - * @param v TextView to receive text - * @param text the text to be set for the TextView - */ - public void setViewText(TextView v, String text) { - v.setText(text); - } - - /** - * Return the index of the column used to get a String representation - * of the Cursor. - * - * @return a valid index in the current Cursor or -1 - * - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - * @see #setStringConversionColumn(int) - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getCursorToStringConverter() - */ - public int getStringConversionColumn() { - return mStringConversionColumn; - } - - /** - * Defines the index of the column in the Cursor used to get a String - * representation of that Cursor. The column is used to convert the - * Cursor to a String only when the current CursorToStringConverter - * is null. - * - * @param stringConversionColumn a valid index in the current Cursor or -1 to use the default - * conversion mechanism - * - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - * @see #getStringConversionColumn() - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getCursorToStringConverter() - */ - public void setStringConversionColumn(int stringConversionColumn) { - mStringConversionColumn = stringConversionColumn; - } - - /** - * Returns the converter used to convert the filtering Cursor - * into a String. - * - * @return null if the converter does not exist or an instance of - * {@link android.widget.SimpleCursorAdapter.CursorToStringConverter} - * - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getStringConversionColumn() - * @see #setStringConversionColumn(int) - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - */ - public CursorToStringConverter getCursorToStringConverter() { - return mCursorToStringConverter; - } - - /** - * Sets the converter used to convert the filtering Cursor - * into a String. - * - * @param cursorToStringConverter the Cursor to String converter, or - * null to remove the converter - * - * @see #setCursorToStringConverter(android.widget.SimpleCursorAdapter.CursorToStringConverter) - * @see #getStringConversionColumn() - * @see #setStringConversionColumn(int) - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - */ - public void setCursorToStringConverter(CursorToStringConverter cursorToStringConverter) { - mCursorToStringConverter = cursorToStringConverter; - } - - /** - * Returns a CharSequence representation of the specified Cursor as defined - * by the current CursorToStringConverter. If no CursorToStringConverter - * has been set, the String conversion column is used instead. If the - * conversion column is -1, the returned String is empty if the cursor - * is null or Cursor.toString(). - * - * @param cursor the Cursor to convert to a CharSequence - * - * @return a non-null CharSequence representing the cursor - */ - @Override - public CharSequence convertToString(Cursor cursor) { - if (mCursorToStringConverter != null) { - return mCursorToStringConverter.convertToString(cursor); - } else if (mStringConversionColumn > -1) { - return cursor.getString(mStringConversionColumn); - } - - return super.convertToString(cursor); - } - - /** - * Create a map from an array of strings to an array of column-id integers in mCursor. - * If mCursor is null, the array will be discarded. - * - * @param from the Strings naming the columns of interest - */ - private void findColumns(String[] from) { - if (mCursor != null) { - int i; - int count = from.length; - if (mFrom == null || mFrom.length != count) { - mFrom = new int[count]; - } - for (i = 0; i < count; i++) { - mFrom[i] = mCursor.getColumnIndexOrThrow(from[i]); - } - } else { - mFrom = null; - } - } - - @Override - public Cursor swapCursor(Cursor c) { - Cursor res = super.swapCursor(c); - // rescan columns in case cursor layout is different - findColumns(mOriginalFrom); - return res; - } - - /** - * Change the cursor and change the column-to-view mappings at the same time. - * - * @param c The database cursor. Can be null if the cursor is not available yet. - * @param from A list of column names representing the data to bind to the UI. Can be null - * if the cursor is not available yet. - * @param to The views that should display column in the "from" parameter. - * These should all be TextViews. The first N views in this list - * are given the values of the first N columns in the from - * parameter. Can be null if the cursor is not available yet. - */ - public void changeCursorAndColumns(Cursor c, String[] from, int[] to) { - mOriginalFrom = from; - mTo = to; - super.changeCursor(c); - findColumns(mOriginalFrom); - } - - /** - * This class can be used by external clients of SimpleCursorAdapter - * to bind values fom the Cursor to views. - * - * You should use this class to bind values from the Cursor to views - * that are not directly supported by SimpleCursorAdapter or to - * change the way binding occurs for views supported by - * SimpleCursorAdapter. - * - * @see SimpleCursorAdapter#bindView(android.view.View, android.content.Context, android.database.Cursor) - * @see SimpleCursorAdapter#setViewImage(ImageView, String) - * @see SimpleCursorAdapter#setViewText(TextView, String) - */ - public static interface ViewBinder { - /** - * Binds the Cursor column defined by the specified index to the specified view. - * - * When binding is handled by this ViewBinder, this method must return true. - * If this method returns false, SimpleCursorAdapter will attempts to handle - * the binding on its own. - * - * @param view the view to bind the data to - * @param cursor the cursor to get the data from - * @param columnIndex the column at which the data can be found in the cursor - * - * @return true if the data was bound to the view, false otherwise - */ - boolean setViewValue(View view, Cursor cursor, int columnIndex); - } - - /** - * This class can be used by external clients of SimpleCursorAdapter - * to define how the Cursor should be converted to a String. - * - * @see android.widget.CursorAdapter#convertToString(android.database.Cursor) - */ - public static interface CursorToStringConverter { - /** - * Returns a CharSequence representing the specified Cursor. - * - * @param cursor the cursor for which a CharSequence representation - * is requested - * - * @return a non-null CharSequence representing the cursor - */ - CharSequence convertToString(Cursor cursor); - } - -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/ActionBarSherlock.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/ActionBarSherlock.java new file mode 100644 index 00000000..ab160f83 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/ActionBarSherlock.java @@ -0,0 +1,794 @@ +package com.actionbarsherlock; + +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Iterator; +import android.app.Activity; +import android.content.Context; +import android.content.res.Configuration; +import android.os.Build; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.internal.ActionBarSherlockCompat; +import com.actionbarsherlock.internal.ActionBarSherlockNative; +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +/** + *

Helper for implementing the action bar design pattern across all versions + * of Android.

+ * + *

This class will manage interaction with a custom action bar based on the + * Android 4.0 source code. The exposed API mirrors that of its native + * counterpart and you should refer to its documentation for instruction.

+ * + * @author Jake Wharton + */ +public abstract class ActionBarSherlock { + protected static final String TAG = "ActionBarSherlock"; + protected static final boolean DEBUG = false; + + private static final Class[] CONSTRUCTOR_ARGS = new Class[] { Activity.class, int.class }; + private static final HashMap> IMPLEMENTATIONS = + new HashMap>(); + + static { + //Register our two built-in implementations + registerImplementation(ActionBarSherlockCompat.class); + registerImplementation(ActionBarSherlockNative.class); + } + + + /** + *

Denotes an implementation of ActionBarSherlock which provides an + * action bar-enhanced experience.

+ */ + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + public @interface Implementation { + static final int DEFAULT_API = -1; + static final int DEFAULT_DPI = -1; + + int api() default DEFAULT_API; + int dpi() default DEFAULT_DPI; + } + + + /** Activity interface for menu creation callback. */ + public interface OnCreatePanelMenuListener { + public boolean onCreatePanelMenu(int featureId, Menu menu); + } + /** Activity interface for menu creation callback. */ + public interface OnCreateOptionsMenuListener { + public boolean onCreateOptionsMenu(Menu menu); + } + /** Activity interface for menu item selection callback. */ + public interface OnMenuItemSelectedListener { + public boolean onMenuItemSelected(int featureId, MenuItem item); + } + /** Activity interface for menu item selection callback. */ + public interface OnOptionsItemSelectedListener { + public boolean onOptionsItemSelected(MenuItem item); + } + /** Activity interface for menu preparation callback. */ + public interface OnPreparePanelListener { + public boolean onPreparePanel(int featureId, View view, Menu menu); + } + /** Activity interface for menu preparation callback. */ + public interface OnPrepareOptionsMenuListener { + public boolean onPrepareOptionsMenu(Menu menu); + } + /** Activity interface for action mode finished callback. */ + public interface OnActionModeFinishedListener { + public void onActionModeFinished(ActionMode mode); + } + /** Activity interface for action mode started callback. */ + public interface OnActionModeStartedListener { + public void onActionModeStarted(ActionMode mode); + } + + + /** + * If set, the logic in these classes will assume that an {@link Activity} + * is dispatching all of the required events to the class. This flag should + * only be used internally or if you are creating your own base activity + * modeled after one of the included types (e.g., {@code SherlockActivity}). + */ + public static final int FLAG_DELEGATE = 1; + + + /** + * Register an ActionBarSherlock implementation. + * + * @param implementationClass Target implementation class which extends + * {@link ActionBarSherlock}. This class must also be annotated with + * {@link Implementation}. + */ + public static void registerImplementation(Class implementationClass) { + if (!implementationClass.isAnnotationPresent(Implementation.class)) { + throw new IllegalArgumentException("Class " + implementationClass.getSimpleName() + " is not annotated with @Implementation"); + } else if (IMPLEMENTATIONS.containsValue(implementationClass)) { + if (DEBUG) Log.w(TAG, "Class " + implementationClass.getSimpleName() + " already registered"); + return; + } + + Implementation impl = implementationClass.getAnnotation(Implementation.class); + if (DEBUG) Log.i(TAG, "Registering " + implementationClass.getSimpleName() + " with qualifier " + impl); + IMPLEMENTATIONS.put(impl, implementationClass); + } + + /** + * Unregister an ActionBarSherlock implementation. This should be + * considered very volatile and you should only use it if you know what + * you are doing. You have been warned. + * + * @param implementationClass Target implementation class. + * @return Boolean indicating whether the class was removed. + */ + public static boolean unregisterImplementation(Class implementationClass) { + return IMPLEMENTATIONS.values().remove(implementationClass); + } + + /** + * Wrap an activity with an action bar abstraction which will enable the + * use of a custom implementation on platforms where a native version does + * not exist. + * + * @param activity Activity to wrap. + * @return Instance to interact with the action bar. + */ + public static ActionBarSherlock wrap(Activity activity) { + return wrap(activity, 0); + } + + /** + * Wrap an activity with an action bar abstraction which will enable the + * use of a custom implementation on platforms where a native version does + * not exist. + * + * @param activity Owning activity. + * @param flags Option flags to control behavior. + * @return Instance to interact with the action bar. + */ + public static ActionBarSherlock wrap(Activity activity, int flags) { + //Create a local implementation map we can modify + HashMap> impls = + new HashMap>(IMPLEMENTATIONS); + boolean hasQualfier; + + /* DPI FILTERING */ + hasQualfier = false; + for (Implementation key : impls.keySet()) { + //Only honor TVDPI as a specific qualifier + if (key.dpi() == DisplayMetrics.DENSITY_TV) { + hasQualfier = true; + break; + } + } + if (hasQualfier) { + final boolean isTvDpi = activity.getResources().getDisplayMetrics().densityDpi == DisplayMetrics.DENSITY_TV; + for (Iterator keys = impls.keySet().iterator(); keys.hasNext(); ) { + int keyDpi = keys.next().dpi(); + if ((isTvDpi && keyDpi != DisplayMetrics.DENSITY_TV) + || (!isTvDpi && keyDpi == DisplayMetrics.DENSITY_TV)) { + keys.remove(); + } + } + } + + /* API FILTERING */ + hasQualfier = false; + for (Implementation key : impls.keySet()) { + if (key.api() != Implementation.DEFAULT_API) { + hasQualfier = true; + break; + } + } + if (hasQualfier) { + final int runtimeApi = Build.VERSION.SDK_INT; + int bestApi = 0; + for (Iterator keys = impls.keySet().iterator(); keys.hasNext(); ) { + int keyApi = keys.next().api(); + if (keyApi > runtimeApi) { + keys.remove(); + } else if (keyApi > bestApi) { + bestApi = keyApi; + } + } + for (Iterator keys = impls.keySet().iterator(); keys.hasNext(); ) { + if (keys.next().api() != bestApi) { + keys.remove(); + } + } + } + + if (impls.size() > 1) { + throw new IllegalStateException("More than one implementation matches configuration."); + } + if (impls.isEmpty()) { + throw new IllegalStateException("No implementations match configuration."); + } + Class impl = impls.values().iterator().next(); + if (DEBUG) Log.i(TAG, "Using implementation: " + impl.getSimpleName()); + + try { + Constructor ctor = impl.getConstructor(CONSTRUCTOR_ARGS); + return ctor.newInstance(activity, flags); + } catch (NoSuchMethodException e) { + throw new RuntimeException(e); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e); + } catch (InstantiationException e) { + throw new RuntimeException(e); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + + /** Activity which is displaying the action bar. Also used for context. */ + protected final Activity mActivity; + /** Whether delegating actions for the activity or managing ourselves. */ + protected final boolean mIsDelegate; + + /** Reference to our custom menu inflater which supports action items. */ + protected MenuInflater mMenuInflater; + + + + protected ActionBarSherlock(Activity activity, int flags) { + if (DEBUG) Log.d(TAG, "[] activity: " + activity + ", flags: " + flags); + + mActivity = activity; + mIsDelegate = (flags & FLAG_DELEGATE) != 0; + } + + + /** + * Get the current action bar instance. + * + * @return Action bar instance. + */ + public abstract ActionBar getActionBar(); + + + /////////////////////////////////////////////////////////////////////////// + // Lifecycle and interaction callbacks when delegating + /////////////////////////////////////////////////////////////////////////// + + /** + * Notify action bar of a configuration change event. Should be dispatched + * after the call to the superclass implementation. + * + *
+     * @Override
+     * public void onConfigurationChanged(Configuration newConfig) {
+     *     super.onConfigurationChanged(newConfig);
+     *     mSherlock.dispatchConfigurationChanged(newConfig);
+     * }
+     * 
+ * + * @param newConfig The new device configuration. + */ + public void dispatchConfigurationChanged(Configuration newConfig) {} + + /** + * Notify the action bar that the activity has finished its resuming. This + * should be dispatched after the call to the superclass implementation. + * + *
+     * @Override
+     * protected void onPostResume() {
+     *     super.onPostResume();
+     *     mSherlock.dispatchPostResume();
+     * }
+     * 
+ */ + public void dispatchPostResume() {} + + /** + * Notify the action bar that the activity is pausing. This should be + * dispatched before the call to the superclass implementation. + * + *
+     * @Override
+     * protected void onPause() {
+     *     mSherlock.dispatchPause();
+     *     super.onPause();
+     * }
+     * 
+ */ + public void dispatchPause() {} + + /** + * Notify the action bar that the activity is stopping. This should be + * called before the superclass implementation. + * + *

+ * @Override + * protected void onStop() { + * mSherlock.dispatchStop(); + * super.onStop(); + * } + *

+ */ + public void dispatchStop() {} + + /** + * Indicate that the menu should be recreated by calling + * {@link OnCreateOptionsMenuListener#onCreateOptionsMenu(com.actionbarsherlock.view.Menu)}. + */ + public abstract void dispatchInvalidateOptionsMenu(); + + /** + * Notify the action bar that it should display its overflow menu if it is + * appropriate for the device. The implementation should conditionally + * call the superclass method only if this method returns {@code false}. + * + *

+ * @Override + * public void openOptionsMenu() { + * if (!mSherlock.dispatchOpenOptionsMenu()) { + * super.openOptionsMenu(); + * } + * } + *

+ * + * @return {@code true} if the opening of the menu was handled internally. + */ + public boolean dispatchOpenOptionsMenu() { + return false; + } + + /** + * Notify the action bar that it should close its overflow menu if it is + * appropriate for the device. This implementation should conditionally + * call the superclass method only if this method returns {@code false}. + * + *
+     * @Override
+     * public void closeOptionsMenu() {
+     *     if (!mSherlock.dispatchCloseOptionsMenu()) {
+     *         super.closeOptionsMenu();
+     *     }
+     * }
+     * 
+ * + * @return {@code true} if the closing of the menu was handled internally. + */ + public boolean dispatchCloseOptionsMenu() { + return false; + } + + /** + * Notify the class that the activity has finished its creation. This + * should be called after the superclass implementation. + * + *
+     * @Override
+     * protected void onPostCreate(Bundle savedInstanceState) {
+     *     mSherlock.dispatchPostCreate(savedInstanceState);
+     *     super.onPostCreate(savedInstanceState);
+     * }
+     * 
+ * + * @param savedInstanceState If the activity is being re-initialized after + * previously being shut down then this Bundle + * contains the data it most recently supplied in + * {@link Activity#}onSaveInstanceState(Bundle)}. + * Note: Otherwise it is null. + */ + public void dispatchPostCreate(Bundle savedInstanceState) {} + + /** + * Notify the action bar that the title has changed and the action bar + * should be updated to reflect the change. This should be called before + * the superclass implementation. + * + *
+     *  @Override
+     *  protected void onTitleChanged(CharSequence title, int color) {
+     *      mSherlock.dispatchTitleChanged(title, color);
+     *      super.onTitleChanged(title, color);
+     *  }
+     * 
+ * + * @param title New activity title. + * @param color New activity color. + */ + public void dispatchTitleChanged(CharSequence title, int color) {} + + /** + * Notify the action bar the user has created a key event. This is used to + * toggle the display of the overflow action item with the menu key and to + * close the action mode or expanded action item with the back key. + * + *
+     * @Override
+     * public boolean dispatchKeyEvent(KeyEvent event) {
+     *     if (mSherlock.dispatchKeyEvent(event)) {
+     *         return true;
+     *     }
+     *     return super.dispatchKeyEvent(event);
+     * }
+     * 
+ * + * @param event Description of the key event. + * @return {@code true} if the event was handled. + */ + public boolean dispatchKeyEvent(KeyEvent event) { + return false; + } + + /** + * Notify the action bar that the Activity has triggered a menu creation + * which should happen on the conclusion of {@link Activity#onCreate}. This + * will be used to gain a reference to the native menu for native and + * overflow binding as well as to indicate when compatibility create should + * occur for the first time. + * + * @param menu Activity native menu. + * @return {@code true} since we always want to say that we have a native + */ + public abstract boolean dispatchCreateOptionsMenu(android.view.Menu menu); + + /** + * Notify the action bar that the Activity has triggered a menu preparation + * which usually means that the user has requested the overflow menu via a + * hardware menu key. You should return the result of this method call and + * not call the superclass implementation. + * + *

+ * @Override + * public final boolean onPrepareOptionsMenu(android.view.Menu menu) { + * return mSherlock.dispatchPrepareOptionsMenu(menu); + * } + *

+ * + * @param menu Activity native menu. + * @return {@code true} if menu display should proceed. + */ + public abstract boolean dispatchPrepareOptionsMenu(android.view.Menu menu); + + /** + * Notify the action bar that a native options menu item has been selected. + * The implementation should return the result of this method call. + * + *

+ * @Override + * public final boolean onOptionsItemSelected(android.view.MenuItem item) { + * return mSherlock.dispatchOptionsItemSelected(item); + * } + *

+ * + * @param item Options menu item. + * @return @{code true} if the selection was handled. + */ + public abstract boolean dispatchOptionsItemSelected(android.view.MenuItem item); + + /** + * Notify the action bar that the overflow menu has been opened. The + * implementation should conditionally return {@code true} if this method + * returns {@code true}, otherwise return the result of the superclass + * method. + * + *

+ * @Override + * public final boolean onMenuOpened(int featureId, android.view.Menu menu) { + * if (mSherlock.dispatchMenuOpened(featureId, menu)) { + * return true; + * } + * return super.onMenuOpened(featureId, menu); + * } + *

+ * + * @param featureId Window feature which triggered the event. + * @param menu Activity native menu. + * @return {@code true} if the event was handled by this method. + */ + public boolean dispatchMenuOpened(int featureId, android.view.Menu menu) { + return false; + } + + /** + * Notify the action bar that the overflow menu has been closed. This + * method should be called before the superclass implementation. + * + *

+ * @Override + * public void onPanelClosed(int featureId, android.view.Menu menu) { + * mSherlock.dispatchPanelClosed(featureId, menu); + * super.onPanelClosed(featureId, menu); + * } + *

+ * + * @param featureId + * @param menu + */ + public void dispatchPanelClosed(int featureId, android.view.Menu menu) {} + + /** + * Notify the action bar that the activity has been destroyed. This method + * should be called before the superclass implementation. + * + *

+ * @Override + * public void onDestroy() { + * mSherlock.dispatchDestroy(); + * super.onDestroy(); + * } + *

+ */ + public void dispatchDestroy() {} + + public void dispatchSaveInstanceState(Bundle outState) {} + + public void dispatchRestoreInstanceState(Bundle savedInstanceState) {} + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + + /** + * Internal method to trigger the menu creation process. + * + * @return {@code true} if menu creation should proceed. + */ + protected final boolean callbackCreateOptionsMenu(Menu menu) { + if (DEBUG) Log.d(TAG, "[callbackCreateOptionsMenu] menu: " + menu); + + boolean result = true; + if (mActivity instanceof OnCreatePanelMenuListener) { + OnCreatePanelMenuListener listener = (OnCreatePanelMenuListener)mActivity; + result = listener.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu); + } else if (mActivity instanceof OnCreateOptionsMenuListener) { + OnCreateOptionsMenuListener listener = (OnCreateOptionsMenuListener)mActivity; + result = listener.onCreateOptionsMenu(menu); + } + + if (DEBUG) Log.d(TAG, "[callbackCreateOptionsMenu] returning " + result); + return result; + } + + /** + * Internal method to trigger the menu preparation process. + * + * @return {@code true} if menu preparation should proceed. + */ + protected final boolean callbackPrepareOptionsMenu(Menu menu) { + if (DEBUG) Log.d(TAG, "[callbackPrepareOptionsMenu] menu: " + menu); + + boolean result = true; + if (mActivity instanceof OnPreparePanelListener) { + OnPreparePanelListener listener = (OnPreparePanelListener)mActivity; + result = listener.onPreparePanel(Window.FEATURE_OPTIONS_PANEL, null, menu); + } else if (mActivity instanceof OnPrepareOptionsMenuListener) { + OnPrepareOptionsMenuListener listener = (OnPrepareOptionsMenuListener)mActivity; + result = listener.onPrepareOptionsMenu(menu); + } + + if (DEBUG) Log.d(TAG, "[callbackPrepareOptionsMenu] returning " + result); + return result; + } + + /** + * Internal method for dispatching options menu selection to the owning + * activity callback. + * + * @param item Selected options menu item. + * @return {@code true} if the item selection was handled in the callback. + */ + protected final boolean callbackOptionsItemSelected(MenuItem item) { + if (DEBUG) Log.d(TAG, "[callbackOptionsItemSelected] item: " + item.getTitleCondensed()); + + boolean result = false; + if (mActivity instanceof OnMenuItemSelectedListener) { + OnMenuItemSelectedListener listener = (OnMenuItemSelectedListener)mActivity; + result = listener.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item); + } else if (mActivity instanceof OnOptionsItemSelectedListener) { + OnOptionsItemSelectedListener listener = (OnOptionsItemSelectedListener)mActivity; + result = listener.onOptionsItemSelected(item); + } + + if (DEBUG) Log.d(TAG, "[callbackOptionsItemSelected] returning " + result); + return result; + } + + + /////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + + /** + * Query for the availability of a certain feature. + * + * @param featureId The feature ID to check. + * @return {@code true} if feature is enabled, {@code false} otherwise. + */ + public abstract boolean hasFeature(int featureId); + + /** + * Enable extended screen features. This must be called before + * {@code setContentView()}. May be called as many times as desired as long + * as it is before {@code setContentView()}. If not called, no extended + * features will be available. You can not turn off a feature once it is + * requested. + * + * @param featureId The desired features, defined as constants by Window. + * @return Returns true if the requested feature is supported and now + * enabled. + */ + public abstract boolean requestFeature(int featureId); + + /** + * Set extra options that will influence the UI for this window. + * + * @param uiOptions Flags specifying extra options for this window. + */ + public abstract void setUiOptions(int uiOptions); + + /** + * Set extra options that will influence the UI for this window. Only the + * bits filtered by mask will be modified. + * + * @param uiOptions Flags specifying extra options for this window. + * @param mask Flags specifying which options should be modified. Others + * will remain unchanged. + */ + public abstract void setUiOptions(int uiOptions, int mask); + + /** + * Set the content of the activity inside the action bar. + * + * @param layoutResId Layout resource ID. + */ + public abstract void setContentView(int layoutResId); + + /** + * Set the content of the activity inside the action bar. + * + * @param view The desired content to display. + */ + public void setContentView(View view) { + if (DEBUG) Log.d(TAG, "[setContentView] view: " + view); + + setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); + } + + /** + * Set the content of the activity inside the action bar. + * + * @param view The desired content to display. + * @param params Layout parameters to apply to the view. + */ + public abstract void setContentView(View view, ViewGroup.LayoutParams params); + + /** + * Variation on {@link #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)} + * to add an additional content view to the screen. Added after any + * existing ones on the screen -- existing views are NOT removed. + * + * @param view The desired content to display. + * @param params Layout parameters for the view. + */ + public abstract void addContentView(View view, ViewGroup.LayoutParams params); + + /** + * Change the title associated with this activity. + */ + public abstract void setTitle(CharSequence title); + + /** + * Change the title associated with this activity. + */ + public void setTitle(int resId) { + if (DEBUG) Log.d(TAG, "[setTitle] resId: " + resId); + + setTitle(mActivity.getString(resId)); + } + + /** + * Sets the visibility of the progress bar in the title. + *

+ * In order for the progress bar to be shown, the feature must be requested + * via {@link #requestWindowFeature(int)}. + * + * @param visible Whether to show the progress bars in the title. + */ + public abstract void setProgressBarVisibility(boolean visible); + + /** + * Sets the visibility of the indeterminate progress bar in the title. + *

+ * In order for the progress bar to be shown, the feature must be requested + * via {@link #requestWindowFeature(int)}. + * + * @param visible Whether to show the progress bars in the title. + */ + public abstract void setProgressBarIndeterminateVisibility(boolean visible); + + /** + * Sets whether the horizontal progress bar in the title should be indeterminate (the circular + * is always indeterminate). + *

+ * In order for the progress bar to be shown, the feature must be requested + * via {@link #requestWindowFeature(int)}. + * + * @param indeterminate Whether the horizontal progress bar should be indeterminate. + */ + public abstract void setProgressBarIndeterminate(boolean indeterminate); + + /** + * Sets the progress for the progress bars in the title. + *

+ * In order for the progress bar to be shown, the feature must be requested + * via {@link #requestWindowFeature(int)}. + * + * @param progress The progress for the progress bar. Valid ranges are from + * 0 to 10000 (both inclusive). If 10000 is given, the progress + * bar will be completely filled and will fade out. + */ + public abstract void setProgress(int progress); + + /** + * Sets the secondary progress for the progress bar in the title. This + * progress is drawn between the primary progress (set via + * {@link #setProgress(int)} and the background. It can be ideal for media + * scenarios such as showing the buffering progress while the default + * progress shows the play progress. + *

+ * In order for the progress bar to be shown, the feature must be requested + * via {@link #requestWindowFeature(int)}. + * + * @param secondaryProgress The secondary progress for the progress bar. Valid ranges are from + * 0 to 10000 (both inclusive). + */ + public abstract void setSecondaryProgress(int secondaryProgress); + + /** + * Get a menu inflater instance which supports the newer menu attributes. + * + * @return Menu inflater instance. + */ + public MenuInflater getMenuInflater() { + if (DEBUG) Log.d(TAG, "[getMenuInflater]"); + + // Make sure that action views can get an appropriate theme. + if (mMenuInflater == null) { + if (getActionBar() != null) { + mMenuInflater = new MenuInflater(getThemedContext(), mActivity); + } else { + mMenuInflater = new MenuInflater(mActivity); + } + } + return mMenuInflater; + } + + protected abstract Context getThemedContext(); + + /** + * Start an action mode. + * + * @param callback Callback that will manage lifecycle events for this + * context mode. + * @return The ContextMode that was started, or null if it was canceled. + * @see ActionMode + */ + public abstract ActionMode startActionMode(ActionMode.Callback callback); +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/ActionBar.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/ActionBar.java new file mode 100644 index 00000000..03755be2 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/ActionBar.java @@ -0,0 +1,956 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.app; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.support.v4.app.FragmentTransaction; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewDebug; +import android.view.ViewGroup; +import android.view.ViewGroup.MarginLayoutParams; +import android.widget.SpinnerAdapter; + +/** + * A window feature at the top of the activity that may display the activity title, navigation + * modes, and other interactive items. + *

Beginning with Android 3.0 (API level 11), the action bar appears at the top of an + * activity's window when the activity uses the system's {@link + * android.R.style#Theme_Holo Holo} theme (or one of its descendant themes), which is the default. + * You may otherwise add the action bar by calling {@link + * android.view.Window#requestFeature requestFeature(FEATURE_ACTION_BAR)} or by declaring it in a + * custom theme with the {@link android.R.styleable#Theme_windowActionBar windowActionBar} property. + *

By default, the action bar shows the application icon on + * the left, followed by the activity title. If your activity has an options menu, you can make + * select items accessible directly from the action bar as "action items". You can also + * modify various characteristics of the action bar or remove it completely.

+ *

From your activity, you can retrieve an instance of {@link ActionBar} by calling {@link + * android.app.Activity#getActionBar getActionBar()}.

+ *

In some cases, the action bar may be overlayed by another bar that enables contextual actions, + * using an {@link android.view.ActionMode}. For example, when the user selects one or more items in + * your activity, you can enable an action mode that offers actions specific to the selected + * items, with a UI that temporarily replaces the action bar. Although the UI may occupy the + * same space, the {@link android.view.ActionMode} APIs are distinct and independent from those for + * {@link ActionBar}. + *

+ *

Developer Guides

+ *

For information about how to use the action bar, including how to add action items, navigation + * modes and more, read the Action + * Bar developer guide.

+ *
+ */ +public abstract class ActionBar { + /** + * Standard navigation mode. Consists of either a logo or icon + * and title text with an optional subtitle. Clicking any of these elements + * will dispatch onOptionsItemSelected to the host Activity with + * a MenuItem with item ID android.R.id.home. + */ + public static final int NAVIGATION_MODE_STANDARD = android.app.ActionBar.NAVIGATION_MODE_STANDARD; + + /** + * List navigation mode. Instead of static title text this mode + * presents a list menu for navigation within the activity. + * e.g. this might be presented to the user as a dropdown list. + */ + public static final int NAVIGATION_MODE_LIST = android.app.ActionBar.NAVIGATION_MODE_LIST; + + /** + * Tab navigation mode. Instead of static title text this mode + * presents a series of tabs for navigation within the activity. + */ + public static final int NAVIGATION_MODE_TABS = android.app.ActionBar.NAVIGATION_MODE_TABS; + + /** + * Use logo instead of icon if available. This flag will cause appropriate + * navigation modes to use a wider logo in place of the standard icon. + * + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + */ + public static final int DISPLAY_USE_LOGO = android.app.ActionBar.DISPLAY_USE_LOGO; + + /** + * Show 'home' elements in this action bar, leaving more space for other + * navigation elements. This includes logo and icon. + * + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + */ + public static final int DISPLAY_SHOW_HOME = android.app.ActionBar.DISPLAY_SHOW_HOME; + + /** + * Display the 'home' element such that it appears as an 'up' affordance. + * e.g. show an arrow to the left indicating the action that will be taken. + * + * Set this flag if selecting the 'home' button in the action bar to return + * up by a single level in your UI rather than back to the top level or front page. + * + *

Setting this option will implicitly enable interaction with the home/up + * button. See {@link #setHomeButtonEnabled(boolean)}. + * + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + */ + public static final int DISPLAY_HOME_AS_UP = android.app.ActionBar.DISPLAY_HOME_AS_UP; + + /** + * Show the activity title and subtitle, if present. + * + * @see #setTitle(CharSequence) + * @see #setTitle(int) + * @see #setSubtitle(CharSequence) + * @see #setSubtitle(int) + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + */ + public static final int DISPLAY_SHOW_TITLE = android.app.ActionBar.DISPLAY_SHOW_TITLE; + + /** + * Show the custom view if one has been set. + * @see #setCustomView(View) + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + */ + public static final int DISPLAY_SHOW_CUSTOM = android.app.ActionBar.DISPLAY_SHOW_CUSTOM; + + /** + * Set the action bar into custom navigation mode, supplying a view + * for custom navigation. + * + * Custom navigation views appear between the application icon and + * any action buttons and may use any space available there. Common + * use cases for custom navigation views might include an auto-suggesting + * address bar for a browser or other navigation mechanisms that do not + * translate well to provided navigation modes. + * + * @param view Custom navigation view to place in the ActionBar. + */ + public abstract void setCustomView(View view); + + /** + * Set the action bar into custom navigation mode, supplying a view + * for custom navigation. + * + *

Custom navigation views appear between the application icon and + * any action buttons and may use any space available there. Common + * use cases for custom navigation views might include an auto-suggesting + * address bar for a browser or other navigation mechanisms that do not + * translate well to provided navigation modes.

+ * + *

The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for + * the custom view to be displayed.

+ * + * @param view Custom navigation view to place in the ActionBar. + * @param layoutParams How this custom view should layout in the bar. + * + * @see #setDisplayOptions(int, int) + */ + public abstract void setCustomView(View view, LayoutParams layoutParams); + + /** + * Set the action bar into custom navigation mode, supplying a view + * for custom navigation. + * + *

Custom navigation views appear between the application icon and + * any action buttons and may use any space available there. Common + * use cases for custom navigation views might include an auto-suggesting + * address bar for a browser or other navigation mechanisms that do not + * translate well to provided navigation modes.

+ * + *

The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for + * the custom view to be displayed.

+ * + * @param resId Resource ID of a layout to inflate into the ActionBar. + * + * @see #setDisplayOptions(int, int) + */ + public abstract void setCustomView(int resId); + + /** + * Set the icon to display in the 'home' section of the action bar. + * The action bar will use an icon specified by its style or the + * activity icon by default. + * + * Whether the home section shows an icon or logo is controlled + * by the display option {@link #DISPLAY_USE_LOGO}. + * + * @param resId Resource ID of a drawable to show as an icon. + * + * @see #setDisplayUseLogoEnabled(boolean) + * @see #setDisplayShowHomeEnabled(boolean) + */ + public abstract void setIcon(int resId); + + /** + * Set the icon to display in the 'home' section of the action bar. + * The action bar will use an icon specified by its style or the + * activity icon by default. + * + * Whether the home section shows an icon or logo is controlled + * by the display option {@link #DISPLAY_USE_LOGO}. + * + * @param icon Drawable to show as an icon. + * + * @see #setDisplayUseLogoEnabled(boolean) + * @see #setDisplayShowHomeEnabled(boolean) + */ + public abstract void setIcon(Drawable icon); + + /** + * Set the logo to display in the 'home' section of the action bar. + * The action bar will use a logo specified by its style or the + * activity logo by default. + * + * Whether the home section shows an icon or logo is controlled + * by the display option {@link #DISPLAY_USE_LOGO}. + * + * @param resId Resource ID of a drawable to show as a logo. + * + * @see #setDisplayUseLogoEnabled(boolean) + * @see #setDisplayShowHomeEnabled(boolean) + */ + public abstract void setLogo(int resId); + + /** + * Set the logo to display in the 'home' section of the action bar. + * The action bar will use a logo specified by its style or the + * activity logo by default. + * + * Whether the home section shows an icon or logo is controlled + * by the display option {@link #DISPLAY_USE_LOGO}. + * + * @param logo Drawable to show as a logo. + * + * @see #setDisplayUseLogoEnabled(boolean) + * @see #setDisplayShowHomeEnabled(boolean) + */ + public abstract void setLogo(Drawable logo); + + /** + * Set the adapter and navigation callback for list navigation mode. + * + * The supplied adapter will provide views for the expanded list as well as + * the currently selected item. (These may be displayed differently.) + * + * The supplied OnNavigationListener will alert the application when the user + * changes the current list selection. + * + * @param adapter An adapter that will provide views both to display + * the current navigation selection and populate views + * within the dropdown navigation menu. + * @param callback An OnNavigationListener that will receive events when the user + * selects a navigation item. + */ + public abstract void setListNavigationCallbacks(SpinnerAdapter adapter, + OnNavigationListener callback); + + /** + * Set the selected navigation item in list or tabbed navigation modes. + * + * @param position Position of the item to select. + */ + public abstract void setSelectedNavigationItem(int position); + + /** + * Get the position of the selected navigation item in list or tabbed navigation modes. + * + * @return Position of the selected item. + */ + public abstract int getSelectedNavigationIndex(); + + /** + * Get the number of navigation items present in the current navigation mode. + * + * @return Number of navigation items. + */ + public abstract int getNavigationItemCount(); + + /** + * Set the action bar's title. This will only be displayed if + * {@link #DISPLAY_SHOW_TITLE} is set. + * + * @param title Title to set + * + * @see #setTitle(int) + * @see #setDisplayOptions(int, int) + */ + public abstract void setTitle(CharSequence title); + + /** + * Set the action bar's title. This will only be displayed if + * {@link #DISPLAY_SHOW_TITLE} is set. + * + * @param resId Resource ID of title string to set + * + * @see #setTitle(CharSequence) + * @see #setDisplayOptions(int, int) + */ + public abstract void setTitle(int resId); + + /** + * Set the action bar's subtitle. This will only be displayed if + * {@link #DISPLAY_SHOW_TITLE} is set. Set to null to disable the + * subtitle entirely. + * + * @param subtitle Subtitle to set + * + * @see #setSubtitle(int) + * @see #setDisplayOptions(int, int) + */ + public abstract void setSubtitle(CharSequence subtitle); + + /** + * Set the action bar's subtitle. This will only be displayed if + * {@link #DISPLAY_SHOW_TITLE} is set. + * + * @param resId Resource ID of subtitle string to set + * + * @see #setSubtitle(CharSequence) + * @see #setDisplayOptions(int, int) + */ + public abstract void setSubtitle(int resId); + + /** + * Set display options. This changes all display option bits at once. To change + * a limited subset of display options, see {@link #setDisplayOptions(int, int)}. + * + * @param options A combination of the bits defined by the DISPLAY_ constants + * defined in ActionBar. + */ + public abstract void setDisplayOptions(int options); + + /** + * Set selected display options. Only the options specified by mask will be changed. + * To change all display option bits at once, see {@link #setDisplayOptions(int)}. + * + *

Example: setDisplayOptions(0, DISPLAY_SHOW_HOME) will disable the + * {@link #DISPLAY_SHOW_HOME} option. + * setDisplayOptions(DISPLAY_SHOW_HOME, DISPLAY_SHOW_HOME | DISPLAY_USE_LOGO) + * will enable {@link #DISPLAY_SHOW_HOME} and disable {@link #DISPLAY_USE_LOGO}. + * + * @param options A combination of the bits defined by the DISPLAY_ constants + * defined in ActionBar. + * @param mask A bit mask declaring which display options should be changed. + */ + public abstract void setDisplayOptions(int options, int mask); + + /** + * Set whether to display the activity logo rather than the activity icon. + * A logo is often a wider, more detailed image. + * + *

To set several display options at once, see the setDisplayOptions methods. + * + * @param useLogo true to use the activity logo, false to use the activity icon. + * + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + */ + public abstract void setDisplayUseLogoEnabled(boolean useLogo); + + /** + * Set whether to include the application home affordance in the action bar. + * Home is presented as either an activity icon or logo. + * + *

To set several display options at once, see the setDisplayOptions methods. + * + * @param showHome true to show home, false otherwise. + * + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + */ + public abstract void setDisplayShowHomeEnabled(boolean showHome); + + /** + * Set whether home should be displayed as an "up" affordance. + * Set this to true if selecting "home" returns up by a single level in your UI + * rather than back to the top level or front page. + * + *

To set several display options at once, see the setDisplayOptions methods. + * + * @param showHomeAsUp true to show the user that selecting home will return one + * level up rather than to the top level of the app. + * + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + */ + public abstract void setDisplayHomeAsUpEnabled(boolean showHomeAsUp); + + /** + * Set whether an activity title/subtitle should be displayed. + * + *

To set several display options at once, see the setDisplayOptions methods. + * + * @param showTitle true to display a title/subtitle if present. + * + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + */ + public abstract void setDisplayShowTitleEnabled(boolean showTitle); + + /** + * Set whether a custom view should be displayed, if set. + * + *

To set several display options at once, see the setDisplayOptions methods. + * + * @param showCustom true if the currently set custom view should be displayed, false otherwise. + * + * @see #setDisplayOptions(int) + * @see #setDisplayOptions(int, int) + */ + public abstract void setDisplayShowCustomEnabled(boolean showCustom); + + /** + * Set the ActionBar's background. This will be used for the primary + * action bar. + * + * @param d Background drawable + * @see #setStackedBackgroundDrawable(Drawable) + * @see #setSplitBackgroundDrawable(Drawable) + */ + public abstract void setBackgroundDrawable(Drawable d); + + /** + * Set the ActionBar's stacked background. This will appear + * in the second row/stacked bar on some devices and configurations. + * + * @param d Background drawable for the stacked row + */ + public void setStackedBackgroundDrawable(Drawable d) { } + + /** + * Set the ActionBar's split background. This will appear in + * the split action bar containing menu-provided action buttons + * on some devices and configurations. + *

You can enable split action bar with {@link android.R.attr#uiOptions} + * + * @param d Background drawable for the split bar + */ + public void setSplitBackgroundDrawable(Drawable d) { } + + /** + * @return The current custom view. + */ + public abstract View getCustomView(); + + /** + * Returns the current ActionBar title in standard mode. + * Returns null if {@link #getNavigationMode()} would not return + * {@link #NAVIGATION_MODE_STANDARD}. + * + * @return The current ActionBar title or null. + */ + public abstract CharSequence getTitle(); + + /** + * Returns the current ActionBar subtitle in standard mode. + * Returns null if {@link #getNavigationMode()} would not return + * {@link #NAVIGATION_MODE_STANDARD}. + * + * @return The current ActionBar subtitle or null. + */ + public abstract CharSequence getSubtitle(); + + /** + * Returns the current navigation mode. The result will be one of: + *

    + *
  • {@link #NAVIGATION_MODE_STANDARD}
  • + *
  • {@link #NAVIGATION_MODE_LIST}
  • + *
  • {@link #NAVIGATION_MODE_TABS}
  • + *
+ * + * @return The current navigation mode. + */ + public abstract int getNavigationMode(); + + /** + * Set the current navigation mode. + * + * @param mode The new mode to set. + * @see #NAVIGATION_MODE_STANDARD + * @see #NAVIGATION_MODE_LIST + * @see #NAVIGATION_MODE_TABS + */ + public abstract void setNavigationMode(int mode); + + /** + * @return The current set of display options. + */ + public abstract int getDisplayOptions(); + + /** + * Create and return a new {@link Tab}. + * This tab will not be included in the action bar until it is added. + * + *

Very often tabs will be used to switch between {@link Fragment} + * objects. Here is a typical implementation of such tabs:

+ * + * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabs.java + * complete} + * + * @return A new Tab + * + * @see #addTab(Tab) + */ + public abstract Tab newTab(); + + /** + * Add a tab for use in tabbed navigation mode. The tab will be added at the end of the list. + * If this is the first tab to be added it will become the selected tab. + * + * @param tab Tab to add + */ + public abstract void addTab(Tab tab); + + /** + * Add a tab for use in tabbed navigation mode. The tab will be added at the end of the list. + * + * @param tab Tab to add + * @param setSelected True if the added tab should become the selected tab. + */ + public abstract void addTab(Tab tab, boolean setSelected); + + /** + * Add a tab for use in tabbed navigation mode. The tab will be inserted at + * position. If this is the first tab to be added it will become + * the selected tab. + * + * @param tab The tab to add + * @param position The new position of the tab + */ + public abstract void addTab(Tab tab, int position); + + /** + * Add a tab for use in tabbed navigation mode. The tab will be insterted at + * position. + * + * @param tab The tab to add + * @param position The new position of the tab + * @param setSelected True if the added tab should become the selected tab. + */ + public abstract void addTab(Tab tab, int position, boolean setSelected); + + /** + * Remove a tab from the action bar. If the removed tab was selected it will be deselected + * and another tab will be selected if present. + * + * @param tab The tab to remove + */ + public abstract void removeTab(Tab tab); + + /** + * Remove a tab from the action bar. If the removed tab was selected it will be deselected + * and another tab will be selected if present. + * + * @param position Position of the tab to remove + */ + public abstract void removeTabAt(int position); + + /** + * Remove all tabs from the action bar and deselect the current tab. + */ + public abstract void removeAllTabs(); + + /** + * Select the specified tab. If it is not a child of this action bar it will be added. + * + *

Note: If you want to select by index, use {@link #setSelectedNavigationItem(int)}.

+ * + * @param tab Tab to select + */ + public abstract void selectTab(Tab tab); + + /** + * Returns the currently selected tab if in tabbed navigation mode and there is at least + * one tab present. + * + * @return The currently selected tab or null + */ + public abstract Tab getSelectedTab(); + + /** + * Returns the tab at the specified index. + * + * @param index Index value in the range 0-get + * @return + */ + public abstract Tab getTabAt(int index); + + /** + * Returns the number of tabs currently registered with the action bar. + * @return Tab count + */ + public abstract int getTabCount(); + + /** + * Retrieve the current height of the ActionBar. + * + * @return The ActionBar's height + */ + public abstract int getHeight(); + + /** + * Show the ActionBar if it is not currently showing. + * If the window hosting the ActionBar does not have the feature + * {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application + * content to fit the new space available. + */ + public abstract void show(); + + /** + * Hide the ActionBar if it is currently showing. + * If the window hosting the ActionBar does not have the feature + * {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application + * content to fit the new space available. + */ + public abstract void hide(); + + /** + * @return true if the ActionBar is showing, false otherwise. + */ + public abstract boolean isShowing(); + + /** + * Add a listener that will respond to menu visibility change events. + * + * @param listener The new listener to add + */ + public abstract void addOnMenuVisibilityListener(OnMenuVisibilityListener listener); + + /** + * Remove a menu visibility listener. This listener will no longer receive menu + * visibility change events. + * + * @param listener A listener to remove that was previously added + */ + public abstract void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener); + + /** + * Enable or disable the "home" button in the corner of the action bar. (Note that this + * is the application home/up affordance on the action bar, not the systemwide home + * button.) + * + *

This defaults to true for packages targeting < API 14. For packages targeting + * API 14 or greater, the application should call this method to enable interaction + * with the home/up affordance. + * + *

Setting the {@link #DISPLAY_HOME_AS_UP} display option will automatically enable + * the home button. + * + * @param enabled true to enable the home button, false to disable the home button. + */ + public void setHomeButtonEnabled(boolean enabled) { } + + /** + * Returns a {@link Context} with an appropriate theme for creating views that + * will appear in the action bar. If you are inflating or instantiating custom views + * that will appear in an action bar, you should use the Context returned by this method. + * (This includes adapters used for list navigation mode.) + * This will ensure that views contrast properly against the action bar. + * + * @return A themed Context for creating views + */ + public Context getThemedContext() { return null; } + + /** + * Listener interface for ActionBar navigation events. + */ + public interface OnNavigationListener { + /** + * This method is called whenever a navigation item in your action bar + * is selected. + * + * @param itemPosition Position of the item clicked. + * @param itemId ID of the item clicked. + * @return True if the event was handled, false otherwise. + */ + public boolean onNavigationItemSelected(int itemPosition, long itemId); + } + + /** + * Listener for receiving events when action bar menus are shown or hidden. + */ + public interface OnMenuVisibilityListener { + /** + * Called when an action bar menu is shown or hidden. Applications may want to use + * this to tune auto-hiding behavior for the action bar or pause/resume video playback, + * gameplay, or other activity within the main content area. + * + * @param isVisible True if an action bar menu is now visible, false if no action bar + * menus are visible. + */ + public void onMenuVisibilityChanged(boolean isVisible); + } + + /** + * A tab in the action bar. + * + *

Tabs manage the hiding and showing of {@link Fragment}s. + */ + public static abstract class Tab { + /** + * An invalid position for a tab. + * + * @see #getPosition() + */ + public static final int INVALID_POSITION = -1; + + /** + * Return the current position of this tab in the action bar. + * + * @return Current position, or {@link #INVALID_POSITION} if this tab is not currently in + * the action bar. + */ + public abstract int getPosition(); + + /** + * Return the icon associated with this tab. + * + * @return The tab's icon + */ + public abstract Drawable getIcon(); + + /** + * Return the text of this tab. + * + * @return The tab's text + */ + public abstract CharSequence getText(); + + /** + * Set the icon displayed on this tab. + * + * @param icon The drawable to use as an icon + * @return The current instance for call chaining + */ + public abstract Tab setIcon(Drawable icon); + + /** + * Set the icon displayed on this tab. + * + * @param resId Resource ID referring to the drawable to use as an icon + * @return The current instance for call chaining + */ + public abstract Tab setIcon(int resId); + + /** + * Set the text displayed on this tab. Text may be truncated if there is not + * room to display the entire string. + * + * @param text The text to display + * @return The current instance for call chaining + */ + public abstract Tab setText(CharSequence text); + + /** + * Set the text displayed on this tab. Text may be truncated if there is not + * room to display the entire string. + * + * @param resId A resource ID referring to the text that should be displayed + * @return The current instance for call chaining + */ + public abstract Tab setText(int resId); + + /** + * Set a custom view to be used for this tab. This overrides values set by + * {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}. + * + * @param view Custom view to be used as a tab. + * @return The current instance for call chaining + */ + public abstract Tab setCustomView(View view); + + /** + * Set a custom view to be used for this tab. This overrides values set by + * {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}. + * + * @param layoutResId A layout resource to inflate and use as a custom tab view + * @return The current instance for call chaining + */ + public abstract Tab setCustomView(int layoutResId); + + /** + * Retrieve a previously set custom view for this tab. + * + * @return The custom view set by {@link #setCustomView(View)}. + */ + public abstract View getCustomView(); + + /** + * Give this Tab an arbitrary object to hold for later use. + * + * @param obj Object to store + * @return The current instance for call chaining + */ + public abstract Tab setTag(Object obj); + + /** + * @return This Tab's tag object. + */ + public abstract Object getTag(); + + /** + * Set the {@link TabListener} that will handle switching to and from this tab. + * All tabs must have a TabListener set before being added to the ActionBar. + * + * @param listener Listener to handle tab selection events + * @return The current instance for call chaining + */ + public abstract Tab setTabListener(TabListener listener); + + /** + * Select this tab. Only valid if the tab has been added to the action bar. + */ + public abstract void select(); + + /** + * Set a description of this tab's content for use in accessibility support. + * If no content description is provided the title will be used. + * + * @param resId A resource ID referring to the description text + * @return The current instance for call chaining + * @see #setContentDescription(CharSequence) + * @see #getContentDescription() + */ + public abstract Tab setContentDescription(int resId); + + /** + * Set a description of this tab's content for use in accessibility support. + * If no content description is provided the title will be used. + * + * @param contentDesc Description of this tab's content + * @return The current instance for call chaining + * @see #setContentDescription(int) + * @see #getContentDescription() + */ + public abstract Tab setContentDescription(CharSequence contentDesc); + + /** + * Gets a brief description of this tab's content for use in accessibility support. + * + * @return Description of this tab's content + * @see #setContentDescription(CharSequence) + * @see #setContentDescription(int) + */ + public abstract CharSequence getContentDescription(); + } + + /** + * Callback interface invoked when a tab is focused, unfocused, added, or removed. + */ + public interface TabListener { + /** + * Called when a tab enters the selected state. + * + * @param tab The tab that was selected + * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute + * during a tab switch. The previous tab's unselect and this tab's select will be + * executed in a single transaction. This FragmentTransaction does not support + * being added to the back stack. + */ + public void onTabSelected(Tab tab, FragmentTransaction ft); + + /** + * Called when a tab exits the selected state. + * + * @param tab The tab that was unselected + * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute + * during a tab switch. This tab's unselect and the newly selected tab's select + * will be executed in a single transaction. This FragmentTransaction does not + * support being added to the back stack. + */ + public void onTabUnselected(Tab tab, FragmentTransaction ft); + + /** + * Called when a tab that is already selected is chosen again by the user. + * Some applications may use this action to return to the top level of a category. + * + * @param tab The tab that was reselected. + * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute + * once this method returns. This FragmentTransaction does not support + * being added to the back stack. + */ + public void onTabReselected(Tab tab, FragmentTransaction ft); + } + + /** + * Per-child layout information associated with action bar custom views. + * + * @attr ref android.R.styleable#ActionBar_LayoutParams_layout_gravity + */ + public static class LayoutParams extends MarginLayoutParams { + private static final int[] ATTRS = new int[] { + android.R.attr.layout_gravity + }; + + /** + * Gravity for the view associated with these LayoutParams. + * + * @see android.view.Gravity + */ + @ViewDebug.ExportedProperty(mapping = { + @ViewDebug.IntToString(from = -1, to = "NONE"), + @ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"), + @ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"), + @ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"), + @ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"), + @ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"), + @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"), + @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"), + @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"), + @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"), + @ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"), + @ViewDebug.IntToString(from = Gravity.FILL, to = "FILL") + }) + public int gravity = -1; + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + + TypedArray a = c.obtainStyledAttributes(attrs, ATTRS); + gravity = a.getInt(0, -1); + a.recycle(); + } + + public LayoutParams(int width, int height) { + super(width, height); + this.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT; + } + + public LayoutParams(int width, int height, int gravity) { + super(width, height); + this.gravity = gravity; + } + + public LayoutParams(int gravity) { + this(WRAP_CONTENT, FILL_PARENT, gravity); + } + + public LayoutParams(LayoutParams source) { + super(source); + + this.gravity = source.gravity; + } + + public LayoutParams(ViewGroup.LayoutParams source) { + super(source); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockActivity.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockActivity.java new file mode 100644 index 00000000..7b454364 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockActivity.java @@ -0,0 +1,270 @@ +package com.actionbarsherlock.app; + +import android.app.Activity; +import android.content.res.Configuration; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.View; +import android.view.Window; +import android.view.ViewGroup.LayoutParams; +import com.actionbarsherlock.ActionBarSherlock; +import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener; +import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener; +import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener; +import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener; +import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener; +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +public abstract class SherlockActivity extends Activity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener { + private ActionBarSherlock mSherlock; + + protected final ActionBarSherlock getSherlock() { + if (mSherlock == null) { + mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE); + } + return mSherlock; + } + + + /////////////////////////////////////////////////////////////////////////// + // Action bar and mode + /////////////////////////////////////////////////////////////////////////// + + public ActionBar getSupportActionBar() { + return getSherlock().getActionBar(); + } + + public ActionMode startActionMode(ActionMode.Callback callback) { + return getSherlock().startActionMode(callback); + } + + @Override + public void onActionModeStarted(ActionMode mode) {} + + @Override + public void onActionModeFinished(ActionMode mode) {} + + + /////////////////////////////////////////////////////////////////////////// + // General lifecycle/callback dispatching + /////////////////////////////////////////////////////////////////////////// + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + getSherlock().dispatchConfigurationChanged(newConfig); + } + + @Override + protected void onPostResume() { + super.onPostResume(); + getSherlock().dispatchPostResume(); + } + + @Override + protected void onPause() { + getSherlock().dispatchPause(); + super.onPause(); + } + + @Override + protected void onStop() { + getSherlock().dispatchStop(); + super.onStop(); + } + + @Override + protected void onDestroy() { + getSherlock().dispatchDestroy(); + super.onDestroy(); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + getSherlock().dispatchPostCreate(savedInstanceState); + super.onPostCreate(savedInstanceState); + } + + @Override + protected void onTitleChanged(CharSequence title, int color) { + getSherlock().dispatchTitleChanged(title, color); + super.onTitleChanged(title, color); + } + + @Override + public final boolean onMenuOpened(int featureId, android.view.Menu menu) { + if (getSherlock().dispatchMenuOpened(featureId, menu)) { + return true; + } + return super.onMenuOpened(featureId, menu); + } + + @Override + public void onPanelClosed(int featureId, android.view.Menu menu) { + getSherlock().dispatchPanelClosed(featureId, menu); + super.onPanelClosed(featureId, menu); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (getSherlock().dispatchKeyEvent(event)) { + return true; + } + return super.dispatchKeyEvent(event); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + getSherlock().dispatchSaveInstanceState(outState); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + getSherlock().dispatchRestoreInstanceState(savedInstanceState); + } + + /////////////////////////////////////////////////////////////////////////// + // Native menu handling + /////////////////////////////////////////////////////////////////////////// + + public MenuInflater getSupportMenuInflater() { + return getSherlock().getMenuInflater(); + } + + public void invalidateOptionsMenu() { + getSherlock().dispatchInvalidateOptionsMenu(); + } + + public void supportInvalidateOptionsMenu() { + invalidateOptionsMenu(); + } + + @Override + public final boolean onCreateOptionsMenu(android.view.Menu menu) { + return getSherlock().dispatchCreateOptionsMenu(menu); + } + + @Override + public final boolean onPrepareOptionsMenu(android.view.Menu menu) { + return getSherlock().dispatchPrepareOptionsMenu(menu); + } + + @Override + public final boolean onOptionsItemSelected(android.view.MenuItem item) { + return getSherlock().dispatchOptionsItemSelected(item); + } + + @Override + public void openOptionsMenu() { + if (!getSherlock().dispatchOpenOptionsMenu()) { + super.openOptionsMenu(); + } + } + + @Override + public void closeOptionsMenu() { + if (!getSherlock().dispatchCloseOptionsMenu()) { + super.closeOptionsMenu(); + } + } + + + /////////////////////////////////////////////////////////////////////////// + // Sherlock menu handling + /////////////////////////////////////////////////////////////////////////// + + @Override + public boolean onCreatePanelMenu(int featureId, Menu menu) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onCreateOptionsMenu(menu); + } + return false; + } + + public boolean onCreateOptionsMenu(Menu menu) { + return true; + } + + @Override + public boolean onPreparePanel(int featureId, View view, Menu menu) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onPrepareOptionsMenu(menu); + } + return false; + } + + public boolean onPrepareOptionsMenu(Menu menu) { + return true; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onOptionsItemSelected(item); + } + return false; + } + + public boolean onOptionsItemSelected(MenuItem item) { + return false; + } + + + /////////////////////////////////////////////////////////////////////////// + // Content + /////////////////////////////////////////////////////////////////////////// + + @Override + public void addContentView(View view, LayoutParams params) { + getSherlock().addContentView(view, params); + } + + @Override + public void setContentView(int layoutResId) { + getSherlock().setContentView(layoutResId); + } + + @Override + public void setContentView(View view, LayoutParams params) { + getSherlock().setContentView(view, params); + } + + @Override + public void setContentView(View view) { + getSherlock().setContentView(view); + } + + public void requestWindowFeature(long featureId) { + getSherlock().requestFeature((int)featureId); + } + + + /////////////////////////////////////////////////////////////////////////// + // Progress Indication + /////////////////////////////////////////////////////////////////////////// + + public void setSupportProgress(int progress) { + getSherlock().setProgress(progress); + } + + public void setSupportProgressBarIndeterminate(boolean indeterminate) { + getSherlock().setProgressBarIndeterminate(indeterminate); + } + + public void setSupportProgressBarIndeterminateVisibility(boolean visible) { + getSherlock().setProgressBarIndeterminateVisibility(visible); + } + + public void setSupportProgressBarVisibility(boolean visible) { + getSherlock().setProgressBarVisibility(visible); + } + + public void setSupportSecondaryProgress(int secondaryProgress) { + getSherlock().setSecondaryProgress(secondaryProgress); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockDialogFragment.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockDialogFragment.java new file mode 100644 index 00000000..a7c856bf --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockDialogFragment.java @@ -0,0 +1,68 @@ +package com.actionbarsherlock.app; + +import android.app.Activity; +import android.support.v4.app.DialogFragment; +import com.actionbarsherlock.internal.view.menu.MenuItemWrapper; +import com.actionbarsherlock.internal.view.menu.MenuWrapper; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +import static com.actionbarsherlock.app.SherlockFragmentActivity.OnCreateOptionsMenuListener; +import static com.actionbarsherlock.app.SherlockFragmentActivity.OnOptionsItemSelectedListener; +import static com.actionbarsherlock.app.SherlockFragmentActivity.OnPrepareOptionsMenuListener; + +public class SherlockDialogFragment extends DialogFragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener { + private SherlockFragmentActivity mActivity; + + public SherlockFragmentActivity getSherlockActivity() { + return mActivity; + } + + @Override + public void onAttach(Activity activity) { + if (!(activity instanceof SherlockFragmentActivity)) { + throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity."); + } + mActivity = (SherlockFragmentActivity)activity; + + super.onAttach(activity); + } + + @Override + public void onDetach() { + mActivity = null; + super.onDetach(); + } + + @Override + public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) { + onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater()); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + //Nothing to see here. + } + + @Override + public final void onPrepareOptionsMenu(android.view.Menu menu) { + onPrepareOptionsMenu(new MenuWrapper(menu)); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + //Nothing to see here. + } + + @Override + public final boolean onOptionsItemSelected(android.view.MenuItem item) { + return onOptionsItemSelected(new MenuItemWrapper(item)); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + //Nothing to see here. + return false; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockExpandableListActivity.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockExpandableListActivity.java new file mode 100644 index 00000000..078f9b0c --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockExpandableListActivity.java @@ -0,0 +1,259 @@ +package com.actionbarsherlock.app; + +import android.app.ExpandableListActivity; +import android.content.res.Configuration; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.view.Window; +import com.actionbarsherlock.ActionBarSherlock; +import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener; +import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener; +import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener; +import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener; +import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener; +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +public abstract class SherlockExpandableListActivity extends ExpandableListActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener { + private ActionBarSherlock mSherlock; + + protected final ActionBarSherlock getSherlock() { + if (mSherlock == null) { + mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE); + } + return mSherlock; + } + + + /////////////////////////////////////////////////////////////////////////// + // Action bar and mode + /////////////////////////////////////////////////////////////////////////// + + public ActionBar getSupportActionBar() { + return getSherlock().getActionBar(); + } + + public ActionMode startActionMode(ActionMode.Callback callback) { + return getSherlock().startActionMode(callback); + } + + @Override + public void onActionModeStarted(ActionMode mode) {} + + @Override + public void onActionModeFinished(ActionMode mode) {} + + + /////////////////////////////////////////////////////////////////////////// + // General lifecycle/callback dispatching + /////////////////////////////////////////////////////////////////////////// + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + getSherlock().dispatchConfigurationChanged(newConfig); + } + + @Override + protected void onPostResume() { + super.onPostResume(); + getSherlock().dispatchPostResume(); + } + + @Override + protected void onPause() { + getSherlock().dispatchPause(); + super.onPause(); + } + + @Override + protected void onStop() { + getSherlock().dispatchStop(); + super.onStop(); + } + + @Override + protected void onDestroy() { + getSherlock().dispatchDestroy(); + super.onDestroy(); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + getSherlock().dispatchPostCreate(savedInstanceState); + super.onPostCreate(savedInstanceState); + } + + @Override + protected void onTitleChanged(CharSequence title, int color) { + getSherlock().dispatchTitleChanged(title, color); + super.onTitleChanged(title, color); + } + + @Override + public final boolean onMenuOpened(int featureId, android.view.Menu menu) { + if (getSherlock().dispatchMenuOpened(featureId, menu)) { + return true; + } + return super.onMenuOpened(featureId, menu); + } + + @Override + public void onPanelClosed(int featureId, android.view.Menu menu) { + getSherlock().dispatchPanelClosed(featureId, menu); + super.onPanelClosed(featureId, menu); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (getSherlock().dispatchKeyEvent(event)) { + return true; + } + return super.dispatchKeyEvent(event); + } + + + /////////////////////////////////////////////////////////////////////////// + // Native menu handling + /////////////////////////////////////////////////////////////////////////// + + public MenuInflater getSupportMenuInflater() { + return getSherlock().getMenuInflater(); + } + + public void invalidateOptionsMenu() { + getSherlock().dispatchInvalidateOptionsMenu(); + } + + public void supportInvalidateOptionsMenu() { + invalidateOptionsMenu(); + } + + @Override + public final boolean onCreateOptionsMenu(android.view.Menu menu) { + return getSherlock().dispatchCreateOptionsMenu(menu); + } + + @Override + public final boolean onPrepareOptionsMenu(android.view.Menu menu) { + return getSherlock().dispatchPrepareOptionsMenu(menu); + } + + @Override + public final boolean onOptionsItemSelected(android.view.MenuItem item) { + return getSherlock().dispatchOptionsItemSelected(item); + } + + @Override + public void openOptionsMenu() { + if (!getSherlock().dispatchOpenOptionsMenu()) { + super.openOptionsMenu(); + } + } + + @Override + public void closeOptionsMenu() { + if (!getSherlock().dispatchCloseOptionsMenu()) { + super.closeOptionsMenu(); + } + } + + + /////////////////////////////////////////////////////////////////////////// + // Sherlock menu handling + /////////////////////////////////////////////////////////////////////////// + + @Override + public boolean onCreatePanelMenu(int featureId, Menu menu) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onCreateOptionsMenu(menu); + } + return false; + } + + public boolean onCreateOptionsMenu(Menu menu) { + return true; + } + + @Override + public boolean onPreparePanel(int featureId, View view, Menu menu) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onPrepareOptionsMenu(menu); + } + return false; + } + + public boolean onPrepareOptionsMenu(Menu menu) { + return true; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onOptionsItemSelected(item); + } + return false; + } + + public boolean onOptionsItemSelected(MenuItem item) { + return false; + } + + + /////////////////////////////////////////////////////////////////////////// + // Content + /////////////////////////////////////////////////////////////////////////// + + @Override + public void addContentView(View view, LayoutParams params) { + getSherlock().addContentView(view, params); + } + + @Override + public void setContentView(int layoutResId) { + getSherlock().setContentView(layoutResId); + } + + @Override + public void setContentView(View view, LayoutParams params) { + getSherlock().setContentView(view, params); + } + + @Override + public void setContentView(View view) { + getSherlock().setContentView(view); + } + + public void requestWindowFeature(long featureId) { + getSherlock().requestFeature((int)featureId); + } + + + /////////////////////////////////////////////////////////////////////////// + // Progress Indication + /////////////////////////////////////////////////////////////////////////// + + public void setSupportProgress(int progress) { + getSherlock().setProgress(progress); + } + + public void setSupportProgressBarIndeterminate(boolean indeterminate) { + getSherlock().setProgressBarIndeterminate(indeterminate); + } + + public void setSupportProgressBarIndeterminateVisibility(boolean visible) { + getSherlock().setProgressBarIndeterminateVisibility(visible); + } + + public void setSupportProgressBarVisibility(boolean visible) { + getSherlock().setProgressBarVisibility(visible); + } + + public void setSupportSecondaryProgress(int secondaryProgress) { + getSherlock().setSecondaryProgress(secondaryProgress); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockFragment.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockFragment.java new file mode 100644 index 00000000..0f24e9c8 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockFragment.java @@ -0,0 +1,68 @@ +package com.actionbarsherlock.app; + +import android.app.Activity; +import android.support.v4.app.Fragment; +import com.actionbarsherlock.internal.view.menu.MenuItemWrapper; +import com.actionbarsherlock.internal.view.menu.MenuWrapper; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +import static com.actionbarsherlock.app.SherlockFragmentActivity.OnCreateOptionsMenuListener; +import static com.actionbarsherlock.app.SherlockFragmentActivity.OnOptionsItemSelectedListener; +import static com.actionbarsherlock.app.SherlockFragmentActivity.OnPrepareOptionsMenuListener; + +public class SherlockFragment extends Fragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener { + private SherlockFragmentActivity mActivity; + + public SherlockFragmentActivity getSherlockActivity() { + return mActivity; + } + + @Override + public void onAttach(Activity activity) { + if (!(activity instanceof SherlockFragmentActivity)) { + throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity."); + } + mActivity = (SherlockFragmentActivity)activity; + + super.onAttach(activity); + } + + @Override + public void onDetach() { + mActivity = null; + super.onDetach(); + } + + @Override + public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) { + onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater()); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + //Nothing to see here. + } + + @Override + public final void onPrepareOptionsMenu(android.view.Menu menu) { + onPrepareOptionsMenu(new MenuWrapper(menu)); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + //Nothing to see here. + } + + @Override + public final boolean onOptionsItemSelected(android.view.MenuItem item) { + return onOptionsItemSelected(new MenuItemWrapper(item)); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + //Nothing to see here. + return false; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockFragmentActivity.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockFragmentActivity.java new file mode 100644 index 00000000..3d092f03 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockFragmentActivity.java @@ -0,0 +1,303 @@ +package com.actionbarsherlock.app; + +import android.content.res.Configuration; +import android.os.Bundle; +import android.support.v4.app.Watson; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.view.Window; +import com.actionbarsherlock.ActionBarSherlock; +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +import static com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener; +import static com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener; + +/** @see {@link android.support.v4.app.Watson} */ +public class SherlockFragmentActivity extends Watson implements OnActionModeStartedListener, OnActionModeFinishedListener { + private static final boolean DEBUG = false; + private static final String TAG = "SherlockFragmentActivity"; + + private ActionBarSherlock mSherlock; + private boolean mIgnoreNativeCreate = false; + private boolean mIgnoreNativePrepare = false; + private boolean mIgnoreNativeSelected = false; + + protected final ActionBarSherlock getSherlock() { + if (mSherlock == null) { + mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE); + } + return mSherlock; + } + + + /////////////////////////////////////////////////////////////////////////// + // Action bar and mode + /////////////////////////////////////////////////////////////////////////// + + public ActionBar getSupportActionBar() { + return getSherlock().getActionBar(); + } + + public ActionMode startActionMode(ActionMode.Callback callback) { + return getSherlock().startActionMode(callback); + } + + @Override + public void onActionModeStarted(ActionMode mode) {} + + @Override + public void onActionModeFinished(ActionMode mode) {} + + + /////////////////////////////////////////////////////////////////////////// + // General lifecycle/callback dispatching + /////////////////////////////////////////////////////////////////////////// + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + getSherlock().dispatchConfigurationChanged(newConfig); + } + + @Override + protected void onPostResume() { + super.onPostResume(); + getSherlock().dispatchPostResume(); + } + + @Override + protected void onPause() { + getSherlock().dispatchPause(); + super.onPause(); + } + + @Override + protected void onStop() { + getSherlock().dispatchStop(); + super.onStop(); + } + + @Override + protected void onDestroy() { + getSherlock().dispatchDestroy(); + super.onDestroy(); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + getSherlock().dispatchPostCreate(savedInstanceState); + super.onPostCreate(savedInstanceState); + } + + @Override + protected void onTitleChanged(CharSequence title, int color) { + getSherlock().dispatchTitleChanged(title, color); + super.onTitleChanged(title, color); + } + + @Override + public final boolean onMenuOpened(int featureId, android.view.Menu menu) { + if (getSherlock().dispatchMenuOpened(featureId, menu)) { + return true; + } + return super.onMenuOpened(featureId, menu); + } + + @Override + public void onPanelClosed(int featureId, android.view.Menu menu) { + getSherlock().dispatchPanelClosed(featureId, menu); + super.onPanelClosed(featureId, menu); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (getSherlock().dispatchKeyEvent(event)) { + return true; + } + return super.dispatchKeyEvent(event); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + getSherlock().dispatchSaveInstanceState(outState); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + getSherlock().dispatchRestoreInstanceState(savedInstanceState); + } + + /////////////////////////////////////////////////////////////////////////// + // Native menu handling + /////////////////////////////////////////////////////////////////////////// + + public MenuInflater getSupportMenuInflater() { + if (DEBUG) Log.d(TAG, "[getSupportMenuInflater]"); + + return getSherlock().getMenuInflater(); + } + + public void invalidateOptionsMenu() { + if (DEBUG) Log.d(TAG, "[invalidateOptionsMenu]"); + + getSherlock().dispatchInvalidateOptionsMenu(); + } + + public void supportInvalidateOptionsMenu() { + if (DEBUG) Log.d(TAG, "[supportInvalidateOptionsMenu]"); + + invalidateOptionsMenu(); + } + + @Override + public final boolean onCreatePanelMenu(int featureId, android.view.Menu menu) { + if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] featureId: " + featureId + ", menu: " + menu); + + if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativeCreate) { + mIgnoreNativeCreate = true; + boolean result = getSherlock().dispatchCreateOptionsMenu(menu); + mIgnoreNativeCreate = false; + + if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] returning " + result); + return result; + } + return super.onCreatePanelMenu(featureId, menu); + } + + @Override + public final boolean onCreateOptionsMenu(android.view.Menu menu) { + return true; + } + + @Override + public final boolean onPreparePanel(int featureId, View view, android.view.Menu menu) { + if (DEBUG) Log.d(TAG, "[onPreparePanel] featureId: " + featureId + ", view: " + view + ", menu: " + menu); + + if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativePrepare) { + mIgnoreNativePrepare = true; + boolean result = getSherlock().dispatchPrepareOptionsMenu(menu); + mIgnoreNativePrepare = false; + + if (DEBUG) Log.d(TAG, "[onPreparePanel] returning " + result); + return result; + } + return super.onPreparePanel(featureId, view, menu); + } + + @Override + public final boolean onPrepareOptionsMenu(android.view.Menu menu) { + return true; + } + + @Override + public final boolean onMenuItemSelected(int featureId, android.view.MenuItem item) { + if (DEBUG) Log.d(TAG, "[onMenuItemSelected] featureId: " + featureId + ", item: " + item); + + if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativeSelected) { + mIgnoreNativeSelected = true; + boolean result = getSherlock().dispatchOptionsItemSelected(item); + mIgnoreNativeSelected = false; + + if (DEBUG) Log.d(TAG, "[onMenuItemSelected] returning " + result); + return result; + } + return super.onMenuItemSelected(featureId, item); + } + + @Override + public final boolean onOptionsItemSelected(android.view.MenuItem item) { + return false; + } + + @Override + public void openOptionsMenu() { + if (!getSherlock().dispatchOpenOptionsMenu()) { + super.openOptionsMenu(); + } + } + + @Override + public void closeOptionsMenu() { + if (!getSherlock().dispatchCloseOptionsMenu()) { + super.closeOptionsMenu(); + } + } + + + /////////////////////////////////////////////////////////////////////////// + // Sherlock menu handling + /////////////////////////////////////////////////////////////////////////// + + public boolean onCreateOptionsMenu(Menu menu) { + return true; + } + + public boolean onPrepareOptionsMenu(Menu menu) { + return true; + } + + public boolean onOptionsItemSelected(MenuItem item) { + return false; + } + + + /////////////////////////////////////////////////////////////////////////// + // Content + /////////////////////////////////////////////////////////////////////////// + + @Override + public void addContentView(View view, LayoutParams params) { + getSherlock().addContentView(view, params); + } + + @Override + public void setContentView(int layoutResId) { + getSherlock().setContentView(layoutResId); + } + + @Override + public void setContentView(View view, LayoutParams params) { + getSherlock().setContentView(view, params); + } + + @Override + public void setContentView(View view) { + getSherlock().setContentView(view); + } + + public void requestWindowFeature(long featureId) { + getSherlock().requestFeature((int)featureId); + } + + + /////////////////////////////////////////////////////////////////////////// + // Progress Indication + /////////////////////////////////////////////////////////////////////////// + + public void setSupportProgress(int progress) { + getSherlock().setProgress(progress); + } + + public void setSupportProgressBarIndeterminate(boolean indeterminate) { + getSherlock().setProgressBarIndeterminate(indeterminate); + } + + public void setSupportProgressBarIndeterminateVisibility(boolean visible) { + getSherlock().setProgressBarIndeterminateVisibility(visible); + } + + public void setSupportProgressBarVisibility(boolean visible) { + getSherlock().setProgressBarVisibility(visible); + } + + public void setSupportSecondaryProgress(int secondaryProgress) { + getSherlock().setSecondaryProgress(secondaryProgress); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockListActivity.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockListActivity.java new file mode 100644 index 00000000..aba6d85e --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockListActivity.java @@ -0,0 +1,270 @@ +package com.actionbarsherlock.app; + +import android.app.ListActivity; +import android.content.res.Configuration; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.View; +import android.view.Window; +import android.view.ViewGroup.LayoutParams; +import com.actionbarsherlock.ActionBarSherlock; +import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener; +import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener; +import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener; +import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener; +import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener; +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +public abstract class SherlockListActivity extends ListActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener { + private ActionBarSherlock mSherlock; + + protected final ActionBarSherlock getSherlock() { + if (mSherlock == null) { + mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE); + } + return mSherlock; + } + + + /////////////////////////////////////////////////////////////////////////// + // Action bar and mode + /////////////////////////////////////////////////////////////////////////// + + public ActionBar getSupportActionBar() { + return getSherlock().getActionBar(); + } + + public ActionMode startActionMode(ActionMode.Callback callback) { + return getSherlock().startActionMode(callback); + } + + @Override + public void onActionModeStarted(ActionMode mode) {} + + @Override + public void onActionModeFinished(ActionMode mode) {} + + + /////////////////////////////////////////////////////////////////////////// + // General lifecycle/callback dispatching + /////////////////////////////////////////////////////////////////////////// + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + getSherlock().dispatchConfigurationChanged(newConfig); + } + + @Override + protected void onPostResume() { + super.onPostResume(); + getSherlock().dispatchPostResume(); + } + + @Override + protected void onPause() { + getSherlock().dispatchPause(); + super.onPause(); + } + + @Override + protected void onStop() { + getSherlock().dispatchStop(); + super.onStop(); + } + + @Override + protected void onDestroy() { + getSherlock().dispatchDestroy(); + super.onDestroy(); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + getSherlock().dispatchPostCreate(savedInstanceState); + super.onPostCreate(savedInstanceState); + } + + @Override + protected void onTitleChanged(CharSequence title, int color) { + getSherlock().dispatchTitleChanged(title, color); + super.onTitleChanged(title, color); + } + + @Override + public final boolean onMenuOpened(int featureId, android.view.Menu menu) { + if (getSherlock().dispatchMenuOpened(featureId, menu)) { + return true; + } + return super.onMenuOpened(featureId, menu); + } + + @Override + public void onPanelClosed(int featureId, android.view.Menu menu) { + getSherlock().dispatchPanelClosed(featureId, menu); + super.onPanelClosed(featureId, menu); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (getSherlock().dispatchKeyEvent(event)) { + return true; + } + return super.dispatchKeyEvent(event); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + getSherlock().dispatchSaveInstanceState(outState); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + getSherlock().dispatchRestoreInstanceState(savedInstanceState); + } + + /////////////////////////////////////////////////////////////////////////// + // Native menu handling + /////////////////////////////////////////////////////////////////////////// + + public MenuInflater getSupportMenuInflater() { + return getSherlock().getMenuInflater(); + } + + public void invalidateOptionsMenu() { + getSherlock().dispatchInvalidateOptionsMenu(); + } + + public void supportInvalidateOptionsMenu() { + invalidateOptionsMenu(); + } + + @Override + public final boolean onCreateOptionsMenu(android.view.Menu menu) { + return getSherlock().dispatchCreateOptionsMenu(menu); + } + + @Override + public final boolean onPrepareOptionsMenu(android.view.Menu menu) { + return getSherlock().dispatchPrepareOptionsMenu(menu); + } + + @Override + public final boolean onOptionsItemSelected(android.view.MenuItem item) { + return getSherlock().dispatchOptionsItemSelected(item); + } + + @Override + public void openOptionsMenu() { + if (!getSherlock().dispatchOpenOptionsMenu()) { + super.openOptionsMenu(); + } + } + + @Override + public void closeOptionsMenu() { + if (!getSherlock().dispatchCloseOptionsMenu()) { + super.closeOptionsMenu(); + } + } + + + /////////////////////////////////////////////////////////////////////////// + // Sherlock menu handling + /////////////////////////////////////////////////////////////////////////// + + @Override + public boolean onCreatePanelMenu(int featureId, Menu menu) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onCreateOptionsMenu(menu); + } + return false; + } + + public boolean onCreateOptionsMenu(Menu menu) { + return true; + } + + @Override + public boolean onPreparePanel(int featureId, View view, Menu menu) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onPrepareOptionsMenu(menu); + } + return false; + } + + public boolean onPrepareOptionsMenu(Menu menu) { + return true; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onOptionsItemSelected(item); + } + return false; + } + + public boolean onOptionsItemSelected(MenuItem item) { + return false; + } + + + /////////////////////////////////////////////////////////////////////////// + // Content + /////////////////////////////////////////////////////////////////////////// + + @Override + public void addContentView(View view, LayoutParams params) { + getSherlock().addContentView(view, params); + } + + @Override + public void setContentView(int layoutResId) { + getSherlock().setContentView(layoutResId); + } + + @Override + public void setContentView(View view, LayoutParams params) { + getSherlock().setContentView(view, params); + } + + @Override + public void setContentView(View view) { + getSherlock().setContentView(view); + } + + public void requestWindowFeature(long featureId) { + getSherlock().requestFeature((int)featureId); + } + + + /////////////////////////////////////////////////////////////////////////// + // Progress Indication + /////////////////////////////////////////////////////////////////////////// + + public void setSupportProgress(int progress) { + getSherlock().setProgress(progress); + } + + public void setSupportProgressBarIndeterminate(boolean indeterminate) { + getSherlock().setProgressBarIndeterminate(indeterminate); + } + + public void setSupportProgressBarIndeterminateVisibility(boolean visible) { + getSherlock().setProgressBarIndeterminateVisibility(visible); + } + + public void setSupportProgressBarVisibility(boolean visible) { + getSherlock().setProgressBarVisibility(visible); + } + + public void setSupportSecondaryProgress(int secondaryProgress) { + getSherlock().setSecondaryProgress(secondaryProgress); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockListFragment.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockListFragment.java new file mode 100644 index 00000000..13ca3c49 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockListFragment.java @@ -0,0 +1,68 @@ +package com.actionbarsherlock.app; + +import android.app.Activity; +import android.support.v4.app.ListFragment; +import com.actionbarsherlock.internal.view.menu.MenuItemWrapper; +import com.actionbarsherlock.internal.view.menu.MenuWrapper; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +import static com.actionbarsherlock.app.SherlockFragmentActivity.OnCreateOptionsMenuListener; +import static com.actionbarsherlock.app.SherlockFragmentActivity.OnOptionsItemSelectedListener; +import static com.actionbarsherlock.app.SherlockFragmentActivity.OnPrepareOptionsMenuListener; + +public class SherlockListFragment extends ListFragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener { + private SherlockFragmentActivity mActivity; + + public SherlockFragmentActivity getSherlockActivity() { + return mActivity; + } + + @Override + public void onAttach(Activity activity) { + if (!(activity instanceof SherlockFragmentActivity)) { + throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity."); + } + mActivity = (SherlockFragmentActivity)activity; + + super.onAttach(activity); + } + + @Override + public void onDetach() { + mActivity = null; + super.onDetach(); + } + + @Override + public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) { + onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater()); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + //Nothing to see here. + } + + @Override + public final void onPrepareOptionsMenu(android.view.Menu menu) { + onPrepareOptionsMenu(new MenuWrapper(menu)); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + //Nothing to see here. + } + + @Override + public final boolean onOptionsItemSelected(android.view.MenuItem item) { + return onOptionsItemSelected(new MenuItemWrapper(item)); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + //Nothing to see here. + return false; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockPreferenceActivity.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockPreferenceActivity.java new file mode 100644 index 00000000..bee72cb2 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/app/SherlockPreferenceActivity.java @@ -0,0 +1,270 @@ +package com.actionbarsherlock.app; + +import android.content.res.Configuration; +import android.os.Bundle; +import android.preference.PreferenceActivity; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.view.Window; +import com.actionbarsherlock.ActionBarSherlock; +import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener; +import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener; +import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener; +import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener; +import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener; +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +public abstract class SherlockPreferenceActivity extends PreferenceActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener { + private ActionBarSherlock mSherlock; + + protected final ActionBarSherlock getSherlock() { + if (mSherlock == null) { + mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE); + } + return mSherlock; + } + + + /////////////////////////////////////////////////////////////////////////// + // Action bar and mode + /////////////////////////////////////////////////////////////////////////// + + public ActionBar getSupportActionBar() { + return getSherlock().getActionBar(); + } + + public ActionMode startActionMode(ActionMode.Callback callback) { + return getSherlock().startActionMode(callback); + } + + @Override + public void onActionModeStarted(ActionMode mode) {} + + @Override + public void onActionModeFinished(ActionMode mode) {} + + + /////////////////////////////////////////////////////////////////////////// + // General lifecycle/callback dispatching + /////////////////////////////////////////////////////////////////////////// + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + getSherlock().dispatchConfigurationChanged(newConfig); + } + + @Override + protected void onPostResume() { + super.onPostResume(); + getSherlock().dispatchPostResume(); + } + + @Override + protected void onPause() { + getSherlock().dispatchPause(); + super.onPause(); + } + + @Override + protected void onStop() { + getSherlock().dispatchStop(); + super.onStop(); + } + + @Override + protected void onDestroy() { + getSherlock().dispatchDestroy(); + super.onDestroy(); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + getSherlock().dispatchPostCreate(savedInstanceState); + super.onPostCreate(savedInstanceState); + } + + @Override + protected void onTitleChanged(CharSequence title, int color) { + getSherlock().dispatchTitleChanged(title, color); + super.onTitleChanged(title, color); + } + + @Override + public final boolean onMenuOpened(int featureId, android.view.Menu menu) { + if (getSherlock().dispatchMenuOpened(featureId, menu)) { + return true; + } + return super.onMenuOpened(featureId, menu); + } + + @Override + public void onPanelClosed(int featureId, android.view.Menu menu) { + getSherlock().dispatchPanelClosed(featureId, menu); + super.onPanelClosed(featureId, menu); + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (getSherlock().dispatchKeyEvent(event)) { + return true; + } + return super.dispatchKeyEvent(event); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + getSherlock().dispatchSaveInstanceState(outState); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + getSherlock().dispatchRestoreInstanceState(savedInstanceState); + } + + /////////////////////////////////////////////////////////////////////////// + // Native menu handling + /////////////////////////////////////////////////////////////////////////// + + public MenuInflater getSupportMenuInflater() { + return getSherlock().getMenuInflater(); + } + + public void invalidateOptionsMenu() { + getSherlock().dispatchInvalidateOptionsMenu(); + } + + public void supportInvalidateOptionsMenu() { + invalidateOptionsMenu(); + } + + @Override + public final boolean onCreateOptionsMenu(android.view.Menu menu) { + return getSherlock().dispatchCreateOptionsMenu(menu); + } + + @Override + public final boolean onPrepareOptionsMenu(android.view.Menu menu) { + return getSherlock().dispatchPrepareOptionsMenu(menu); + } + + @Override + public final boolean onOptionsItemSelected(android.view.MenuItem item) { + return getSherlock().dispatchOptionsItemSelected(item); + } + + @Override + public void openOptionsMenu() { + if (!getSherlock().dispatchOpenOptionsMenu()) { + super.openOptionsMenu(); + } + } + + @Override + public void closeOptionsMenu() { + if (!getSherlock().dispatchCloseOptionsMenu()) { + super.closeOptionsMenu(); + } + } + + + /////////////////////////////////////////////////////////////////////////// + // Sherlock menu handling + /////////////////////////////////////////////////////////////////////////// + + @Override + public boolean onCreatePanelMenu(int featureId, Menu menu) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onCreateOptionsMenu(menu); + } + return false; + } + + public boolean onCreateOptionsMenu(Menu menu) { + return true; + } + + @Override + public boolean onPreparePanel(int featureId, View view, Menu menu) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onPrepareOptionsMenu(menu); + } + return false; + } + + public boolean onPrepareOptionsMenu(Menu menu) { + return true; + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + if (featureId == Window.FEATURE_OPTIONS_PANEL) { + return onOptionsItemSelected(item); + } + return false; + } + + public boolean onOptionsItemSelected(MenuItem item) { + return false; + } + + + /////////////////////////////////////////////////////////////////////////// + // Content + /////////////////////////////////////////////////////////////////////////// + + @Override + public void addContentView(View view, LayoutParams params) { + getSherlock().addContentView(view, params); + } + + @Override + public void setContentView(int layoutResId) { + getSherlock().setContentView(layoutResId); + } + + @Override + public void setContentView(View view, LayoutParams params) { + getSherlock().setContentView(view, params); + } + + @Override + public void setContentView(View view) { + getSherlock().setContentView(view); + } + + public void requestWindowFeature(long featureId) { + getSherlock().requestFeature((int)featureId); + } + + + /////////////////////////////////////////////////////////////////////////// + // Progress Indication + /////////////////////////////////////////////////////////////////////////// + + public void setSupportProgress(int progress) { + getSherlock().setProgress(progress); + } + + public void setSupportProgressBarIndeterminate(boolean indeterminate) { + getSherlock().setProgressBarIndeterminate(indeterminate); + } + + public void setSupportProgressBarIndeterminateVisibility(boolean visible) { + getSherlock().setProgressBarIndeterminateVisibility(visible); + } + + public void setSupportProgressBarVisibility(boolean visible) { + getSherlock().setProgressBarVisibility(visible); + } + + public void setSupportSecondaryProgress(int secondaryProgress) { + getSherlock().setSecondaryProgress(secondaryProgress); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java new file mode 100644 index 00000000..5e69275c --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java @@ -0,0 +1,1203 @@ +package com.actionbarsherlock.internal; + +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import org.xmlpull.v1.XmlPullParser; +import android.app.Activity; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.res.AssetManager; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; +import android.os.Bundle; +import android.util.AndroidRuntimeException; +import android.util.Log; +import android.util.TypedValue; +import android.view.ContextThemeWrapper; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewStub; +import android.view.Window; +import android.view.accessibility.AccessibilityEvent; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.FrameLayout; +import android.widget.TextView; +import com.actionbarsherlock.ActionBarSherlock; +import com.actionbarsherlock.R; +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.internal.app.ActionBarImpl; +import com.actionbarsherlock.internal.view.StandaloneActionMode; +import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter; +import com.actionbarsherlock.internal.view.menu.MenuBuilder; +import com.actionbarsherlock.internal.view.menu.MenuItemImpl; +import com.actionbarsherlock.internal.view.menu.MenuPresenter; +import com.actionbarsherlock.internal.widget.ActionBarContainer; +import com.actionbarsherlock.internal.widget.ActionBarContextView; +import com.actionbarsherlock.internal.widget.ActionBarView; +import com.actionbarsherlock.internal.widget.IcsProgressBar; +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; + +@ActionBarSherlock.Implementation(api = 7) +public class ActionBarSherlockCompat extends ActionBarSherlock implements MenuBuilder.Callback, com.actionbarsherlock.view.Window.Callback, MenuPresenter.Callback, android.view.MenuItem.OnMenuItemClickListener { + /** Window features which are enabled by default. */ + protected static final int DEFAULT_FEATURES = 0; + + static private final String PANELS_TAG = "sherlock:Panels"; + + public ActionBarSherlockCompat(Activity activity, int flags) { + super(activity, flags); + } + + + /////////////////////////////////////////////////////////////////////////// + // Properties + /////////////////////////////////////////////////////////////////////////// + + /** Whether or not the device has a dedicated menu key button. */ + private boolean mReserveOverflow; + /** Lazy-load indicator for {@link #mReserveOverflow}. */ + private boolean mReserveOverflowSet = false; + + /** Current menu instance for managing action items. */ + private MenuBuilder mMenu; + /** Map between native options items and sherlock items. */ + protected HashMap mNativeItemMap; + + /** Parent view of the window decoration (action bar, mode, etc.). */ + private ViewGroup mDecor; + /** Parent view of the activity content. */ + private ViewGroup mContentParent; + + /** Whether or not the title is stable and can be displayed. */ + private boolean mIsTitleReady = false; + /** Whether or not the parent activity has been destroyed. */ + private boolean mIsDestroyed = false; + + /* Emulate PanelFeatureState */ + private boolean mClosingActionMenu; + private boolean mMenuIsPrepared; + private boolean mMenuRefreshContent; + private Bundle mMenuFrozenActionViewState; + + /** Implementation which backs the action bar interface API. */ + private ActionBarImpl aActionBar; + /** Main action bar view which displays the core content. */ + private ActionBarView wActionBar; + /** Relevant window and action bar features flags. */ + private int mFeatures = DEFAULT_FEATURES; + /** Relevant user interface option flags. */ + private int mUiOptions = 0; + + /** Decor indeterminate progress indicator. */ + private IcsProgressBar mCircularProgressBar; + /** Decor progress indicator. */ + private IcsProgressBar mHorizontalProgressBar; + + /** Current displayed context action bar, if any. */ + private ActionMode mActionMode; + /** Parent view in which the context action bar is displayed. */ + private ActionBarContextView mActionModeView; + + /** Title view used with dialogs. */ + private TextView mTitleView; + /** Current activity title. */ + private CharSequence mTitle = null; + /** Whether or not this "activity" is floating (i.e., a dialog) */ + private boolean mIsFloating; + + + + /////////////////////////////////////////////////////////////////////////// + // Instance methods + /////////////////////////////////////////////////////////////////////////// + + @Override + public ActionBar getActionBar() { + if (DEBUG) Log.d(TAG, "[getActionBar]"); + + initActionBar(); + return aActionBar; + } + + private void initActionBar() { + if (DEBUG) Log.d(TAG, "[initActionBar]"); + + // Initializing the window decor can change window feature flags. + // Make sure that we have the correct set before performing the test below. + if (mDecor == null) { + installDecor(); + } + + if ((aActionBar != null) || !hasFeature(Window.FEATURE_ACTION_BAR) || hasFeature(Window.FEATURE_NO_TITLE) || mActivity.isChild()) { + return; + } + + aActionBar = new ActionBarImpl(mActivity, mFeatures); + + if (!mIsDelegate) { + //We may never get another chance to set the title + wActionBar.setWindowTitle(mActivity.getTitle()); + } + } + + @Override + protected Context getThemedContext() { + return aActionBar.getThemedContext(); + } + + @Override + public void setTitle(CharSequence title) { + if (DEBUG) Log.d(TAG, "[setTitle] title: " + title); + + dispatchTitleChanged(title, 0); + } + + @Override + public ActionMode startActionMode(ActionMode.Callback callback) { + if (DEBUG) Log.d(TAG, "[startActionMode] callback: " + callback); + + if (mActionMode != null) { + mActionMode.finish(); + } + + final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback); + ActionMode mode = null; + + //Emulate Activity's onWindowStartingActionMode: + initActionBar(); + if (aActionBar != null) { + mode = aActionBar.startActionMode(wrappedCallback); + } + + if (mode != null) { + mActionMode = mode; + } else { + if (mActionModeView == null) { + ViewStub stub = (ViewStub)mDecor.findViewById(R.id.abs__action_mode_bar_stub); + if (stub != null) { + mActionModeView = (ActionBarContextView)stub.inflate(); + } + } + if (mActionModeView != null) { + mActionModeView.killMode(); + mode = new StandaloneActionMode(mActivity, mActionModeView, wrappedCallback, true); + if (callback.onCreateActionMode(mode, mode.getMenu())) { + mode.invalidate(); + mActionModeView.initForMode(mode); + mActionModeView.setVisibility(View.VISIBLE); + mActionMode = mode; + mActionModeView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + } else { + mActionMode = null; + } + } + } + if (mActionMode != null && mActivity instanceof OnActionModeStartedListener) { + ((OnActionModeStartedListener)mActivity).onActionModeStarted(mActionMode); + } + return mActionMode; + } + + + /////////////////////////////////////////////////////////////////////////// + // Lifecycle and interaction callbacks for delegation + /////////////////////////////////////////////////////////////////////////// + + @Override + public void dispatchConfigurationChanged(Configuration newConfig) { + if (DEBUG) Log.d(TAG, "[dispatchConfigurationChanged] newConfig: " + newConfig); + + if (aActionBar != null) { + aActionBar.onConfigurationChanged(newConfig); + } + } + + @Override + public void dispatchPostResume() { + if (DEBUG) Log.d(TAG, "[dispatchPostResume]"); + + if (aActionBar != null) { + aActionBar.setShowHideAnimationEnabled(true); + } + } + + @Override + public void dispatchPause() { + if (DEBUG) Log.d(TAG, "[dispatchPause]"); + + if (wActionBar != null && wActionBar.isOverflowMenuShowing()) { + wActionBar.hideOverflowMenu(); + } + } + + @Override + public void dispatchStop() { + if (DEBUG) Log.d(TAG, "[dispatchStop]"); + + if (aActionBar != null) { + aActionBar.setShowHideAnimationEnabled(false); + } + } + + @Override + public void dispatchInvalidateOptionsMenu() { + if (DEBUG) Log.d(TAG, "[dispatchInvalidateOptionsMenu]"); + + Bundle savedActionViewStates = null; + if (mMenu != null) { + savedActionViewStates = new Bundle(); + mMenu.saveActionViewStates(savedActionViewStates); + if (savedActionViewStates.size() > 0) { + mMenuFrozenActionViewState = savedActionViewStates; + } + // This will be started again when the panel is prepared. + mMenu.stopDispatchingItemsChanged(); + mMenu.clear(); + } + mMenuRefreshContent = true; + + // Prepare the options panel if we have an action bar + if (wActionBar != null) { + mMenuIsPrepared = false; + preparePanel(); + } + } + + @Override + public boolean dispatchOpenOptionsMenu() { + if (DEBUG) Log.d(TAG, "[dispatchOpenOptionsMenu]"); + + if (!isReservingOverflow()) { + return false; + } + + return wActionBar.showOverflowMenu(); + } + + @Override + public boolean dispatchCloseOptionsMenu() { + if (DEBUG) Log.d(TAG, "[dispatchCloseOptionsMenu]"); + + if (!isReservingOverflow()) { + return false; + } + + if (wActionBar != null) { + return wActionBar.hideOverflowMenu(); + } + return false; + } + + @Override + public void dispatchPostCreate(Bundle savedInstanceState) { + if (DEBUG) Log.d(TAG, "[dispatchOnPostCreate]"); + + if (mIsDelegate) { + mIsTitleReady = true; + } + + if (mDecor == null) { + initActionBar(); + } + } + + @Override + public boolean dispatchCreateOptionsMenu(android.view.Menu menu) { + if (DEBUG) { + Log.d(TAG, "[dispatchCreateOptionsMenu] android.view.Menu: " + menu); + Log.d(TAG, "[dispatchCreateOptionsMenu] returning true"); + } + return true; + } + + @Override + public boolean dispatchPrepareOptionsMenu(android.view.Menu menu) { + if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] android.view.Menu: " + menu); + + if (mActionMode != null) { + return false; + } + + mMenuIsPrepared = false; + if (!preparePanel()) { + return false; + } + + if (isReservingOverflow()) { + return false; + } + + if (mNativeItemMap == null) { + mNativeItemMap = new HashMap(); + } else { + mNativeItemMap.clear(); + } + + if (mMenu == null) { + return false; + } + + boolean result = mMenu.bindNativeOverflow(menu, this, mNativeItemMap); + if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] returning " + result); + return result; + } + + @Override + public boolean dispatchOptionsItemSelected(android.view.MenuItem item) { + throw new IllegalStateException("Native callback invoked. Create a test case and report!"); + } + + @Override + public boolean dispatchMenuOpened(int featureId, android.view.Menu menu) { + if (DEBUG) Log.d(TAG, "[dispatchMenuOpened] featureId: " + featureId + ", menu: " + menu); + + if (featureId == Window.FEATURE_ACTION_BAR || featureId == Window.FEATURE_OPTIONS_PANEL) { + if (aActionBar != null) { + aActionBar.dispatchMenuVisibilityChanged(true); + } + return true; + } + + return false; + } + + @Override + public void dispatchPanelClosed(int featureId, android.view.Menu menu){ + if (DEBUG) Log.d(TAG, "[dispatchPanelClosed] featureId: " + featureId + ", menu: " + menu); + + if (featureId == Window.FEATURE_ACTION_BAR || featureId == Window.FEATURE_OPTIONS_PANEL) { + if (aActionBar != null) { + aActionBar.dispatchMenuVisibilityChanged(false); + } + } + } + + @Override + public void dispatchTitleChanged(CharSequence title, int color) { + if (DEBUG) Log.d(TAG, "[dispatchTitleChanged] title: " + title + ", color: " + color); + + if (!mIsDelegate || mIsTitleReady) { + if (mTitleView != null) { + mTitleView.setText(title); + } else if (wActionBar != null) { + wActionBar.setWindowTitle(title); + } + } + + mTitle = title; + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] event: " + event); + + final int keyCode = event.getKeyCode(); + + // Not handled by the view hierarchy, does the action bar want it + // to cancel out of something special? + if (keyCode == KeyEvent.KEYCODE_BACK) { + final int action = event.getAction(); + // Back cancels action modes first. + if (mActionMode != null) { + if (action == KeyEvent.ACTION_UP) { + mActionMode.finish(); + } + if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning true"); + return true; + } + + // Next collapse any expanded action views. + if (wActionBar != null && wActionBar.hasExpandedActionView()) { + if (action == KeyEvent.ACTION_UP) { + wActionBar.collapseActionView(); + } + if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning true"); + return true; + } + } + + if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning false"); + return false; + } + + @Override + public void dispatchDestroy() { + mIsDestroyed = true; + } + + @Override + public void dispatchSaveInstanceState(Bundle outState) { + if (mMenu != null) { + mMenuFrozenActionViewState = new Bundle(); + mMenu.saveActionViewStates(mMenuFrozenActionViewState); + } + outState.putParcelable(PANELS_TAG, mMenuFrozenActionViewState); + } + + @Override + public void dispatchRestoreInstanceState(Bundle savedInstanceState) { + mMenuFrozenActionViewState = savedInstanceState.getParcelable(PANELS_TAG); + } + + /////////////////////////////////////////////////////////////////////////// + // Menu callback lifecycle and creation + /////////////////////////////////////////////////////////////////////////// + + private boolean preparePanel() { + // Already prepared (isPrepared will be reset to false later) + if (mMenuIsPrepared) { + return true; + } + + // Init the panel state's menu--return false if init failed + if (mMenu == null || mMenuRefreshContent) { + if (mMenu == null) { + if (!initializePanelMenu() || (mMenu == null)) { + return false; + } + } + + if (wActionBar != null) { + wActionBar.setMenu(mMenu, this); + } + + // Call callback, and return if it doesn't want to display menu. + + // Creating the panel menu will involve a lot of manipulation; + // don't dispatch change events to presenters until we're done. + mMenu.stopDispatchingItemsChanged(); + if (!callbackCreateOptionsMenu(mMenu)) { + // Ditch the menu created above + mMenu = null; + + if (wActionBar != null) { + // Don't show it in the action bar either + wActionBar.setMenu(null, this); + } + + return false; + } + + mMenuRefreshContent = false; + } + + // Callback and return if the callback does not want to show the menu + + // Preparing the panel menu can involve a lot of manipulation; + // don't dispatch change events to presenters until we're done. + mMenu.stopDispatchingItemsChanged(); + + // Restore action view state before we prepare. This gives apps + // an opportunity to override frozen/restored state in onPrepare. + if (mMenuFrozenActionViewState != null) { + mMenu.restoreActionViewStates(mMenuFrozenActionViewState); + mMenuFrozenActionViewState = null; + } + + if (!callbackPrepareOptionsMenu(mMenu)) { + if (wActionBar != null) { + // The app didn't want to show the menu for now but it still exists. + // Clear it out of the action bar. + wActionBar.setMenu(null, this); + } + mMenu.startDispatchingItemsChanged(); + return false; + } + + // Set the proper keymap + KeyCharacterMap kmap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); + mMenu.setQwertyMode(kmap.getKeyboardType() != KeyCharacterMap.NUMERIC); + mMenu.startDispatchingItemsChanged(); + + // Set other state + mMenuIsPrepared = true; + + return true; + } + + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { + return callbackOptionsItemSelected(item); + } + + public void onMenuModeChange(MenuBuilder menu) { + reopenMenu(true); + } + + private void reopenMenu(boolean toggleMenuMode) { + if (wActionBar != null && wActionBar.isOverflowReserved()) { + if (!wActionBar.isOverflowMenuShowing() || !toggleMenuMode) { + if (wActionBar.getVisibility() == View.VISIBLE) { + if (callbackPrepareOptionsMenu(mMenu)) { + wActionBar.showOverflowMenu(); + } + } + } else { + wActionBar.hideOverflowMenu(); + } + return; + } + } + + private boolean initializePanelMenu() { + Context context = mActivity;//getContext(); + + // If we have an action bar, initialize the menu with a context themed for it. + if (wActionBar != null) { + TypedValue outValue = new TypedValue(); + Resources.Theme currentTheme = context.getTheme(); + currentTheme.resolveAttribute(R.attr.actionBarWidgetTheme, + outValue, true); + final int targetThemeRes = outValue.resourceId; + + if (targetThemeRes != 0 /*&& context.getThemeResId() != targetThemeRes*/) { + context = new ContextThemeWrapper(context, targetThemeRes); + } + } + + mMenu = new MenuBuilder(context); + mMenu.setCallback(this); + + return true; + } + + void checkCloseActionMenu(Menu menu) { + if (mClosingActionMenu) { + return; + } + + mClosingActionMenu = true; + wActionBar.dismissPopupMenus(); + //Callback cb = getCallback(); + //if (cb != null && !isDestroyed()) { + // cb.onPanelClosed(FEATURE_ACTION_BAR, menu); + //} + mClosingActionMenu = false; + } + + @Override + public boolean onOpenSubMenu(MenuBuilder subMenu) { + return true; + } + + @Override + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + checkCloseActionMenu(menu); + } + + @Override + public boolean onMenuItemClick(android.view.MenuItem item) { + if (DEBUG) Log.d(TAG, "[mNativeItemListener.onMenuItemClick] item: " + item); + + final MenuItemImpl sherlockItem = mNativeItemMap.get(item); + if (sherlockItem != null) { + sherlockItem.invoke(); + } else { + Log.e(TAG, "Options item \"" + item + "\" not found in mapping"); + } + + return true; //Do not allow continuation of native handling + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + return callbackOptionsItemSelected(item); + } + + + /////////////////////////////////////////////////////////////////////////// + // Progress bar interaction and internal handling + /////////////////////////////////////////////////////////////////////////// + + @Override + public void setProgressBarVisibility(boolean visible) { + if (DEBUG) Log.d(TAG, "[setProgressBarVisibility] visible: " + visible); + + setFeatureInt(Window.FEATURE_PROGRESS, visible ? Window.PROGRESS_VISIBILITY_ON : + Window.PROGRESS_VISIBILITY_OFF); + } + + @Override + public void setProgressBarIndeterminateVisibility(boolean visible) { + if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminateVisibility] visible: " + visible); + + setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS, + visible ? Window.PROGRESS_VISIBILITY_ON : Window.PROGRESS_VISIBILITY_OFF); + } + + @Override + public void setProgressBarIndeterminate(boolean indeterminate) { + if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminate] indeterminate: " + indeterminate); + + setFeatureInt(Window.FEATURE_PROGRESS, + indeterminate ? Window.PROGRESS_INDETERMINATE_ON : Window.PROGRESS_INDETERMINATE_OFF); + } + + @Override + public void setProgress(int progress) { + if (DEBUG) Log.d(TAG, "[setProgress] progress: " + progress); + + setFeatureInt(Window.FEATURE_PROGRESS, progress + Window.PROGRESS_START); + } + + @Override + public void setSecondaryProgress(int secondaryProgress) { + if (DEBUG) Log.d(TAG, "[setSecondaryProgress] secondaryProgress: " + secondaryProgress); + + setFeatureInt(Window.FEATURE_PROGRESS, + secondaryProgress + Window.PROGRESS_SECONDARY_START); + } + + private void setFeatureInt(int featureId, int value) { + updateInt(featureId, value, false); + } + + private void updateInt(int featureId, int value, boolean fromResume) { + // Do nothing if the decor is not yet installed... an update will + // need to be forced when we eventually become active. + if (mContentParent == null) { + return; + } + + final int featureMask = 1 << featureId; + + if ((getFeatures() & featureMask) == 0 && !fromResume) { + return; + } + + onIntChanged(featureId, value); + } + + private void onIntChanged(int featureId, int value) { + if (featureId == Window.FEATURE_PROGRESS || featureId == Window.FEATURE_INDETERMINATE_PROGRESS) { + updateProgressBars(value); + } + } + + private void updateProgressBars(int value) { + IcsProgressBar circularProgressBar = getCircularProgressBar(true); + IcsProgressBar horizontalProgressBar = getHorizontalProgressBar(true); + + final int features = mFeatures;//getLocalFeatures(); + if (value == Window.PROGRESS_VISIBILITY_ON) { + if ((features & (1 << Window.FEATURE_PROGRESS)) != 0) { + int level = horizontalProgressBar.getProgress(); + int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ? + View.VISIBLE : View.INVISIBLE; + horizontalProgressBar.setVisibility(visibility); + } + if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0) { + circularProgressBar.setVisibility(View.VISIBLE); + } + } else if (value == Window.PROGRESS_VISIBILITY_OFF) { + if ((features & (1 << Window.FEATURE_PROGRESS)) != 0) { + horizontalProgressBar.setVisibility(View.GONE); + } + if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0) { + circularProgressBar.setVisibility(View.GONE); + } + } else if (value == Window.PROGRESS_INDETERMINATE_ON) { + horizontalProgressBar.setIndeterminate(true); + } else if (value == Window.PROGRESS_INDETERMINATE_OFF) { + horizontalProgressBar.setIndeterminate(false); + } else if (Window.PROGRESS_START <= value && value <= Window.PROGRESS_END) { + // We want to set the progress value before testing for visibility + // so that when the progress bar becomes visible again, it has the + // correct level. + horizontalProgressBar.setProgress(value - Window.PROGRESS_START); + + if (value < Window.PROGRESS_END) { + showProgressBars(horizontalProgressBar, circularProgressBar); + } else { + hideProgressBars(horizontalProgressBar, circularProgressBar); + } + } else if (Window.PROGRESS_SECONDARY_START <= value && value <= Window.PROGRESS_SECONDARY_END) { + horizontalProgressBar.setSecondaryProgress(value - Window.PROGRESS_SECONDARY_START); + + showProgressBars(horizontalProgressBar, circularProgressBar); + } + } + + private void showProgressBars(IcsProgressBar horizontalProgressBar, IcsProgressBar spinnyProgressBar) { + final int features = mFeatures;//getLocalFeatures(); + if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0 && + spinnyProgressBar.getVisibility() == View.INVISIBLE) { + spinnyProgressBar.setVisibility(View.VISIBLE); + } + // Only show the progress bars if the primary progress is not complete + if ((features & (1 << Window.FEATURE_PROGRESS)) != 0 && + horizontalProgressBar.getProgress() < 10000) { + horizontalProgressBar.setVisibility(View.VISIBLE); + } + } + + private void hideProgressBars(IcsProgressBar horizontalProgressBar, IcsProgressBar spinnyProgressBar) { + final int features = mFeatures;//getLocalFeatures(); + Animation anim = AnimationUtils.loadAnimation(mActivity, android.R.anim.fade_out); + anim.setDuration(1000); + if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0 && + spinnyProgressBar.getVisibility() == View.VISIBLE) { + spinnyProgressBar.startAnimation(anim); + spinnyProgressBar.setVisibility(View.INVISIBLE); + } + if ((features & (1 << Window.FEATURE_PROGRESS)) != 0 && + horizontalProgressBar.getVisibility() == View.VISIBLE) { + horizontalProgressBar.startAnimation(anim); + horizontalProgressBar.setVisibility(View.INVISIBLE); + } + } + + private IcsProgressBar getCircularProgressBar(boolean shouldInstallDecor) { + if (mCircularProgressBar != null) { + return mCircularProgressBar; + } + if (mContentParent == null && shouldInstallDecor) { + installDecor(); + } + mCircularProgressBar = (IcsProgressBar)mDecor.findViewById(R.id.abs__progress_circular); + if (mCircularProgressBar != null) { + mCircularProgressBar.setVisibility(View.INVISIBLE); + } + return mCircularProgressBar; + } + + private IcsProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) { + if (mHorizontalProgressBar != null) { + return mHorizontalProgressBar; + } + if (mContentParent == null && shouldInstallDecor) { + installDecor(); + } + mHorizontalProgressBar = (IcsProgressBar)mDecor.findViewById(R.id.abs__progress_horizontal); + if (mHorizontalProgressBar != null) { + mHorizontalProgressBar.setVisibility(View.INVISIBLE); + } + return mHorizontalProgressBar; + } + + + /////////////////////////////////////////////////////////////////////////// + // Feature management and content interaction and creation + /////////////////////////////////////////////////////////////////////////// + + private int getFeatures() { + if (DEBUG) Log.d(TAG, "[getFeatures] returning " + mFeatures); + + return mFeatures; + } + + @Override + public boolean hasFeature(int featureId) { + if (DEBUG) Log.d(TAG, "[hasFeature] featureId: " + featureId); + + boolean result = (mFeatures & (1 << featureId)) != 0; + if (DEBUG) Log.d(TAG, "[hasFeature] returning " + result); + return result; + } + + @Override + public boolean requestFeature(int featureId) { + if (DEBUG) Log.d(TAG, "[requestFeature] featureId: " + featureId); + + if (mContentParent != null) { + throw new AndroidRuntimeException("requestFeature() must be called before adding content"); + } + + switch (featureId) { + case Window.FEATURE_ACTION_BAR: + case Window.FEATURE_ACTION_BAR_OVERLAY: + case Window.FEATURE_ACTION_MODE_OVERLAY: + case Window.FEATURE_INDETERMINATE_PROGRESS: + case Window.FEATURE_NO_TITLE: + case Window.FEATURE_PROGRESS: + mFeatures |= (1 << featureId); + return true; + + default: + return false; + } + } + + @Override + public void setUiOptions(int uiOptions) { + if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions); + + mUiOptions = uiOptions; + } + + @Override + public void setUiOptions(int uiOptions, int mask) { + if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions + ", mask: " + mask); + + mUiOptions = (mUiOptions & ~mask) | (uiOptions & mask); + } + + @Override + public void setContentView(int layoutResId) { + if (DEBUG) Log.d(TAG, "[setContentView] layoutResId: " + layoutResId); + + if (mContentParent == null) { + installDecor(); + } else { + mContentParent.removeAllViews(); + } + mActivity.getLayoutInflater().inflate(layoutResId, mContentParent); + + android.view.Window.Callback callback = mActivity.getWindow().getCallback(); + if (callback != null) { + callback.onContentChanged(); + } + + initActionBar(); + } + + @Override + public void setContentView(View view, ViewGroup.LayoutParams params) { + if (DEBUG) Log.d(TAG, "[setContentView] view: " + view + ", params: " + params); + + if (mContentParent == null) { + installDecor(); + } else { + mContentParent.removeAllViews(); + } + mContentParent.addView(view, params); + + android.view.Window.Callback callback = mActivity.getWindow().getCallback(); + if (callback != null) { + callback.onContentChanged(); + } + + initActionBar(); + } + + @Override + public void addContentView(View view, ViewGroup.LayoutParams params) { + if (DEBUG) Log.d(TAG, "[addContentView] view: " + view + ", params: " + params); + + if (mContentParent == null) { + installDecor(); + } + mContentParent.addView(view, params); + + initActionBar(); + } + + private void installDecor() { + if (DEBUG) Log.d(TAG, "[installDecor]"); + + if (mDecor == null) { + mDecor = (ViewGroup)mActivity.getWindow().getDecorView().findViewById(android.R.id.content); + } + if (mContentParent == null) { + //Since we are not operating at the window level we need to take + //into account the fact that the true decor may have already been + //initialized and had content attached to it. If that is the case, + //copy over its children to our new content container. + List views = null; + if (mDecor.getChildCount() > 0) { + views = new ArrayList(1); //Usually there's only one child + for (int i = 0, children = mDecor.getChildCount(); i < children; i++) { + View child = mDecor.getChildAt(0); + mDecor.removeView(child); + views.add(child); + } + } + + mContentParent = generateLayout(); + + //Copy over the old children. See above for explanation. + if (views != null) { + for (View child : views) { + mContentParent.addView(child); + } + } + + mTitleView = (TextView)mDecor.findViewById(android.R.id.title); + if (mTitleView != null) { + if (hasFeature(Window.FEATURE_NO_TITLE)) { + mTitleView.setVisibility(View.GONE); + if (mContentParent instanceof FrameLayout) { + ((FrameLayout)mContentParent).setForeground(null); + } + } else { + mTitleView.setText(mTitle); + } + } else { + wActionBar = (ActionBarView)mDecor.findViewById(R.id.abs__action_bar); + if (wActionBar != null) { + wActionBar.setWindowCallback(this); + if (wActionBar.getTitle() == null) { + wActionBar.setWindowTitle(mActivity.getTitle()); + } + if (hasFeature(Window.FEATURE_PROGRESS)) { + wActionBar.initProgress(); + } + if (hasFeature(Window.FEATURE_INDETERMINATE_PROGRESS)) { + wActionBar.initIndeterminateProgress(); + } + + //Since we don't require onCreate dispatching, parse for uiOptions here + int uiOptions = loadUiOptionsFromManifest(mActivity); + if (uiOptions != 0) { + mUiOptions = uiOptions; + } + + boolean splitActionBar = false; + final boolean splitWhenNarrow = (mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0; + if (splitWhenNarrow) { + splitActionBar = getResources_getBoolean(mActivity, R.bool.abs__split_action_bar_is_narrow); + } else { + splitActionBar = mActivity.getTheme() + .obtainStyledAttributes(R.styleable.SherlockTheme) + .getBoolean(R.styleable.SherlockTheme_windowSplitActionBar, false); + } + final ActionBarContainer splitView = (ActionBarContainer)mDecor.findViewById(R.id.abs__split_action_bar); + if (splitView != null) { + wActionBar.setSplitView(splitView); + wActionBar.setSplitActionBar(splitActionBar); + wActionBar.setSplitWhenNarrow(splitWhenNarrow); + + mActionModeView = (ActionBarContextView)mDecor.findViewById(R.id.abs__action_context_bar); + mActionModeView.setSplitView(splitView); + mActionModeView.setSplitActionBar(splitActionBar); + mActionModeView.setSplitWhenNarrow(splitWhenNarrow); + } else if (splitActionBar) { + Log.e(TAG, "Requested split action bar with incompatible window decor! Ignoring request."); + } + + // Post the panel invalidate for later; avoid application onCreateOptionsMenu + // being called in the middle of onCreate or similar. + mDecor.post(new Runnable() { + @Override + public void run() { + //Invalidate if the panel menu hasn't been created before this. + if (!mIsDestroyed && !mActivity.isFinishing() && mMenu == null) { + dispatchInvalidateOptionsMenu(); + } + } + }); + } + } + } + } + + private ViewGroup generateLayout() { + if (DEBUG) Log.d(TAG, "[generateLayout]"); + + // Apply data from current theme. + + TypedArray a = mActivity.getTheme().obtainStyledAttributes(R.styleable.SherlockTheme); + + mIsFloating = a.getBoolean(R.styleable.SherlockTheme_android_windowIsFloating, false); + + if (!a.hasValue(R.styleable.SherlockTheme_windowActionBar)) { + throw new IllegalStateException("You must use Theme.Sherlock, Theme.Sherlock.Light, Theme.Sherlock.Light.DarkActionBar, or a derivative."); + } + + if (a.getBoolean(R.styleable.SherlockTheme_windowNoTitle, false)) { + requestFeature(Window.FEATURE_NO_TITLE); + } else if (a.getBoolean(R.styleable.SherlockTheme_windowActionBar, false)) { + // Don't allow an action bar if there is no title. + requestFeature(Window.FEATURE_ACTION_BAR); + } + + if (a.getBoolean(R.styleable.SherlockTheme_windowActionBarOverlay, false)) { + requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY); + } + + if (a.getBoolean(R.styleable.SherlockTheme_windowActionModeOverlay, false)) { + requestFeature(Window.FEATURE_ACTION_MODE_OVERLAY); + } + + a.recycle(); + + int layoutResource; + if (!hasFeature(Window.FEATURE_NO_TITLE)) { + if (mIsFloating) { + //Trash original dialog LinearLayout + mDecor = (ViewGroup)mDecor.getParent(); + mDecor.removeAllViews(); + + layoutResource = R.layout.abs__dialog_title_holo; + } else { + if (hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) { + layoutResource = R.layout.abs__screen_action_bar_overlay; + } else { + layoutResource = R.layout.abs__screen_action_bar; + } + } + } else if (hasFeature(Window.FEATURE_ACTION_MODE_OVERLAY) && !hasFeature(Window.FEATURE_NO_TITLE)) { + layoutResource = R.layout.abs__screen_simple_overlay_action_mode; + } else { + layoutResource = R.layout.abs__screen_simple; + } + + if (DEBUG) Log.d(TAG, "[generateLayout] using screen XML " + mActivity.getResources().getString(layoutResource)); + View in = mActivity.getLayoutInflater().inflate(layoutResource, null); + mDecor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); + + ViewGroup contentParent = (ViewGroup)mDecor.findViewById(R.id.abs__content); + if (contentParent == null) { + throw new RuntimeException("Couldn't find content container view"); + } + + //Make our new child the true content view (for fragments). VERY VOLATILE! + mDecor.setId(View.NO_ID); + contentParent.setId(android.R.id.content); + + if (hasFeature(Window.FEATURE_INDETERMINATE_PROGRESS)) { + IcsProgressBar progress = getCircularProgressBar(false); + if (progress != null) { + progress.setIndeterminate(true); + } + } + + return contentParent; + } + + + /////////////////////////////////////////////////////////////////////////// + // Miscellaneous + /////////////////////////////////////////////////////////////////////////// + + /** + * Determine whether or not the device has a dedicated menu key. + * + * @return {@code true} if native menu key is present. + */ + private boolean isReservingOverflow() { + if (!mReserveOverflowSet) { + mReserveOverflow = ActionMenuPresenter.reserveOverflow(mActivity); + mReserveOverflowSet = true; + } + return mReserveOverflow; + } + + private static int loadUiOptionsFromManifest(Activity activity) { + int uiOptions = 0; + try { + final String thisPackage = activity.getClass().getName(); + if (DEBUG) Log.i(TAG, "Parsing AndroidManifest.xml for " + thisPackage); + + final String packageName = activity.getApplicationInfo().packageName; + final AssetManager am = activity.createPackageContext(packageName, 0).getAssets(); + final XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml"); + + int eventType = xml.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + String name = xml.getName(); + + if ("application".equals(name)) { + //Check if the has the attribute + if (DEBUG) Log.d(TAG, "Got "); + + for (int i = xml.getAttributeCount() - 1; i >= 0; i--) { + if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i)); + + if ("uiOptions".equals(xml.getAttributeName(i))) { + uiOptions = xml.getAttributeIntValue(i, 0); + break; //out of for loop + } + } + } else if ("activity".equals(name)) { + //Check if the is us and has the attribute + if (DEBUG) Log.d(TAG, "Got "); + Integer activityUiOptions = null; + String activityPackage = null; + boolean isOurActivity = false; + + for (int i = xml.getAttributeCount() - 1; i >= 0; i--) { + if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i)); + + //We need both uiOptions and name attributes + String attrName = xml.getAttributeName(i); + if ("uiOptions".equals(attrName)) { + activityUiOptions = xml.getAttributeIntValue(i, 0); + } else if ("name".equals(attrName)) { + activityPackage = cleanActivityName(packageName, xml.getAttributeValue(i)); + if (!thisPackage.equals(activityPackage)) { + break; //out of for loop + } + isOurActivity = true; + } + + //Make sure we have both attributes before processing + if ((activityUiOptions != null) && (activityPackage != null)) { + //Our activity, uiOptions specified, override with our value + uiOptions = activityUiOptions.intValue(); + } + } + if (isOurActivity) { + //If we matched our activity but it had no logo don't + //do any more processing of the manifest + break; + } + } + } + eventType = xml.nextToken(); + } + } catch (Exception e) { + e.printStackTrace(); + } + if (DEBUG) Log.i(TAG, "Returning " + Integer.toHexString(uiOptions)); + return uiOptions; + } + + public static String cleanActivityName(String manifestPackage, String activityName) { + if (activityName.charAt(0) == '.') { + //Relative activity name (e.g., android:name=".ui.SomeClass") + return manifestPackage + activityName; + } + if (activityName.indexOf('.', 1) == -1) { + //Unqualified activity name (e.g., android:name="SomeClass") + return manifestPackage + "." + activityName; + } + //Fully-qualified activity name (e.g., "com.my.package.SomeClass") + return activityName; + } + + /** + * Clears out internal reference when the action mode is destroyed. + */ + private class ActionModeCallbackWrapper implements ActionMode.Callback { + private final ActionMode.Callback mWrapped; + + public ActionModeCallbackWrapper(ActionMode.Callback wrapped) { + mWrapped = wrapped; + } + + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + return mWrapped.onCreateActionMode(mode, menu); + } + + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return mWrapped.onPrepareActionMode(mode, menu); + } + + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + return mWrapped.onActionItemClicked(mode, item); + } + + public void onDestroyActionMode(ActionMode mode) { + mWrapped.onDestroyActionMode(mode); + if (mActionModeView != null) { + mActionModeView.setVisibility(View.GONE); + mActionModeView.removeAllViews(); + } + if (mActivity instanceof OnActionModeFinishedListener) { + ((OnActionModeFinishedListener)mActivity).onActionModeFinished(mActionMode); + } + mActionMode = null; + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java new file mode 100644 index 00000000..0824d384 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java @@ -0,0 +1,336 @@ +package com.actionbarsherlock.internal; + +import com.actionbarsherlock.ActionBarSherlock; +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.internal.app.ActionBarWrapper; +import com.actionbarsherlock.internal.view.menu.MenuWrapper; +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.MenuInflater; +import android.app.Activity; +import android.content.Context; +import android.util.Log; +import android.util.TypedValue; +import android.view.ContextThemeWrapper; +import android.view.View; +import android.view.Window; +import android.view.ViewGroup.LayoutParams; + +@ActionBarSherlock.Implementation(api = 14) +public class ActionBarSherlockNative extends ActionBarSherlock { + private ActionBarWrapper mActionBar; + private ActionModeWrapper mActionMode; + private MenuWrapper mMenu; + + public ActionBarSherlockNative(Activity activity, int flags) { + super(activity, flags); + } + + + @Override + public ActionBar getActionBar() { + if (DEBUG) Log.d(TAG, "[getActionBar]"); + + initActionBar(); + return mActionBar; + } + + private void initActionBar() { + if (mActionBar != null || mActivity.getActionBar() == null) { + return; + } + + mActionBar = new ActionBarWrapper(mActivity); + } + + @Override + public void dispatchInvalidateOptionsMenu() { + if (DEBUG) Log.d(TAG, "[dispatchInvalidateOptionsMenu]"); + + mActivity.getWindow().invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL); + } + + @Override + public boolean dispatchCreateOptionsMenu(android.view.Menu menu) { + if (DEBUG) Log.d(TAG, "[dispatchCreateOptionsMenu] menu: " + menu); + + if (mMenu == null || menu != mMenu.unwrap()) { + mMenu = new MenuWrapper(menu); + } + + final boolean result = callbackCreateOptionsMenu(mMenu); + if (DEBUG) Log.d(TAG, "[dispatchCreateOptionsMenu] returning " + result); + return result; + } + + @Override + public boolean dispatchPrepareOptionsMenu(android.view.Menu menu) { + if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] menu: " + menu); + + final boolean result = callbackPrepareOptionsMenu(mMenu); + if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] returning " + result); + return result; + } + + @Override + public boolean dispatchOptionsItemSelected(android.view.MenuItem item) { + if (DEBUG) Log.d(TAG, "[dispatchOptionsItemSelected] item: " + item.getTitleCondensed()); + + final boolean result = callbackOptionsItemSelected(mMenu.findItem(item)); + if (DEBUG) Log.d(TAG, "[dispatchOptionsItemSelected] returning " + result); + return result; + } + + @Override + public boolean hasFeature(int feature) { + if (DEBUG) Log.d(TAG, "[hasFeature] feature: " + feature); + + final boolean result = mActivity.getWindow().hasFeature(feature); + if (DEBUG) Log.d(TAG, "[hasFeature] returning " + result); + return result; + } + + @Override + public boolean requestFeature(int featureId) { + if (DEBUG) Log.d(TAG, "[requestFeature] featureId: " + featureId); + + final boolean result = mActivity.getWindow().requestFeature(featureId); + if (DEBUG) Log.d(TAG, "[requestFeature] returning " + result); + return result; + } + + @Override + public void setUiOptions(int uiOptions) { + if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions); + + mActivity.getWindow().setUiOptions(uiOptions); + } + + @Override + public void setUiOptions(int uiOptions, int mask) { + if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions + ", mask: " + mask); + + mActivity.getWindow().setUiOptions(uiOptions, mask); + } + + @Override + public void setContentView(int layoutResId) { + if (DEBUG) Log.d(TAG, "[setContentView] layoutResId: " + layoutResId); + + mActivity.getWindow().setContentView(layoutResId); + initActionBar(); + } + + @Override + public void setContentView(View view, LayoutParams params) { + if (DEBUG) Log.d(TAG, "[setContentView] view: " + view + ", params: " + params); + + mActivity.getWindow().setContentView(view, params); + initActionBar(); + } + + @Override + public void addContentView(View view, LayoutParams params) { + if (DEBUG) Log.d(TAG, "[addContentView] view: " + view + ", params: " + params); + + mActivity.getWindow().addContentView(view, params); + initActionBar(); + } + + @Override + public void setTitle(CharSequence title) { + if (DEBUG) Log.d(TAG, "[setTitle] title: " + title); + + mActivity.getWindow().setTitle(title); + } + + @Override + public void setProgressBarVisibility(boolean visible) { + if (DEBUG) Log.d(TAG, "[setProgressBarVisibility] visible: " + visible); + + mActivity.setProgressBarVisibility(visible); + } + + @Override + public void setProgressBarIndeterminateVisibility(boolean visible) { + if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminateVisibility] visible: " + visible); + + mActivity.setProgressBarIndeterminateVisibility(visible); + } + + @Override + public void setProgressBarIndeterminate(boolean indeterminate) { + if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminate] indeterminate: " + indeterminate); + + mActivity.setProgressBarIndeterminate(indeterminate); + } + + @Override + public void setProgress(int progress) { + if (DEBUG) Log.d(TAG, "[setProgress] progress: " + progress); + + mActivity.setProgress(progress); + } + + @Override + public void setSecondaryProgress(int secondaryProgress) { + if (DEBUG) Log.d(TAG, "[setSecondaryProgress] secondaryProgress: " + secondaryProgress); + + mActivity.setSecondaryProgress(secondaryProgress); + } + + @Override + protected Context getThemedContext() { + Context context = mActivity; + TypedValue outValue = new TypedValue(); + mActivity.getTheme().resolveAttribute(android.R.attr.actionBarWidgetTheme, outValue, true); + if (outValue.resourceId != 0) { + //We are unable to test if this is the same as our current theme + //so we just wrap it and hope that if the attribute was specified + //then the user is intentionally specifying an alternate theme. + context = new ContextThemeWrapper(context, outValue.resourceId); + } + return context; + } + + @Override + public ActionMode startActionMode(com.actionbarsherlock.view.ActionMode.Callback callback) { + if (DEBUG) Log.d(TAG, "[startActionMode] callback: " + callback); + + if (mActionMode != null) { + mActionMode.finish(); + } + ActionModeCallbackWrapper wrapped = null; + if (callback != null) { + wrapped = new ActionModeCallbackWrapper(callback); + } + + //Calling this will trigger the callback wrapper's onCreate which + //is where we will set the new instance to mActionMode since we need + //to pass it through to the sherlock callbacks and the call below + //will not have returned yet to store its value. + if (mActivity.startActionMode(wrapped) == null) { + mActionMode = null; + } + if (mActivity instanceof OnActionModeStartedListener && mActionMode != null) { + ((OnActionModeStartedListener)mActivity).onActionModeStarted(mActionMode); + } + + return mActionMode; + } + + private class ActionModeCallbackWrapper implements android.view.ActionMode.Callback { + private final ActionMode.Callback mCallback; + + public ActionModeCallbackWrapper(ActionMode.Callback callback) { + mCallback = callback; + } + + @Override + public boolean onCreateActionMode(android.view.ActionMode mode, android.view.Menu menu) { + //See ActionBarSherlockNative#startActionMode + mActionMode = new ActionModeWrapper(mode); + + return mCallback.onCreateActionMode(mActionMode, mActionMode.getMenu()); + } + + @Override + public boolean onPrepareActionMode(android.view.ActionMode mode, android.view.Menu menu) { + return mCallback.onPrepareActionMode(mActionMode, mActionMode.getMenu()); + } + + @Override + public boolean onActionItemClicked(android.view.ActionMode mode, android.view.MenuItem item) { + return mCallback.onActionItemClicked(mActionMode, mActionMode.getMenu().findItem(item)); + } + + @Override + public void onDestroyActionMode(android.view.ActionMode mode) { + mCallback.onDestroyActionMode(mActionMode); + if (mActivity instanceof OnActionModeFinishedListener) { + ((OnActionModeFinishedListener)mActivity).onActionModeFinished(mActionMode); + } + } + } + + private class ActionModeWrapper extends ActionMode { + private final android.view.ActionMode mActionMode; + private MenuWrapper mMenu = null; + + ActionModeWrapper(android.view.ActionMode actionMode) { + mActionMode = actionMode; + } + + @Override + public void setTitle(CharSequence title) { + mActionMode.setTitle(title); + } + + @Override + public void setTitle(int resId) { + mActionMode.setTitle(resId); + } + + @Override + public void setSubtitle(CharSequence subtitle) { + mActionMode.setSubtitle(subtitle); + } + + @Override + public void setSubtitle(int resId) { + mActionMode.setSubtitle(resId); + } + + @Override + public void setCustomView(View view) { + mActionMode.setCustomView(view); + } + + @Override + public void invalidate() { + mActionMode.invalidate(); + } + + @Override + public void finish() { + mActionMode.finish(); + } + + @Override + public MenuWrapper getMenu() { + if (mMenu == null) { + mMenu = new MenuWrapper(mActionMode.getMenu()); + } + return mMenu; + } + + @Override + public CharSequence getTitle() { + return mActionMode.getTitle(); + } + + @Override + public CharSequence getSubtitle() { + return mActionMode.getSubtitle(); + } + + @Override + public View getCustomView() { + return mActionMode.getCustomView(); + } + + @Override + public MenuInflater getMenuInflater() { + return ActionBarSherlockNative.this.getMenuInflater(); + } + + @Override + public void setTag(Object tag) { + mActionMode.setTag(tag); + } + + @Override + public Object getTag() { + return mActionMode.getTag(); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ResourcesCompat.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ResourcesCompat.java new file mode 100644 index 00000000..8e1efe8c --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/ResourcesCompat.java @@ -0,0 +1,95 @@ +package com.actionbarsherlock.internal; + +import android.content.Context; +import android.os.Build; +import android.util.DisplayMetrics; +import com.actionbarsherlock.R; + +public final class ResourcesCompat { + //No instances + private ResourcesCompat() {} + + + /** + * Support implementation of {@code getResources().getBoolean()} that we + * can use to simulate filtering based on width and smallest width + * qualifiers on pre-3.2. + * + * @param context Context to load booleans from on 3.2+ and to fetch the + * display metrics. + * @param id Id of boolean to load. + * @return Associated boolean value as reflected by the current display + * metrics. + */ + public static boolean getResources_getBoolean(Context context, int id) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { + return context.getResources().getBoolean(id); + } + + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + float widthDp = metrics.widthPixels / metrics.density; + float heightDp = metrics.heightPixels / metrics.density; + float smallestWidthDp = (widthDp < heightDp) ? widthDp : heightDp; + + if (id == R.bool.abs__action_bar_embed_tabs) { + if (widthDp >= 480) { + return true; //values-w480dp + } + return false; //values + } + if (id == R.bool.abs__split_action_bar_is_narrow) { + if (widthDp >= 480) { + return false; //values-w480dp + } + return true; //values + } + if (id == R.bool.abs__action_bar_expanded_action_views_exclusive) { + if (smallestWidthDp >= 600) { + return false; //values-sw600dp + } + return true; //values + } + if (id == R.bool.abs__config_allowActionMenuItemTextWithIcon) { + if (widthDp >= 480) { + return true; //values-w480dp + } + return false; //values + } + + throw new IllegalArgumentException("Unknown boolean resource ID " + id); + } + + /** + * Support implementation of {@code getResources().getInteger()} that we + * can use to simulate filtering based on width qualifiers on pre-3.2. + * + * @param context Context to load integers from on 3.2+ and to fetch the + * display metrics. + * @param id Id of integer to load. + * @return Associated integer value as reflected by the current display + * metrics. + */ + public static int getResources_getInteger(Context context, int id) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { + return context.getResources().getInteger(id); + } + + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + float widthDp = metrics.widthPixels / metrics.density; + + if (id == R.integer.abs__max_action_buttons) { + if (widthDp >= 600) { + return 5; //values-w600dp + } + if (widthDp >= 500) { + return 4; //values-w500dp + } + if (widthDp >= 360) { + return 3; //values-w360dp + } + return 2; //values + } + + throw new IllegalArgumentException("Unknown integer resource ID " + id); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/app/ActionBarImpl.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/app/ActionBarImpl.java index 7cc6c8d2..d022a246 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/app/ActionBarImpl.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/app/ActionBarImpl.java @@ -1,6 +1,5 @@ /* - * Copyright (C) 2011 Jake Wharton - * Copyright (C) 2010 Johan Nilsson + * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,406 +16,1011 @@ package com.actionbarsherlock.internal.app; +import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.List; import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.drawable.Drawable; -import android.support.v4.app.ActionBar; -import android.support.v4.app.SupportActivity; -import android.support.v4.view.ActionMode; -import android.support.v4.view.MenuItem; +import android.os.Build; +import android.os.Handler; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; +import android.util.TypedValue; +import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; +import android.view.Window; +import android.view.accessibility.AccessibilityEvent; import android.widget.SpinnerAdapter; import com.actionbarsherlock.R; -import com.actionbarsherlock.internal.view.menu.ActionMenuItemView; +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.internal.nineoldandroids.animation.Animator; +import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorListenerAdapter; +import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet; +import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator; +import com.actionbarsherlock.internal.nineoldandroids.animation.Animator.AnimatorListener; +import com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout; import com.actionbarsherlock.internal.view.menu.MenuBuilder; -import com.actionbarsherlock.internal.view.menu.MenuItemImpl; +import com.actionbarsherlock.internal.view.menu.MenuPopupHelper; +import com.actionbarsherlock.internal.view.menu.SubMenuBuilder; import com.actionbarsherlock.internal.widget.ActionBarContainer; +import com.actionbarsherlock.internal.widget.ActionBarContextView; import com.actionbarsherlock.internal.widget.ActionBarView; +import com.actionbarsherlock.internal.widget.ScrollingTabContainerView; +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; +import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean; + +/** + * ActionBarImpl is the ActionBar implementation used + * by devices of all screen sizes. If it detects a compatible decor, + * it will split contextual modes across both the ActionBarView at + * the top of the screen and a horizontal LinearLayout at the bottom + * which is normally hidden. + */ +public class ActionBarImpl extends ActionBar { + //UNUSED private static final String TAG = "ActionBarImpl"; -public final class ActionBarImpl extends ActionBar { - /** Action bar container. */ - private ActionBarContainer mContainerView; + private Context mContext; + private Context mThemedContext; + private Activity mActivity; + //UNUSED private Dialog mDialog; - /** Action bar view. */ + private ActionBarContainer mContainerView; private ActionBarView mActionView; + private ActionBarContextView mContextView; + private ActionBarContainer mSplitView; + private NineFrameLayout mContentView; + private ScrollingTabContainerView mTabScrollView; - /** List of listeners to the menu visibility. */ - private final List mMenuListeners = new ArrayList(); + private ArrayList mTabs = new ArrayList(); + private TabImpl mSelectedTab; + private int mSavedTabPosition = INVALID_POSITION; + ActionModeImpl mActionMode; + ActionMode mDeferredDestroyActionMode; + ActionMode.Callback mDeferredModeDestroyCallback; - public ActionBarImpl(T activity) { - super(activity); - } + private boolean mLastMenuVisibility; + private ArrayList mMenuVisibilityListeners = + new ArrayList(); + private static final int CONTEXT_DISPLAY_NORMAL = 0; + private static final int CONTEXT_DISPLAY_SPLIT = 1; - // ------------------------------------------------------------------------ - // ACTION BAR SHERLOCK SUPPORT - // ------------------------------------------------------------------------ + private static final int INVALID_POSITION = -1; - @Override - protected ActionBar getPublicInstance() { - return this; - } + private int mContextDisplayMode; + private boolean mHasEmbeddedTabs; - public void init() { - mActionView = (ActionBarView)mActivity.findViewById(R.id.abs__action_bar); - mContainerView = (ActionBarContainer)mActivity.findViewById(R.id.abs__action_bar_container); + final Handler mHandler = new Handler(); + Runnable mTabSelector; - if (mActionView == null) { - throw new IllegalStateException(getClass().getSimpleName() + " can only be used with a screen_*.xml layout"); + private Animator mCurrentShowAnim; + private Animator mCurrentModeAnim; + private boolean mShowHideAnimationEnabled; + boolean mWasHiddenBeforeMode; + + final AnimatorListener mHideListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (mContentView != null) { + mContentView.setTranslationY(0); + mContainerView.setTranslationY(0); + } + if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { + mSplitView.setVisibility(View.GONE); + } + mContainerView.setVisibility(View.GONE); + mContainerView.setTransitioning(false); + mCurrentShowAnim = null; + completeDeferredDestroyActionMode(); } + }; - if (mActionView.getTitle() == null) { - mActionView.setTitle(mActivity.getTitle()); + final AnimatorListener mShowListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mCurrentShowAnim = null; + mContainerView.requestLayout(); + } + }; + + public ActionBarImpl(Activity activity, int features) { + mActivity = activity; + Window window = activity.getWindow(); + View decor = window.getDecorView(); + init(decor); + + //window.hasFeature() workaround for pre-3.0 + if ((features & (1 << Window.FEATURE_ACTION_BAR_OVERLAY)) == 0) { + mContentView = (NineFrameLayout)decor.findViewById(android.R.id.content); } } - public void onMenuInflated(MenuBuilder menu) { - if (mActionView == null) { - return; + public ActionBarImpl(Dialog dialog) { + //UNUSED mDialog = dialog; + init(dialog.getWindow().getDecorView()); + } + + private void init(View decor) { + mContext = decor.getContext(); + mActionView = (ActionBarView) decor.findViewById(R.id.abs__action_bar); + mContextView = (ActionBarContextView) decor.findViewById( + R.id.abs__action_context_bar); + mContainerView = (ActionBarContainer) decor.findViewById( + R.id.abs__action_bar_container); + mSplitView = (ActionBarContainer) decor.findViewById( + R.id.abs__split_action_bar); + + if (mActionView == null || mContextView == null || mContainerView == null) { + throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + + "with a compatible window decor layout"); } - final int maxItems = mActivity.getResources().getInteger(R.integer.abs__max_action_buttons); + mActionView.setContextView(mContextView); + mContextDisplayMode = mActionView.isSplitActionBar() ? + CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL; - //Iterate and grab as many actions as we can up to maxItems honoring - //their showAsAction values - int ifItems = 0; - final int count = menu.size(); - boolean showsActionItemText = menu.getShowsActionItemText(); - List keep = new ArrayList(); - for (int i = 0; i < count; i++) { - MenuItemImpl item = (MenuItemImpl)menu.getItem(i); + // Older apps get the home button interaction enabled by default. + // Newer apps need to enable it explicitly. + setHomeButtonEnabled(mContext.getApplicationInfo().targetSdkVersion < 14); - //Items without an icon or custom view are forced into the overflow menu - if (!showsActionItemText && (item.getIcon() == null) && (item.getActionView() == null)) { - continue; - } - if (showsActionItemText && ((item.getTitle() == null) || "".equals(item.getTitle()))) { - continue; - } + setHasEmbeddedTabs(getResources_getBoolean(mContext, + R.bool.abs__action_bar_embed_tabs)); + } - if ((item.getShowAsAction() & MenuItem.SHOW_AS_ACTION_ALWAYS) != 0) { - //Show always therefore add to keep list - keep.add(item); - - if ((keep.size() > maxItems) && (ifItems > 0)) { - //If we have exceeded the max and there are "ifRoom" items - //then iterate backwards to remove one and add it to the - //head of the classic items list. - for (int j = keep.size() - 1; j >= 0; j--) { - if ((keep.get(j).getShowAsAction() & MenuItem.SHOW_AS_ACTION_IF_ROOM) != 0) { - keep.remove(j); - ifItems -= 1; - break; - } - } - } - } else if (((item.getShowAsAction() & MenuItem.SHOW_AS_ACTION_IF_ROOM) != 0) - && (keep.size() < maxItems)) { - //"ifRoom" items are added if we have not exceeded the max. - keep.add(item); - ifItems += 1; + public void onConfigurationChanged(Configuration newConfig) { + setHasEmbeddedTabs(getResources_getBoolean(mContext, + R.bool.abs__action_bar_embed_tabs)); + + //Manually dispatch a configuration change to the action bar view on pre-2.2 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { + mActionView.onConfigurationChanged(newConfig); + if (mContextView != null) { + mContextView.onConfigurationChanged(newConfig); } } + } - //Mark items that will be shown on the action bar as such so they do - //not show up on the activity options menu - mActionView.removeAllItems(); - for (MenuItemImpl item : keep) { - item.setIsShownOnActionBar(true); + private void setHasEmbeddedTabs(boolean hasEmbeddedTabs) { + mHasEmbeddedTabs = hasEmbeddedTabs; + // Switch tab layout configuration if needed + if (!mHasEmbeddedTabs) { + mActionView.setEmbeddedTabView(null); + mContainerView.setTabContainer(mTabScrollView); + } else { + mContainerView.setTabContainer(null); + mActionView.setEmbeddedTabView(mTabScrollView); + } + final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS; + if (mTabScrollView != null) { + mTabScrollView.setVisibility(isInTabMode ? View.VISIBLE : View.GONE); + } + mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode); + } - //Get a new item for this menu item - ActionMenuItemView actionItem = mActionView.newItem(); - actionItem.initialize(item, MenuBuilder.TYPE_ACTION_BAR); + private void ensureTabsExist() { + if (mTabScrollView != null) { + return; + } - //Associate the itemview with the item so changes will be reflected - item.setItemView(MenuBuilder.TYPE_ACTION_BAR, actionItem); + ScrollingTabContainerView tabScroller = new ScrollingTabContainerView(mContext); - //Add to the action bar for display - mActionView.addItem(actionItem); + if (mHasEmbeddedTabs) { + tabScroller.setVisibility(View.VISIBLE); + mActionView.setEmbeddedTabView(tabScroller); + } else { + tabScroller.setVisibility(getNavigationMode() == NAVIGATION_MODE_TABS ? + View.VISIBLE : View.GONE); + mContainerView.setTabContainer(tabScroller); } + mTabScrollView = tabScroller; } - public void onMenuVisibilityChanged(boolean isVisible) { - //Marshal to all listeners - for (OnMenuVisibilityListener listener : mMenuListeners) { - listener.onMenuVisibilityChanged(isVisible); + void completeDeferredDestroyActionMode() { + if (mDeferredModeDestroyCallback != null) { + mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode); + mDeferredDestroyActionMode = null; + mDeferredModeDestroyCallback = null; } } - public void setProgressBarIndeterminateVisibility(boolean visible) { - if (mActionView != null) { - mActionView.setProgressBarIndeterminateVisibility(visible); + /** + * Enables or disables animation between show/hide states. + * If animation is disabled using this method, animations in progress + * will be finished. + * + * @param enabled true to animate, false to not animate. + */ + public void setShowHideAnimationEnabled(boolean enabled) { + mShowHideAnimationEnabled = enabled; + if (!enabled && mCurrentShowAnim != null) { + mCurrentShowAnim.end(); } } - // ------------------------------------------------------------------------ - // ACTION MODE METHODS - // ------------------------------------------------------------------------ + public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) { + mMenuVisibilityListeners.add(listener); + } - @Override - protected ActionMode startActionMode(ActionMode.Callback callback) { - throw new RuntimeException("Not implemented."); + public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) { + mMenuVisibilityListeners.remove(listener); } - // ------------------------------------------------------------------------ - // ACTION BAR METHODS - // ------------------------------------------------------------------------ + public void dispatchMenuVisibilityChanged(boolean isVisible) { + if (isVisible == mLastMenuVisibility) { + return; + } + mLastMenuVisibility = isVisible; - @Override - public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) { - if (!mMenuListeners.contains(listener)) { - mMenuListeners.add(listener); + final int count = mMenuVisibilityListeners.size(); + for (int i = 0; i < count; i++) { + mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible); } } @Override - public void addTab(Tab tab) { - mActionView.addTab(tab); + public void setCustomView(int resId) { + setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId, mActionView, false)); } @Override - public void addTab(Tab tab, boolean setSelected) { - mActionView.addTab(tab, setSelected); + public void setDisplayUseLogoEnabled(boolean useLogo) { + setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO); } @Override - public void addTab(Tab tab, int position) { - mActionView.addTab(tab, position); + public void setDisplayShowHomeEnabled(boolean showHome) { + setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME); } @Override - public void addTab(ActionBar.Tab tab, int position, boolean setSelected) { - mActionView.addTab(tab, position, setSelected); + public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) { + setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP); } @Override - public View getCustomView() { - return mActionView.getCustomView(); + public void setDisplayShowTitleEnabled(boolean showTitle) { + setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE); } @Override - public int getDisplayOptions() { - return mActionView.getDisplayOptions(); + public void setDisplayShowCustomEnabled(boolean showCustom) { + setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM); } @Override - public int getHeight() { - return mActionView.getHeight(); + public void setHomeButtonEnabled(boolean enable) { + mActionView.setHomeButtonEnabled(enable); } @Override - public int getNavigationItemCount() { + public void setTitle(int resId) { + setTitle(mContext.getString(resId)); + } + + @Override + public void setSubtitle(int resId) { + setSubtitle(mContext.getString(resId)); + } + + public void setSelectedNavigationItem(int position) { switch (mActionView.getNavigationMode()) { - default: - case ActionBar.NAVIGATION_MODE_STANDARD: - return 0; + case NAVIGATION_MODE_TABS: + selectTab(mTabs.get(position)); + break; + case NAVIGATION_MODE_LIST: + mActionView.setDropdownSelectedPosition(position); + break; + default: + throw new IllegalStateException( + "setSelectedNavigationIndex not valid for current navigation mode"); + } + } - case ActionBar.NAVIGATION_MODE_LIST: - SpinnerAdapter dropdownAdapter = mActionView.getDropdownAdapter(); - return (dropdownAdapter != null) ? dropdownAdapter.getCount() : 0; + public void removeAllTabs() { + cleanupTabs(); + } - case ActionBar.NAVIGATION_MODE_TABS: - return mActionView.getTabCount(); + private void cleanupTabs() { + if (mSelectedTab != null) { + selectTab(null); } + mTabs.clear(); + if (mTabScrollView != null) { + mTabScrollView.removeAllTabs(); + } + mSavedTabPosition = INVALID_POSITION; } - @Override - public int getNavigationMode() { - return mActionView.getNavigationMode(); + public void setTitle(CharSequence title) { + mActionView.setTitle(title); } - @Override - public int getSelectedNavigationIndex() { - switch (mActionView.getNavigationMode()) { - default: - case ActionBar.NAVIGATION_MODE_STANDARD: - return -1; + public void setSubtitle(CharSequence subtitle) { + mActionView.setSubtitle(subtitle); + } - case ActionBar.NAVIGATION_MODE_LIST: - return mActionView.getDropdownSelectedPosition(); + public void setDisplayOptions(int options) { + mActionView.setDisplayOptions(options); + } + + public void setDisplayOptions(int options, int mask) { + final int current = mActionView.getDisplayOptions(); + mActionView.setDisplayOptions((options & mask) | (current & ~mask)); + } + + public void setBackgroundDrawable(Drawable d) { + mContainerView.setPrimaryBackground(d); + } - case ActionBar.NAVIGATION_MODE_TABS: - return mActionView.getSelectedTab().getPosition(); + public void setStackedBackgroundDrawable(Drawable d) { + mContainerView.setStackedBackground(d); + } + + public void setSplitBackgroundDrawable(Drawable d) { + if (mSplitView != null) { + mSplitView.setSplitBackground(d); } } - @Override - public ActionBar.Tab getSelectedTab() { - return mActionView.getSelectedTab(); + public View getCustomView() { + return mActionView.getCustomNavigationView(); + } + + public CharSequence getTitle() { + return mActionView.getTitle(); } - @Override public CharSequence getSubtitle() { return mActionView.getSubtitle(); } - @Override - public ActionBar.Tab getTabAt(int index) { - return mActionView.getTabAt(index); + public int getNavigationMode() { + return mActionView.getNavigationMode(); } - @Override - public int getTabCount() { - return mActionView.getTabCount(); + public int getDisplayOptions() { + return mActionView.getDisplayOptions(); } - @Override - public CharSequence getTitle() { - return mActionView.getTitle(); + public ActionMode startActionMode(ActionMode.Callback callback) { + boolean wasHidden = false; + if (mActionMode != null) { + wasHidden = mWasHiddenBeforeMode; + mActionMode.finish(); + } + + mContextView.killMode(); + ActionModeImpl mode = new ActionModeImpl(callback); + if (mode.dispatchOnCreate()) { + mWasHiddenBeforeMode = !isShowing() || wasHidden; + mode.invalidate(); + mContextView.initForMode(mode); + animateToMode(true); + if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { + // TODO animate this + mSplitView.setVisibility(View.VISIBLE); + } + mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + mActionMode = mode; + return mode; + } + return null; + } + + private void configureTab(Tab tab, int position) { + final TabImpl tabi = (TabImpl) tab; + final ActionBar.TabListener callback = tabi.getCallback(); + + if (callback == null) { + throw new IllegalStateException("Action Bar Tab must have a Callback"); + } + + tabi.setPosition(position); + mTabs.add(position, tabi); + + final int count = mTabs.size(); + for (int i = position + 1; i < count; i++) { + mTabs.get(i).setPosition(i); + } } @Override - public void hide() { - //TODO: animate - mContainerView.setVisibility(View.GONE); + public void addTab(Tab tab) { + addTab(tab, mTabs.isEmpty()); } @Override - public boolean isShowing() { - return mContainerView.getVisibility() == View.VISIBLE; + public void addTab(Tab tab, int position) { + addTab(tab, position, mTabs.isEmpty()); } @Override - public ActionBar.Tab newTab() { - return mActionView.newTab(); + public void addTab(Tab tab, boolean setSelected) { + ensureTabsExist(); + mTabScrollView.addTab(tab, setSelected); + configureTab(tab, mTabs.size()); + if (setSelected) { + selectTab(tab); + } } @Override - public void removeAllTabs() { - mActionView.removeAllTabs(); + public void addTab(Tab tab, int position, boolean setSelected) { + ensureTabsExist(); + mTabScrollView.addTab(tab, position, setSelected); + configureTab(tab, position); + if (setSelected) { + selectTab(tab); + } } @Override - public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) { - mMenuListeners.remove(listener); + public Tab newTab() { + return new TabImpl(); } @Override - public void removeTab(ActionBar.Tab tab) { + public void removeTab(Tab tab) { removeTabAt(tab.getPosition()); } @Override public void removeTabAt(int position) { - mActionView.removeTabAt(position); + if (mTabScrollView == null) { + // No tabs around to remove + return; + } + + int selectedTabPosition = mSelectedTab != null + ? mSelectedTab.getPosition() : mSavedTabPosition; + mTabScrollView.removeTabAt(position); + TabImpl removedTab = mTabs.remove(position); + if (removedTab != null) { + removedTab.setPosition(-1); + } + + final int newTabCount = mTabs.size(); + for (int i = position; i < newTabCount; i++) { + mTabs.get(i).setPosition(i); + } + + if (selectedTabPosition == position) { + selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1))); + } } @Override - public void setBackgroundDrawable(Drawable d) { - mContainerView.setBackgroundDrawable(d); + public void selectTab(Tab tab) { + if (getNavigationMode() != NAVIGATION_MODE_TABS) { + mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION; + return; + } + + FragmentTransaction trans = null; + if (mActivity instanceof FragmentActivity) { + trans = ((FragmentActivity)mActivity).getSupportFragmentManager().beginTransaction() + .disallowAddToBackStack(); + } + + if (mSelectedTab == tab) { + if (mSelectedTab != null) { + mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans); + mTabScrollView.animateToTab(tab.getPosition()); + } + } else { + mTabScrollView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION); + if (mSelectedTab != null) { + mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans); + } + mSelectedTab = (TabImpl) tab; + if (mSelectedTab != null) { + mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans); + } + } + + if (trans != null && !trans.isEmpty()) { + trans.commit(); + } } @Override - public void setCustomView(int resId) { - View view = LayoutInflater.from(mContext).inflate(resId, mActionView, false); - setCustomView(view); + public Tab getSelectedTab() { + return mSelectedTab; } @Override - public void setCustomView(View view) { - mActionView.setCustomNavigationView(view); + public int getHeight() { + return mContainerView.getHeight(); } @Override - public void setCustomView(View view, ActionBar.LayoutParams layoutParams) { - view.setLayoutParams(layoutParams); - mActionView.setCustomNavigationView(view); + public void show() { + show(true); } - @Override - public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) { - setDisplayOptions(showHomeAsUp ? ActionBar.DISPLAY_HOME_AS_UP : 0, ActionBar.DISPLAY_HOME_AS_UP); + void show(boolean markHiddenBeforeMode) { + if (mCurrentShowAnim != null) { + mCurrentShowAnim.end(); + } + if (mContainerView.getVisibility() == View.VISIBLE) { + if (markHiddenBeforeMode) mWasHiddenBeforeMode = false; + return; + } + mContainerView.setVisibility(View.VISIBLE); + + if (mShowHideAnimationEnabled) { + mContainerView.setAlpha(0); + AnimatorSet anim = new AnimatorSet(); + AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1)); + if (mContentView != null) { + b.with(ObjectAnimator.ofFloat(mContentView, "translationY", + -mContainerView.getHeight(), 0)); + mContainerView.setTranslationY(-mContainerView.getHeight()); + b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0)); + } + if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) { + mSplitView.setAlpha(0); + mSplitView.setVisibility(View.VISIBLE); + b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1)); + } + anim.addListener(mShowListener); + mCurrentShowAnim = anim; + anim.start(); + } else { + mContainerView.setAlpha(1); + mContainerView.setTranslationY(0); + mShowListener.onAnimationEnd(null); + } } @Override - public void setDisplayOptions(int options) { - mActionView.setDisplayOptions(options); + public void hide() { + if (mCurrentShowAnim != null) { + mCurrentShowAnim.end(); + } + if (mContainerView.getVisibility() == View.GONE) { + return; + } + + if (mShowHideAnimationEnabled) { + mContainerView.setAlpha(1); + mContainerView.setTransitioning(true); + AnimatorSet anim = new AnimatorSet(); + AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0)); + if (mContentView != null) { + b.with(ObjectAnimator.ofFloat(mContentView, "translationY", + 0, -mContainerView.getHeight())); + b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", + -mContainerView.getHeight())); + } + if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) { + mSplitView.setAlpha(1); + b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0)); + } + anim.addListener(mHideListener); + mCurrentShowAnim = anim; + anim.start(); + } else { + mHideListener.onAnimationEnd(null); + } } - @Override - public void setDisplayOptions(int newOptions, int mask) { - mActionView.setDisplayOptions((mActionView.getDisplayOptions() & ~mask) | newOptions); + public boolean isShowing() { + return mContainerView.getVisibility() == View.VISIBLE; } - @Override - public void setDisplayShowCustomEnabled(boolean showCustom) { - setDisplayOptions(showCustom ? ActionBar.DISPLAY_SHOW_CUSTOM : 0, ActionBar.DISPLAY_SHOW_CUSTOM); + void animateToMode(boolean toActionMode) { + if (toActionMode) { + show(false); + } + if (mCurrentModeAnim != null) { + mCurrentModeAnim.end(); + } + + mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE); + mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE); + if (mTabScrollView != null && !mActionView.hasEmbeddedTabs() && mActionView.isCollapsed()) { + mTabScrollView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE); + } } - @Override - public void setDisplayShowHomeEnabled(boolean showHome) { - setDisplayOptions(showHome ? ActionBar.DISPLAY_SHOW_HOME : 0, ActionBar.DISPLAY_SHOW_HOME); + public Context getThemedContext() { + if (mThemedContext == null) { + TypedValue outValue = new TypedValue(); + Resources.Theme currentTheme = mContext.getTheme(); + currentTheme.resolveAttribute(R.attr.actionBarWidgetTheme, + outValue, true); + final int targetThemeRes = outValue.resourceId; + + if (targetThemeRes != 0) { //XXX && mContext.getThemeResId() != targetThemeRes) { + mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes); + } else { + mThemedContext = mContext; + } + } + return mThemedContext; + } + + /** + * @hide + */ + public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback { + private ActionMode.Callback mCallback; + private MenuBuilder mMenu; + private WeakReference mCustomView; + + public ActionModeImpl(ActionMode.Callback callback) { + mCallback = callback; + mMenu = new MenuBuilder(getThemedContext()) + .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + mMenu.setCallback(this); + } + + @Override + public MenuInflater getMenuInflater() { + return new MenuInflater(getThemedContext()); + } + + @Override + public Menu getMenu() { + return mMenu; + } + + @Override + public void finish() { + if (mActionMode != this) { + // Not the active action mode - no-op + return; + } + + // If we were hidden before the mode was shown, defer the onDestroy + // callback until the animation is finished and associated relayout + // is about to happen. This lets apps better anticipate visibility + // and layout behavior. + if (mWasHiddenBeforeMode) { + mDeferredDestroyActionMode = this; + mDeferredModeDestroyCallback = mCallback; + } else { + mCallback.onDestroyActionMode(this); + } + mCallback = null; + animateToMode(false); + + // Clear out the context mode views after the animation finishes + mContextView.closeMode(); + mActionView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + + mActionMode = null; + + if (mWasHiddenBeforeMode) { + hide(); + } + } + + @Override + public void invalidate() { + mMenu.stopDispatchingItemsChanged(); + try { + mCallback.onPrepareActionMode(this, mMenu); + } finally { + mMenu.startDispatchingItemsChanged(); + } + } + + public boolean dispatchOnCreate() { + mMenu.stopDispatchingItemsChanged(); + try { + return mCallback.onCreateActionMode(this, mMenu); + } finally { + mMenu.startDispatchingItemsChanged(); + } + } + + @Override + public void setCustomView(View view) { + mContextView.setCustomView(view); + mCustomView = new WeakReference(view); + } + + @Override + public void setSubtitle(CharSequence subtitle) { + mContextView.setSubtitle(subtitle); + } + + @Override + public void setTitle(CharSequence title) { + mContextView.setTitle(title); + } + + @Override + public void setTitle(int resId) { + setTitle(mContext.getResources().getString(resId)); + } + + @Override + public void setSubtitle(int resId) { + setSubtitle(mContext.getResources().getString(resId)); + } + + @Override + public CharSequence getTitle() { + return mContextView.getTitle(); + } + + @Override + public CharSequence getSubtitle() { + return mContextView.getSubtitle(); + } + + @Override + public View getCustomView() { + return mCustomView != null ? mCustomView.get() : null; + } + + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { + if (mCallback != null) { + return mCallback.onActionItemClicked(this, item); + } else { + return false; + } + } + + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + } + + public boolean onSubMenuSelected(SubMenuBuilder subMenu) { + if (mCallback == null) { + return false; + } + + if (!subMenu.hasVisibleItems()) { + return true; + } + + new MenuPopupHelper(getThemedContext(), subMenu).show(); + return true; + } + + public void onCloseSubMenu(SubMenuBuilder menu) { + } + + public void onMenuModeChange(MenuBuilder menu) { + if (mCallback == null) { + return; + } + invalidate(); + mContextView.showOverflowMenu(); + } + } + + /** + * @hide + */ + public class TabImpl extends ActionBar.Tab { + private ActionBar.TabListener mCallback; + private Object mTag; + private Drawable mIcon; + private CharSequence mText; + private CharSequence mContentDesc; + private int mPosition = -1; + private View mCustomView; + + @Override + public Object getTag() { + return mTag; + } + + @Override + public Tab setTag(Object tag) { + mTag = tag; + return this; + } + + public ActionBar.TabListener getCallback() { + return mCallback; + } + + @Override + public Tab setTabListener(ActionBar.TabListener callback) { + mCallback = callback; + return this; + } + + @Override + public View getCustomView() { + return mCustomView; + } + + @Override + public Tab setCustomView(View view) { + mCustomView = view; + if (mPosition >= 0) { + mTabScrollView.updateTab(mPosition); + } + return this; + } + + @Override + public Tab setCustomView(int layoutResId) { + return setCustomView(LayoutInflater.from(getThemedContext()) + .inflate(layoutResId, null)); + } + + @Override + public Drawable getIcon() { + return mIcon; + } + + @Override + public int getPosition() { + return mPosition; + } + + public void setPosition(int position) { + mPosition = position; + } + + @Override + public CharSequence getText() { + return mText; + } + + @Override + public Tab setIcon(Drawable icon) { + mIcon = icon; + if (mPosition >= 0) { + mTabScrollView.updateTab(mPosition); + } + return this; + } + + @Override + public Tab setIcon(int resId) { + return setIcon(mContext.getResources().getDrawable(resId)); + } + + @Override + public Tab setText(CharSequence text) { + mText = text; + if (mPosition >= 0) { + mTabScrollView.updateTab(mPosition); + } + return this; + } + + @Override + public Tab setText(int resId) { + return setText(mContext.getResources().getText(resId)); + } + + @Override + public void select() { + selectTab(this); + } + + @Override + public Tab setContentDescription(int resId) { + return setContentDescription(mContext.getResources().getText(resId)); + } + + @Override + public Tab setContentDescription(CharSequence contentDesc) { + mContentDesc = contentDesc; + if (mPosition >= 0) { + mTabScrollView.updateTab(mPosition); + } + return this; + } + + @Override + public CharSequence getContentDescription() { + return mContentDesc; + } } @Override - public void setDisplayShowTitleEnabled(boolean showTitle) { - setDisplayOptions(showTitle ? ActionBar.DISPLAY_SHOW_TITLE : 0, ActionBar.DISPLAY_SHOW_TITLE); + public void setCustomView(View view) { + mActionView.setCustomNavigationView(view); } @Override - public void setDisplayUseLogoEnabled(boolean useLogo) { - setDisplayOptions(useLogo ? ActionBar.DISPLAY_USE_LOGO : 0, ActionBar.DISPLAY_USE_LOGO); + public void setCustomView(View view, LayoutParams layoutParams) { + view.setLayoutParams(layoutParams); + mActionView.setCustomNavigationView(view); } @Override - public void setListNavigationCallbacks(SpinnerAdapter adapter, ActionBar.OnNavigationListener callback) { + public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) { mActionView.setDropdownAdapter(adapter); mActionView.setCallback(callback); } @Override - public void setNavigationMode(int mode) { - mActionView.setNavigationMode(mode); + public int getSelectedNavigationIndex() { + switch (mActionView.getNavigationMode()) { + case NAVIGATION_MODE_TABS: + return mSelectedTab != null ? mSelectedTab.getPosition() : -1; + case NAVIGATION_MODE_LIST: + return mActionView.getDropdownSelectedPosition(); + default: + return -1; + } } @Override - public void setSelectedNavigationItem(int position) { + public int getNavigationItemCount() { switch (mActionView.getNavigationMode()) { + case NAVIGATION_MODE_TABS: + return mTabs.size(); + case NAVIGATION_MODE_LIST: + SpinnerAdapter adapter = mActionView.getDropdownAdapter(); + return adapter != null ? adapter.getCount() : 0; default: - case ActionBar.NAVIGATION_MODE_STANDARD: - throw new IllegalStateException(); + return 0; + } + } - case ActionBar.NAVIGATION_MODE_TABS: - mActionView.getTabAt(position).select(); - break; + @Override + public int getTabCount() { + return mTabs.size(); + } - case ActionBar.NAVIGATION_MODE_LIST: - mActionView.setDropdownSelectedPosition(position); + @Override + public void setNavigationMode(int mode) { + final int oldMode = mActionView.getNavigationMode(); + switch (oldMode) { + case NAVIGATION_MODE_TABS: + mSavedTabPosition = getSelectedNavigationIndex(); + selectTab(null); + mTabScrollView.setVisibility(View.GONE); break; } + mActionView.setNavigationMode(mode); + switch (mode) { + case NAVIGATION_MODE_TABS: + ensureTabsExist(); + mTabScrollView.setVisibility(View.VISIBLE); + if (mSavedTabPosition != INVALID_POSITION) { + setSelectedNavigationItem(mSavedTabPosition); + mSavedTabPosition = INVALID_POSITION; + } + break; + } + mActionView.setCollapsable(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs); } @Override - public void selectTab(ActionBar.Tab tab) { - mActionView.selectTab(tab); + public Tab getTabAt(int index) { + return mTabs.get(index); } - @Override - public void setSubtitle(CharSequence subtitle) { - mActionView.setSubtitle(subtitle); - } @Override - public void setSubtitle(int resId) { - mActionView.setSubtitle(resId); + public void setIcon(int resId) { + mActionView.setIcon(resId); } @Override - public void setTitle(CharSequence title) { - mActionView.setTitle(title); + public void setIcon(Drawable icon) { + mActionView.setIcon(icon); } + @Override - public void setTitle(int resId) { - mActionView.setTitle(resId); + public void setLogo(int resId) { + mActionView.setLogo(resId); } @Override - public void show() { - //TODO: animate - mContainerView.setVisibility(View.VISIBLE); + public void setLogo(Drawable logo) { + mActionView.setLogo(logo); } } diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java index 75d58286..840cb3d2 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java @@ -1,581 +1,468 @@ -/* - * Copyright 2011 Jake Wharton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package com.actionbarsherlock.internal.app; -import java.util.HashMap; -import com.actionbarsherlock.internal.view.menu.MenuItemWrapper; -import com.actionbarsherlock.internal.view.menu.MenuWrapper; +import java.util.HashSet; +import java.util.Set; + import android.app.Activity; import android.content.Context; import android.graphics.drawable.Drawable; -import android.support.v4.app.ActionBar; -import android.support.v4.app.SupportActivity; -import android.support.v4.view.ActionMode; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuInflater; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentTransaction; import android.view.View; import android.widget.SpinnerAdapter; -public final class ActionBarWrapper { - //No instances - private ActionBarWrapper() {} - - /** - * Abstraction to get an instance of our implementing class. - * - * @param activity Parent activity. - * @return {@code ActionBar} instance. - */ - public static ActionBar createFor(T activity) { - return new ActionBarWrapper.Impl(activity); - } - - /** - *

Handler for Android's native {@link android.app.ActionBar}.

- */ - public static final class Impl extends ActionBar implements android.app.ActionBar.TabListener { - /** Mapping between support listeners and native listeners. */ - private final HashMap mMenuListenerMap = new HashMap(); - - - private Impl(T activity) { - super(activity); - } - - - /** - * Get the native {@link ActionBar} instance. - * - * @return The action bar. - */ - private android.app.ActionBar getActionBar() { - return mActivity.asActivity().getActionBar(); - } - - @Override - protected ActionBar getPublicInstance() { - return (getActionBar() != null) ? this : null; - } +import com.actionbarsherlock.app.ActionBar; - /** - * Converts our Tab wrapper to a native version containing the wrapper - * instance as its tag. - * - * @param tab Tab wrapper instance. - * @return Native tab. - */ - private android.app.ActionBar.Tab convertTabToNative(ActionBar.Tab tab) { - return getActionBar().newTab() - .setCustomView(tab.getCustomView()) - .setIcon(tab.getIcon()) - .setTabListener(this) - .setTag(tab) - .setText(tab.getText()); - } +public class ActionBarWrapper extends ActionBar implements android.app.ActionBar.OnNavigationListener, android.app.ActionBar.OnMenuVisibilityListener { + private final Activity mActivity; + private final android.app.ActionBar mActionBar; + private ActionBar.OnNavigationListener mNavigationListener; + private Set mMenuVisibilityListeners = new HashSet(1); + private FragmentTransaction mFragmentTransaction; - @Override - public void onTabReselected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) { - ActionBar.TabListener listener = ((ActionBar.Tab)tab.getTag()).getTabListener(); - if (listener != null) { - listener.onTabReselected((ActionBar.Tab)tab.getTag(), null); - } - } - @Override - public void onTabSelected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) { - ActionBar.TabListener listener = ((ActionBar.Tab)tab.getTag()).getTabListener(); - if (listener != null) { - listener.onTabSelected((ActionBar.Tab)tab.getTag(), null); - } + public ActionBarWrapper(Activity activity) { + mActivity = activity; + mActionBar = activity.getActionBar(); + if (mActionBar != null) { + mActionBar.addOnMenuVisibilityListener(this); } + } - @Override - public void onTabUnselected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) { - ActionBar.TabListener listener = ((ActionBar.Tab)tab.getTag()).getTabListener(); - if (listener != null) { - listener.onTabUnselected((ActionBar.Tab)tab.getTag(), null); - } - } - - // --------------------------------------------------------------------- - // ACTION MODE SUPPORT - // --------------------------------------------------------------------- - - @Override - protected ActionMode startActionMode(final ActionMode.Callback callback) { - //We have to re-wrap the instances in every callback since the - //wrapped instance is needed before we could have a change to - //properly store it. - return new ActionModeWrapper(mContext, - mActivity.asActivity().startActionMode(new android.view.ActionMode.Callback() { - @Override - public boolean onPrepareActionMode(android.view.ActionMode mode, android.view.Menu menu) { - return callback.onPrepareActionMode(new ActionModeWrapper(mContext, mode), new MenuWrapper(menu)); - } - - @Override - public void onDestroyActionMode(android.view.ActionMode mode) { - final ActionMode actionMode = new ActionModeWrapper(mContext, mode); - callback.onDestroyActionMode(actionMode); - - //Send the activity callback once the action mode callback has run. - //This type-check has already occurred in the action bar constructor. - ((SupportActivity)mActivity).onActionModeFinished(actionMode); - } - - @Override - public boolean onCreateActionMode(android.view.ActionMode mode, android.view.Menu menu) { - return callback.onCreateActionMode(new ActionModeWrapper(mContext, mode), new MenuWrapper(menu)); - } - @Override - public boolean onActionItemClicked(android.view.ActionMode mode, android.view.MenuItem item) { - return callback.onActionItemClicked(new ActionModeWrapper(mContext, mode), new MenuItemWrapper(item)); - } - }) - ); - } + @Override + public void setHomeButtonEnabled(boolean enabled) { + mActionBar.setHomeButtonEnabled(enabled); + } - private static class ActionModeWrapper extends ActionMode { - private final Context mContext; - private final android.view.ActionMode mActionMode; + @Override + public Context getThemedContext() { + return mActionBar.getThemedContext(); + } - ActionModeWrapper(Context context, android.view.ActionMode actionMode) { - mContext = context; - mActionMode = actionMode; - } + @Override + public void setCustomView(View view) { + mActionBar.setCustomView(view); + } - @Override - public void finish() { - mActionMode.finish(); - } + @Override + public void setCustomView(View view, LayoutParams layoutParams) { + android.app.ActionBar.LayoutParams lp = new android.app.ActionBar.LayoutParams(layoutParams); + lp.gravity = layoutParams.gravity; + lp.bottomMargin = layoutParams.bottomMargin; + lp.topMargin = layoutParams.topMargin; + lp.leftMargin = layoutParams.leftMargin; + lp.rightMargin = layoutParams.rightMargin; + mActionBar.setCustomView(view, lp); + } - @Override - public View getCustomView() { - return mActionMode.getCustomView(); - } + @Override + public void setCustomView(int resId) { + mActionBar.setCustomView(resId); + } - @Override - public Menu getMenu() { - return new MenuWrapper(mActionMode.getMenu()); - } + @Override + public void setIcon(int resId) { + mActionBar.setIcon(resId); + } - @Override - public MenuInflater getMenuInflater() { - return new MenuInflater(mContext, null); - } + @Override + public void setIcon(Drawable icon) { + mActionBar.setIcon(icon); + } - @Override - public CharSequence getSubtitle() { - return mActionMode.getSubtitle(); - } + @Override + public void setLogo(int resId) { + mActionBar.setLogo(resId); + } - @Override - public CharSequence getTitle() { - return mActionMode.getTitle(); - } + @Override + public void setLogo(Drawable logo) { + mActionBar.setLogo(logo); + } - @Override - public void invalidate() { - mActionMode.invalidate(); - } + @Override + public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) { + mNavigationListener = callback; + mActionBar.setListNavigationCallbacks(adapter, (callback != null) ? this : null); + } - @Override - public void setCustomView(View view) { - mActionMode.setCustomView(view); - } + @Override + public boolean onNavigationItemSelected(int itemPosition, long itemId) { + //This should never be a NullPointerException since we only set + //ourselves as the listener when the callback is not null. + return mNavigationListener.onNavigationItemSelected(itemPosition, itemId); + } - @Override - public void setSubtitle(int resId) { - mActionMode.setSubtitle(resId); - } + @Override + public void setSelectedNavigationItem(int position) { + mActionBar.setSelectedNavigationItem(position); + } - @Override - public void setSubtitle(CharSequence subtitle) { - mActionMode.setSubtitle(subtitle); - } + @Override + public int getSelectedNavigationIndex() { + return mActionBar.getSelectedNavigationIndex(); + } - @Override - public void setTitle(int resId) { - mActionMode.setTitle(resId); - } + @Override + public int getNavigationItemCount() { + return mActionBar.getNavigationItemCount(); + } - @Override - public void setTitle(CharSequence title) { - mActionMode.setTitle(title); - } - } + @Override + public void setTitle(CharSequence title) { + mActionBar.setTitle(title); + } - // --------------------------------------------------------------------- - // ACTION BAR SUPPORT - // --------------------------------------------------------------------- + @Override + public void setTitle(int resId) { + mActionBar.setTitle(resId); + } - private static class TabImpl extends ActionBar.Tab { - final ActionBarWrapper.Impl mActionBar; + @Override + public void setSubtitle(CharSequence subtitle) { + mActionBar.setSubtitle(subtitle); + } - View mCustomView; - Drawable mIcon; - ActionBar.TabListener mListener; - Object mTag; - CharSequence mText; + @Override + public void setSubtitle(int resId) { + mActionBar.setSubtitle(resId); + } - TabImpl(ActionBarWrapper.Impl actionBar) { - mActionBar = actionBar; - } + @Override + public void setDisplayOptions(int options) { + mActionBar.setDisplayOptions(options); + } - @Override - public View getCustomView() { - return mCustomView; - } + @Override + public void setDisplayOptions(int options, int mask) { + mActionBar.setDisplayOptions(options, mask); + } - @Override - public Drawable getIcon() { - return mIcon; - } + @Override + public void setDisplayUseLogoEnabled(boolean useLogo) { + mActionBar.setDisplayUseLogoEnabled(useLogo); + } - @Override - public int getPosition() { - final int tabCount = mActionBar.getTabCount(); - for (int i = 0; i < tabCount; i++) { - if (mActionBar.getTabAt(i).equals(this)) { - return i; - } - } - return ActionBar.Tab.INVALID_POSITION; - } + @Override + public void setDisplayShowHomeEnabled(boolean showHome) { + mActionBar.setDisplayShowHomeEnabled(showHome); + } - @Override - public ActionBar.TabListener getTabListener() { - return mListener; - } + @Override + public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) { + mActionBar.setDisplayHomeAsUpEnabled(showHomeAsUp); + } - @Override - public Object getTag() { - return mTag; - } + @Override + public void setDisplayShowTitleEnabled(boolean showTitle) { + mActionBar.setDisplayShowTitleEnabled(showTitle); + } - @Override - public CharSequence getText() { - return mText; - } + @Override + public void setDisplayShowCustomEnabled(boolean showCustom) { + mActionBar.setDisplayShowCustomEnabled(showCustom); + } - @Override - public void select() { - mActionBar.selectTab(this); - } + @Override + public void setBackgroundDrawable(Drawable d) { + mActionBar.setBackgroundDrawable(d); + } - @Override - public ActionBar.Tab setCustomView(int layoutResId) { - mCustomView = mActionBar.mActivity.getLayoutInflater().inflate(layoutResId, null); - return this; - } + @Override + public void setStackedBackgroundDrawable(Drawable d) { + mActionBar.setStackedBackgroundDrawable(d); + } - @Override - public ActionBar.Tab setCustomView(View view) { - mCustomView = view; - return this; - } + @Override + public void setSplitBackgroundDrawable(Drawable d) { + mActionBar.setSplitBackgroundDrawable(d); + } - @Override - public ActionBar.Tab setIcon(Drawable icon) { - mIcon = icon; - return this; - } + @Override + public View getCustomView() { + return mActionBar.getCustomView(); + } - @Override - public ActionBar.Tab setIcon(int resId) { - mIcon = mActionBar.mActivity.getResources().getDrawable(resId); - return this; - } + @Override + public CharSequence getTitle() { + return mActionBar.getTitle(); + } - @Override - public ActionBar.Tab setTabListener(TabListener listener) { - mListener = listener; - return this; - } + @Override + public CharSequence getSubtitle() { + return mActionBar.getSubtitle(); + } - @Override - public ActionBar.Tab setTag(Object obj) { - mTag = obj; - return this; - } + @Override + public int getNavigationMode() { + return mActionBar.getNavigationMode(); + } - @Override - public ActionBar.Tab setText(int resId) { - mText = mActionBar.mActivity.getResources().getString(resId); - return this; - } + @Override + public void setNavigationMode(int mode) { + mActionBar.setNavigationMode(mode); + } - @Override - public ActionBar.Tab setText(CharSequence text) { - mText = text; - return this; - } - } + @Override + public int getDisplayOptions() { + return mActionBar.getDisplayOptions(); + } - @Override - public void addOnMenuVisibilityListener(final OnMenuVisibilityListener listener) { - if ((listener != null) && !mMenuListenerMap.containsKey(listener)) { - android.app.ActionBar.OnMenuVisibilityListener nativeListener = new android.app.ActionBar.OnMenuVisibilityListener() { - @Override - public void onMenuVisibilityChanged(boolean isVisible) { - listener.onMenuVisibilityChanged(isVisible); - } - }; - mMenuListenerMap.put(listener, nativeListener); + public class TabWrapper extends ActionBar.Tab implements android.app.ActionBar.TabListener { + final android.app.ActionBar.Tab mNativeTab; + private Object mTag; + private TabListener mListener; - getActionBar().addOnMenuVisibilityListener(nativeListener); - } + public TabWrapper(android.app.ActionBar.Tab nativeTab) { + mNativeTab = nativeTab; + mNativeTab.setTag(this); } @Override - public void addTab(Tab tab) { - getActionBar().addTab(convertTabToNative(tab)); + public int getPosition() { + return mNativeTab.getPosition(); } @Override - public void addTab(Tab tab, boolean setSelected) { - getActionBar().addTab(convertTabToNative(tab), setSelected); + public Drawable getIcon() { + return mNativeTab.getIcon(); } @Override - public void addTab(Tab tab, int position) { - getActionBar().addTab(convertTabToNative(tab), position); + public CharSequence getText() { + return mNativeTab.getText(); } @Override - public void addTab(ActionBar.Tab tab, int position, boolean setSelected) { - getActionBar().addTab(convertTabToNative(tab), position, setSelected); + public Tab setIcon(Drawable icon) { + mNativeTab.setIcon(icon); + return this; } @Override - public View getCustomView() { - return getActionBar().getCustomView(); + public Tab setIcon(int resId) { + mNativeTab.setIcon(resId); + return this; } @Override - public int getDisplayOptions() { - return getActionBar().getDisplayOptions(); + public Tab setText(CharSequence text) { + mNativeTab.setText(text); + return this; } @Override - public int getHeight() { - return getActionBar().getHeight(); + public Tab setText(int resId) { + mNativeTab.setText(resId); + return this; } @Override - public int getNavigationItemCount() { - return getActionBar().getNavigationItemCount(); + public Tab setCustomView(View view) { + mNativeTab.setCustomView(view); + return this; } @Override - public int getNavigationMode() { - return getActionBar().getNavigationMode(); + public Tab setCustomView(int layoutResId) { + mNativeTab.setCustomView(layoutResId); + return this; } @Override - public int getSelectedNavigationIndex() { - return getActionBar().getSelectedNavigationIndex(); + public View getCustomView() { + return mNativeTab.getCustomView(); } @Override - public Tab getSelectedTab() { - return (ActionBar.Tab)getActionBar().getSelectedTab().getTag(); + public Tab setTag(Object obj) { + mTag = obj; + return this; } @Override - public CharSequence getSubtitle() { - return getActionBar().getSubtitle(); + public Object getTag() { + return mTag; } @Override - public ActionBar.Tab getTabAt(int index) { - return (Tab)getActionBar().getTabAt(index).getTag(); + public Tab setTabListener(TabListener listener) { + mNativeTab.setTabListener(listener != null ? this : null); + mListener = listener; + return this; } @Override - public int getTabCount() { - return getActionBar().getTabCount(); + public void select() { + mNativeTab.select(); } @Override - public CharSequence getTitle() { - return getActionBar().getTitle(); + public Tab setContentDescription(int resId) { + mNativeTab.setContentDescription(resId); + return this; } @Override - public void hide() { - getActionBar().hide(); + public Tab setContentDescription(CharSequence contentDesc) { + mNativeTab.setContentDescription(contentDesc); + return this; } @Override - public boolean isShowing() { - return getActionBar().isShowing(); + public CharSequence getContentDescription() { + return mNativeTab.getContentDescription(); } @Override - public ActionBar.Tab newTab() { - return new TabImpl(this); - } + public void onTabReselected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) { + if (mListener != null) { + FragmentTransaction trans = null; + if (mActivity instanceof FragmentActivity) { + trans = ((FragmentActivity)mActivity).getSupportFragmentManager().beginTransaction() + .disallowAddToBackStack(); + } - @Override - public void removeAllTabs() { - getActionBar().removeAllTabs(); - } + mListener.onTabReselected(this, trans); - @Override - public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) { - if ((listener != null) && mMenuListenerMap.containsKey(listener)) { - getActionBar().removeOnMenuVisibilityListener( - mMenuListenerMap.remove(listener) - ); + if (trans != null && !trans.isEmpty()) { + trans.commit(); + } } } @Override - public void removeTab(Tab tab) { - final int tabCount = getActionBar().getTabCount(); - for (int i = 0; i < tabCount; i++) { - if (getActionBar().getTabAt(i).getTag().equals(tab)) { - getActionBar().removeTabAt(i); - break; + public void onTabSelected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) { + if (mListener != null) { + + if (mFragmentTransaction == null && mActivity instanceof FragmentActivity) { + mFragmentTransaction = ((FragmentActivity)mActivity).getSupportFragmentManager().beginTransaction() + .disallowAddToBackStack(); } - } - } - @Override - public void removeTabAt(int position) { - getActionBar().removeTabAt(position); - } + mListener.onTabSelected(this, mFragmentTransaction); - @Override - public void selectTab(ActionBar.Tab tab) { - final int tabCount = getActionBar().getTabCount(); - for (int i = 0; i < tabCount; i++) { - if (getActionBar().getTabAt(i).getTag().equals(tab)) { - getActionBar().setSelectedNavigationItem(i); - break; + if (mFragmentTransaction != null) { + if (!mFragmentTransaction.isEmpty()) { + mFragmentTransaction.commit(); + } + mFragmentTransaction = null; } } } @Override - public void setBackgroundDrawable(Drawable d) { - getActionBar().setBackgroundDrawable(d); - } + public void onTabUnselected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) { + if (mListener != null) { + FragmentTransaction trans = null; + if (mActivity instanceof FragmentActivity) { + trans = ((FragmentActivity)mActivity).getSupportFragmentManager().beginTransaction() + .disallowAddToBackStack(); + mFragmentTransaction = trans; + } - @Override - public void setCustomView(int resId) { - getActionBar().setCustomView(resId); + mListener.onTabUnselected(this, trans); + } } + } - @Override - public void setCustomView(View view) { - getActionBar().setCustomView(view); - } + @Override + public Tab newTab() { + return new TabWrapper(mActionBar.newTab()); + } - @Override - public void setCustomView(View view, LayoutParams layoutParams) { - android.app.ActionBar.LayoutParams nativeLayoutParams = new android.app.ActionBar.LayoutParams(layoutParams); - nativeLayoutParams.gravity = layoutParams.gravity; - getActionBar().setCustomView(view, nativeLayoutParams); - } + @Override + public void addTab(Tab tab) { + mActionBar.addTab(((TabWrapper)tab).mNativeTab); + } - @Override - public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) { - getActionBar().setDisplayHomeAsUpEnabled(showHomeAsUp); - } + @Override + public void addTab(Tab tab, boolean setSelected) { + mActionBar.addTab(((TabWrapper)tab).mNativeTab, setSelected); + } - @Override - public void setDisplayOptions(int options, int mask) { - getActionBar().setDisplayOptions(options, mask); - } + @Override + public void addTab(Tab tab, int position) { + mActionBar.addTab(((TabWrapper)tab).mNativeTab, position); + } - @Override - public void setDisplayOptions(int options) { - getActionBar().setDisplayOptions(options); - } + @Override + public void addTab(Tab tab, int position, boolean setSelected) { + mActionBar.addTab(((TabWrapper)tab).mNativeTab, position, setSelected); + } - @Override - public void setDisplayShowCustomEnabled(boolean showCustom) { - getActionBar().setDisplayShowCustomEnabled(showCustom); - } + @Override + public void removeTab(Tab tab) { + mActionBar.removeTab(((TabWrapper)tab).mNativeTab); + } - @Override - public void setDisplayShowHomeEnabled(boolean showHome) { - getActionBar().setDisplayShowHomeEnabled(showHome); - } + @Override + public void removeTabAt(int position) { + mActionBar.removeTabAt(position); + } - @Override - public void setDisplayShowTitleEnabled(boolean showTitle) { - getActionBar().setDisplayShowTitleEnabled(showTitle); - } + @Override + public void removeAllTabs() { + mActionBar.removeAllTabs(); + } - @Override - public void setDisplayUseLogoEnabled(boolean useLogo) { - getActionBar().setDisplayUseLogoEnabled(useLogo); - } + @Override + public void selectTab(Tab tab) { + mActionBar.selectTab(((TabWrapper)tab).mNativeTab); + } - @Override - public void setListNavigationCallbacks(SpinnerAdapter adapter, final OnNavigationListener callback) { - getActionBar().setListNavigationCallbacks(adapter, new android.app.ActionBar.OnNavigationListener() { - @Override - public boolean onNavigationItemSelected(int itemPosition, long itemId) { - if (callback != null) { - return callback.onNavigationItemSelected(itemPosition, itemId); - } - return false; - } - }); - } + @Override + public Tab getSelectedTab() { + android.app.ActionBar.Tab selected = mActionBar.getSelectedTab(); + return (selected != null) ? (Tab)selected.getTag() : null; + } - @Override - public void setNavigationMode(int mode) { - getActionBar().setNavigationMode(mode); - } + @Override + public Tab getTabAt(int index) { + android.app.ActionBar.Tab selected = mActionBar.getTabAt(index); + return (selected != null) ? (Tab)selected.getTag() : null; + } - @Override - public void setSelectedNavigationItem(int position) { - getActionBar().setSelectedNavigationItem(position); - } + @Override + public int getTabCount() { + return mActionBar.getTabCount(); + } - @Override - public void setSubtitle(CharSequence subtitle) { - getActionBar().setSubtitle(subtitle); - } + @Override + public int getHeight() { + return mActionBar.getHeight(); + } - @Override - public void setSubtitle(int resId) { - getActionBar().setSubtitle(resId); - } + @Override + public void show() { + mActionBar.show(); + } - @Override - public void setTitle(CharSequence title) { - getActionBar().setTitle(title); - } + @Override + public void hide() { + mActionBar.hide(); + } - @Override - public void setTitle(int resId) { - getActionBar().setTitle(resId); - } + @Override + public boolean isShowing() { + return mActionBar.isShowing(); + } - @Override - public void show() { - getActionBar().show(); + @Override + public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) { + mMenuVisibilityListeners.add(listener); + } + + @Override + public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) { + mMenuVisibilityListeners.remove(listener); + } + + @Override + public void onMenuVisibilityChanged(boolean isVisible) { + for (OnMenuVisibilityListener listener : mMenuVisibilityListeners) { + listener.onMenuVisibilityChanged(isVisible); } } } diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/Animator.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/Animator.java new file mode 100644 index 00000000..2caf5b4a --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/Animator.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +import java.util.ArrayList; + +import android.view.animation.Interpolator; + +/** + * This is the superclass for classes which provide basic support for animations which can be + * started, ended, and have AnimatorListeners added to them. + */ +public abstract class Animator implements Cloneable { + + + /** + * The set of listeners to be sent events through the life of an animation. + */ + ArrayList mListeners = null; + + /** + * Starts this animation. If the animation has a nonzero startDelay, the animation will start + * running after that delay elapses. A non-delayed animation will have its initial + * value(s) set immediately, followed by calls to + * {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator. + * + *

The animation started by calling this method will be run on the thread that called + * this method. This thread should have a Looper on it (a runtime exception will be thrown if + * this is not the case). Also, if the animation will animate + * properties of objects in the view hierarchy, then the calling thread should be the UI + * thread for that view hierarchy.

+ * + */ + public void start() { + } + + /** + * Cancels the animation. Unlike {@link #end()}, cancel() causes the animation to + * stop in its tracks, sending an + * {@link android.animation.Animator.AnimatorListener#onAnimationCancel(Animator)} to + * its listeners, followed by an + * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} message. + * + *

This method must be called on the thread that is running the animation.

+ */ + public void cancel() { + } + + /** + * Ends the animation. This causes the animation to assign the end value of the property being + * animated, then calling the + * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} method on + * its listeners. + * + *

This method must be called on the thread that is running the animation.

+ */ + public void end() { + } + + /** + * The amount of time, in milliseconds, to delay starting the animation after + * {@link #start()} is called. + * + * @return the number of milliseconds to delay running the animation + */ + public abstract long getStartDelay(); + + /** + * The amount of time, in milliseconds, to delay starting the animation after + * {@link #start()} is called. + + * @param startDelay The amount of the delay, in milliseconds + */ + public abstract void setStartDelay(long startDelay); + + + /** + * Sets the length of the animation. + * + * @param duration The length of the animation, in milliseconds. + */ + public abstract Animator setDuration(long duration); + + /** + * Gets the length of the animation. + * + * @return The length of the animation, in milliseconds. + */ + public abstract long getDuration(); + + /** + * The time interpolator used in calculating the elapsed fraction of this animation. The + * interpolator determines whether the animation runs with linear or non-linear motion, + * such as acceleration and deceleration. The default value is + * {@link android.view.animation.AccelerateDecelerateInterpolator} + * + * @param value the interpolator to be used by this animation + */ + public abstract void setInterpolator(/*Time*/Interpolator value); + + /** + * Returns whether this Animator is currently running (having been started and gone past any + * initial startDelay period and not yet ended). + * + * @return Whether the Animator is running. + */ + public abstract boolean isRunning(); + + /** + * Returns whether this Animator has been started and not yet ended. This state is a superset + * of the state of {@link #isRunning()}, because an Animator with a nonzero + * {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during the + * delay phase, whereas {@link #isRunning()} will return true only after the delay phase + * is complete. + * + * @return Whether the Animator has been started and not yet ended. + */ + public boolean isStarted() { + // Default method returns value for isRunning(). Subclasses should override to return a + // real value. + return isRunning(); + } + + /** + * Adds a listener to the set of listeners that are sent events through the life of an + * animation, such as start, repeat, and end. + * + * @param listener the listener to be added to the current set of listeners for this animation. + */ + public void addListener(AnimatorListener listener) { + if (mListeners == null) { + mListeners = new ArrayList(); + } + mListeners.add(listener); + } + + /** + * Removes a listener from the set listening to this animation. + * + * @param listener the listener to be removed from the current set of listeners for this + * animation. + */ + public void removeListener(AnimatorListener listener) { + if (mListeners == null) { + return; + } + mListeners.remove(listener); + if (mListeners.size() == 0) { + mListeners = null; + } + } + + /** + * Gets the set of {@link android.animation.Animator.AnimatorListener} objects that are currently + * listening for events on this Animator object. + * + * @return ArrayList The set of listeners. + */ + public ArrayList getListeners() { + return mListeners; + } + + /** + * Removes all listeners from this object. This is equivalent to calling + * getListeners() followed by calling clear() on the + * returned list of listeners. + */ + public void removeAllListeners() { + if (mListeners != null) { + mListeners.clear(); + mListeners = null; + } + } + + @Override + public Animator clone() { + try { + final Animator anim = (Animator) super.clone(); + if (mListeners != null) { + ArrayList oldListeners = mListeners; + anim.mListeners = new ArrayList(); + int numListeners = oldListeners.size(); + for (int i = 0; i < numListeners; ++i) { + anim.mListeners.add(oldListeners.get(i)); + } + } + return anim; + } catch (CloneNotSupportedException e) { + throw new AssertionError(); + } + } + + /** + * This method tells the object to use appropriate information to extract + * starting values for the animation. For example, a AnimatorSet object will pass + * this call to its child objects to tell them to set up the values. A + * ObjectAnimator object will use the information it has about its target object + * and PropertyValuesHolder objects to get the start values for its properties. + * An ValueAnimator object will ignore the request since it does not have enough + * information (such as a target object) to gather these values. + */ + public void setupStartValues() { + } + + /** + * This method tells the object to use appropriate information to extract + * ending values for the animation. For example, a AnimatorSet object will pass + * this call to its child objects to tell them to set up the values. A + * ObjectAnimator object will use the information it has about its target object + * and PropertyValuesHolder objects to get the start values for its properties. + * An ValueAnimator object will ignore the request since it does not have enough + * information (such as a target object) to gather these values. + */ + public void setupEndValues() { + } + + /** + * Sets the target object whose property will be animated by this animation. Not all subclasses + * operate on target objects (for example, {@link ValueAnimator}, but this method + * is on the superclass for the convenience of dealing generically with those subclasses + * that do handle targets. + * + * @param target The object being animated + */ + public void setTarget(Object target) { + } + + /** + *

An animation listener receives notifications from an animation. + * Notifications indicate animation related events, such as the end or the + * repetition of the animation.

+ */ + public static interface AnimatorListener { + /** + *

Notifies the start of the animation.

+ * + * @param animation The started animation. + */ + void onAnimationStart(Animator animation); + + /** + *

Notifies the end of the animation. This callback is not invoked + * for animations with repeat count set to INFINITE.

+ * + * @param animation The animation which reached its end. + */ + void onAnimationEnd(Animator animation); + + /** + *

Notifies the cancellation of the animation. This callback is not invoked + * for animations with repeat count set to INFINITE.

+ * + * @param animation The animation which was canceled. + */ + void onAnimationCancel(Animator animation); + + /** + *

Notifies the repetition of the animation.

+ * + * @param animation The animation which was repeated. + */ + void onAnimationRepeat(Animator animation); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorListenerAdapter.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorListenerAdapter.java new file mode 100644 index 00000000..02ddff48 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorListenerAdapter.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +/** + * This adapter class provides empty implementations of the methods from {@link android.animation.Animator.AnimatorListener}. + * Any custom listener that cares only about a subset of the methods of this listener can + * simply subclass this adapter class instead of implementing the interface directly. + */ +public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener { + + /** + * {@inheritDoc} + */ + @Override + public void onAnimationCancel(Animator animation) { + } + + /** + * {@inheritDoc} + */ + @Override + public void onAnimationEnd(Animator animation) { + } + + /** + * {@inheritDoc} + */ + @Override + public void onAnimationRepeat(Animator animation) { + } + + /** + * {@inheritDoc} + */ + @Override + public void onAnimationStart(Animator animation) { + } + +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java new file mode 100644 index 00000000..3231080c --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java @@ -0,0 +1,1111 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + +import android.view.animation.Interpolator; + +/** + * This class plays a set of {@link Animator} objects in the specified order. Animations + * can be set up to play together, in sequence, or after a specified delay. + * + *

There are two different approaches to adding animations to a AnimatorSet: + * either the {@link AnimatorSet#playTogether(Animator[]) playTogether()} or + * {@link AnimatorSet#playSequentially(Animator[]) playSequentially()} methods can be called to add + * a set of animations all at once, or the {@link AnimatorSet#play(Animator)} can be + * used in conjunction with methods in the {@link AnimatorSet.Builder Builder} + * class to add animations + * one by one.

+ * + *

It is possible to set up a AnimatorSet with circular dependencies between + * its animations. For example, an animation a1 could be set up to start before animation a2, a2 + * before a3, and a3 before a1. The results of this configuration are undefined, but will typically + * result in none of the affected animations being played. Because of this (and because + * circular dependencies do not make logical sense anyway), circular dependencies + * should be avoided, and the dependency flow of animations should only be in one direction. + */ +@SuppressWarnings("unchecked") +public final class AnimatorSet extends Animator { + + /** + * Internal variables + * NOTE: This object implements the clone() method, making a deep copy of any referenced + * objects. As other non-trivial fields are added to this class, make sure to add logic + * to clone() to make deep copies of them. + */ + + /** + * Tracks animations currently being played, so that we know what to + * cancel or end when cancel() or end() is called on this AnimatorSet + */ + private ArrayList mPlayingSet = new ArrayList(); + + /** + * Contains all nodes, mapped to their respective Animators. When new + * dependency information is added for an Animator, we want to add it + * to a single node representing that Animator, not create a new Node + * if one already exists. + */ + private HashMap mNodeMap = new HashMap(); + + /** + * Set of all nodes created for this AnimatorSet. This list is used upon + * starting the set, and the nodes are placed in sorted order into the + * sortedNodes collection. + */ + private ArrayList mNodes = new ArrayList(); + + /** + * The sorted list of nodes. This is the order in which the animations will + * be played. The details about when exactly they will be played depend + * on the dependency relationships of the nodes. + */ + private ArrayList mSortedNodes = new ArrayList(); + + /** + * Flag indicating whether the nodes should be sorted prior to playing. This + * flag allows us to cache the previous sorted nodes so that if the sequence + * is replayed with no changes, it does not have to re-sort the nodes again. + */ + private boolean mNeedsSort = true; + + private AnimatorSetListener mSetListener = null; + + /** + * Flag indicating that the AnimatorSet has been manually + * terminated (by calling cancel() or end()). + * This flag is used to avoid starting other animations when currently-playing + * child animations of this AnimatorSet end. It also determines whether cancel/end + * notifications are sent out via the normal AnimatorSetListener mechanism. + */ + boolean mTerminated = false; + + /** + * Indicates whether an AnimatorSet has been start()'d, whether or + * not there is a nonzero startDelay. + */ + private boolean mStarted = false; + + // The amount of time in ms to delay starting the animation after start() is called + private long mStartDelay = 0; + + // Animator used for a nonzero startDelay + private ValueAnimator mDelayAnim = null; + + + // How long the child animations should last in ms. The default value is negative, which + // simply means that there is no duration set on the AnimatorSet. When a real duration is + // set, it is passed along to the child animations. + private long mDuration = -1; + + + /** + * Sets up this AnimatorSet to play all of the supplied animations at the same time. + * + * @param items The animations that will be started simultaneously. + */ + public void playTogether(Animator... items) { + if (items != null) { + mNeedsSort = true; + Builder builder = play(items[0]); + for (int i = 1; i < items.length; ++i) { + builder.with(items[i]); + } + } + } + + /** + * Sets up this AnimatorSet to play all of the supplied animations at the same time. + * + * @param items The animations that will be started simultaneously. + */ + public void playTogether(Collection items) { + if (items != null && items.size() > 0) { + mNeedsSort = true; + Builder builder = null; + for (Animator anim : items) { + if (builder == null) { + builder = play(anim); + } else { + builder.with(anim); + } + } + } + } + + /** + * Sets up this AnimatorSet to play each of the supplied animations when the + * previous animation ends. + * + * @param items The animations that will be started one after another. + */ + public void playSequentially(Animator... items) { + if (items != null) { + mNeedsSort = true; + if (items.length == 1) { + play(items[0]); + } else { + for (int i = 0; i < items.length - 1; ++i) { + play(items[i]).before(items[i+1]); + } + } + } + } + + /** + * Sets up this AnimatorSet to play each of the supplied animations when the + * previous animation ends. + * + * @param items The animations that will be started one after another. + */ + public void playSequentially(List items) { + if (items != null && items.size() > 0) { + mNeedsSort = true; + if (items.size() == 1) { + play(items.get(0)); + } else { + for (int i = 0; i < items.size() - 1; ++i) { + play(items.get(i)).before(items.get(i+1)); + } + } + } + } + + /** + * Returns the current list of child Animator objects controlled by this + * AnimatorSet. This is a copy of the internal list; modifications to the returned list + * will not affect the AnimatorSet, although changes to the underlying Animator objects + * will affect those objects being managed by the AnimatorSet. + * + * @return ArrayList The list of child animations of this AnimatorSet. + */ + public ArrayList getChildAnimations() { + ArrayList childList = new ArrayList(); + for (Node node : mNodes) { + childList.add(node.animation); + } + return childList; + } + + /** + * Sets the target object for all current {@link #getChildAnimations() child animations} + * of this AnimatorSet that take targets ({@link ObjectAnimator} and + * AnimatorSet). + * + * @param target The object being animated + */ + @Override + public void setTarget(Object target) { + for (Node node : mNodes) { + Animator animation = node.animation; + if (animation instanceof AnimatorSet) { + ((AnimatorSet)animation).setTarget(target); + } else if (animation instanceof ObjectAnimator) { + ((ObjectAnimator)animation).setTarget(target); + } + } + } + + /** + * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations} + * of this AnimatorSet. + * + * @param interpolator the interpolator to be used by each child animation of this AnimatorSet + */ + @Override + public void setInterpolator(/*Time*/Interpolator interpolator) { + for (Node node : mNodes) { + node.animation.setInterpolator(interpolator); + } + } + + /** + * This method creates a Builder object, which is used to + * set up playing constraints. This initial play() method + * tells the Builder the animation that is the dependency for + * the succeeding commands to the Builder. For example, + * calling play(a1).with(a2) sets up the AnimatorSet to play + * a1 and a2 at the same time, + * play(a1).before(a2) sets up the AnimatorSet to play + * a1 first, followed by a2, and + * play(a1).after(a2) sets up the AnimatorSet to play + * a2 first, followed by a1. + * + *

Note that play() is the only way to tell the + * Builder the animation upon which the dependency is created, + * so successive calls to the various functions in Builder + * will all refer to the initial parameter supplied in play() + * as the dependency of the other animations. For example, calling + * play(a1).before(a2).before(a3) will play both a2 + * and a3 when a1 ends; it does not set up a dependency between + * a2 and a3.

+ * + * @param anim The animation that is the dependency used in later calls to the + * methods in the returned Builder object. A null parameter will result + * in a null Builder return value. + * @return Builder The object that constructs the AnimatorSet based on the dependencies + * outlined in the calls to play and the other methods in the + * BuilderNote that canceling a AnimatorSet also cancels all of the animations that it + * is responsible for.

+ */ + @Override + public void cancel() { + mTerminated = true; + if (isStarted()) { + ArrayList tmpListeners = null; + if (mListeners != null) { + tmpListeners = (ArrayList) mListeners.clone(); + for (AnimatorListener listener : tmpListeners) { + listener.onAnimationCancel(this); + } + } + if (mDelayAnim != null && mDelayAnim.isRunning()) { + // If we're currently in the startDelay period, just cancel that animator and + // send out the end event to all listeners + mDelayAnim.cancel(); + } else if (mSortedNodes.size() > 0) { + for (Node node : mSortedNodes) { + node.animation.cancel(); + } + } + if (tmpListeners != null) { + for (AnimatorListener listener : tmpListeners) { + listener.onAnimationEnd(this); + } + } + mStarted = false; + } + } + + /** + * {@inheritDoc} + * + *

Note that ending a AnimatorSet also ends all of the animations that it is + * responsible for.

+ */ + @Override + public void end() { + mTerminated = true; + if (isStarted()) { + if (mSortedNodes.size() != mNodes.size()) { + // hasn't been started yet - sort the nodes now, then end them + sortNodes(); + for (Node node : mSortedNodes) { + if (mSetListener == null) { + mSetListener = new AnimatorSetListener(this); + } + node.animation.addListener(mSetListener); + } + } + if (mDelayAnim != null) { + mDelayAnim.cancel(); + } + if (mSortedNodes.size() > 0) { + for (Node node : mSortedNodes) { + node.animation.end(); + } + } + if (mListeners != null) { + ArrayList tmpListeners = + (ArrayList) mListeners.clone(); + for (AnimatorListener listener : tmpListeners) { + listener.onAnimationEnd(this); + } + } + mStarted = false; + } + } + + /** + * Returns true if any of the child animations of this AnimatorSet have been started and have + * not yet ended. + * @return Whether this AnimatorSet has been started and has not yet ended. + */ + @Override + public boolean isRunning() { + for (Node node : mNodes) { + if (node.animation.isRunning()) { + return true; + } + } + return false; + } + + @Override + public boolean isStarted() { + return mStarted; + } + + /** + * The amount of time, in milliseconds, to delay starting the animation after + * {@link #start()} is called. + * + * @return the number of milliseconds to delay running the animation + */ + @Override + public long getStartDelay() { + return mStartDelay; + } + + /** + * The amount of time, in milliseconds, to delay starting the animation after + * {@link #start()} is called. + + * @param startDelay The amount of the delay, in milliseconds + */ + @Override + public void setStartDelay(long startDelay) { + mStartDelay = startDelay; + } + + /** + * Gets the length of each of the child animations of this AnimatorSet. This value may + * be less than 0, which indicates that no duration has been set on this AnimatorSet + * and each of the child animations will use their own duration. + * + * @return The length of the animation, in milliseconds, of each of the child + * animations of this AnimatorSet. + */ + @Override + public long getDuration() { + return mDuration; + } + + /** + * Sets the length of each of the current child animations of this AnimatorSet. By default, + * each child animation will use its own duration. If the duration is set on the AnimatorSet, + * then each child animation inherits this duration. + * + * @param duration The length of the animation, in milliseconds, of each of the child + * animations of this AnimatorSet. + */ + @Override + public AnimatorSet setDuration(long duration) { + if (duration < 0) { + throw new IllegalArgumentException("duration must be a value of zero or greater"); + } + for (Node node : mNodes) { + // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to + // insert "play-after" delays + node.animation.setDuration(duration); + } + mDuration = duration; + return this; + } + + @Override + public void setupStartValues() { + for (Node node : mNodes) { + node.animation.setupStartValues(); + } + } + + @Override + public void setupEndValues() { + for (Node node : mNodes) { + node.animation.setupEndValues(); + } + } + + /** + * {@inheritDoc} + * + *

Starting this AnimatorSet will, in turn, start the animations for which + * it is responsible. The details of when exactly those animations are started depends on + * the dependency relationships that have been set up between the animations. + */ + @Override + public void start() { + mTerminated = false; + mStarted = true; + + // First, sort the nodes (if necessary). This will ensure that sortedNodes + // contains the animation nodes in the correct order. + sortNodes(); + + int numSortedNodes = mSortedNodes.size(); + for (int i = 0; i < numSortedNodes; ++i) { + Node node = mSortedNodes.get(i); + // First, clear out the old listeners + ArrayList oldListeners = node.animation.getListeners(); + if (oldListeners != null && oldListeners.size() > 0) { + final ArrayList clonedListeners = new + ArrayList(oldListeners); + + for (AnimatorListener listener : clonedListeners) { + if (listener instanceof DependencyListener || + listener instanceof AnimatorSetListener) { + node.animation.removeListener(listener); + } + } + } + } + + // nodesToStart holds the list of nodes to be started immediately. We don't want to + // start the animations in the loop directly because we first need to set up + // dependencies on all of the nodes. For example, we don't want to start an animation + // when some other animation also wants to start when the first animation begins. + final ArrayList nodesToStart = new ArrayList(); + for (int i = 0; i < numSortedNodes; ++i) { + Node node = mSortedNodes.get(i); + if (mSetListener == null) { + mSetListener = new AnimatorSetListener(this); + } + if (node.dependencies == null || node.dependencies.size() == 0) { + nodesToStart.add(node); + } else { + int numDependencies = node.dependencies.size(); + for (int j = 0; j < numDependencies; ++j) { + Dependency dependency = node.dependencies.get(j); + dependency.node.animation.addListener( + new DependencyListener(this, node, dependency.rule)); + } + node.tmpDependencies = (ArrayList) node.dependencies.clone(); + } + node.animation.addListener(mSetListener); + } + // Now that all dependencies are set up, start the animations that should be started. + if (mStartDelay <= 0) { + for (Node node : nodesToStart) { + node.animation.start(); + mPlayingSet.add(node.animation); + } + } else { + mDelayAnim = ValueAnimator.ofFloat(0f, 1f); + mDelayAnim.setDuration(mStartDelay); + mDelayAnim.addListener(new AnimatorListenerAdapter() { + boolean canceled = false; + public void onAnimationCancel(Animator anim) { + canceled = true; + } + public void onAnimationEnd(Animator anim) { + if (!canceled) { + int numNodes = nodesToStart.size(); + for (int i = 0; i < numNodes; ++i) { + Node node = nodesToStart.get(i); + node.animation.start(); + mPlayingSet.add(node.animation); + } + } + } + }); + mDelayAnim.start(); + } + if (mListeners != null) { + ArrayList tmpListeners = + (ArrayList) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (int i = 0; i < numListeners; ++i) { + tmpListeners.get(i).onAnimationStart(this); + } + } + if (mNodes.size() == 0 && mStartDelay == 0) { + // Handle unusual case where empty AnimatorSet is started - should send out + // end event immediately since the event will not be sent out at all otherwise + mStarted = false; + if (mListeners != null) { + ArrayList tmpListeners = + (ArrayList) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (int i = 0; i < numListeners; ++i) { + tmpListeners.get(i).onAnimationEnd(this); + } + } + } + } + + @Override + public AnimatorSet clone() { + final AnimatorSet anim = (AnimatorSet) super.clone(); + /* + * The basic clone() operation copies all items. This doesn't work very well for + * AnimatorSet, because it will copy references that need to be recreated and state + * that may not apply. What we need to do now is put the clone in an uninitialized + * state, with fresh, empty data structures. Then we will build up the nodes list + * manually, as we clone each Node (and its animation). The clone will then be sorted, + * and will populate any appropriate lists, when it is started. + */ + anim.mNeedsSort = true; + anim.mTerminated = false; + anim.mStarted = false; + anim.mPlayingSet = new ArrayList(); + anim.mNodeMap = new HashMap(); + anim.mNodes = new ArrayList(); + anim.mSortedNodes = new ArrayList(); + + // Walk through the old nodes list, cloning each node and adding it to the new nodemap. + // One problem is that the old node dependencies point to nodes in the old AnimatorSet. + // We need to track the old/new nodes in order to reconstruct the dependencies in the clone. + HashMap nodeCloneMap = new HashMap(); // + for (Node node : mNodes) { + Node nodeClone = node.clone(); + nodeCloneMap.put(node, nodeClone); + anim.mNodes.add(nodeClone); + anim.mNodeMap.put(nodeClone.animation, nodeClone); + // Clear out the dependencies in the clone; we'll set these up manually later + nodeClone.dependencies = null; + nodeClone.tmpDependencies = null; + nodeClone.nodeDependents = null; + nodeClone.nodeDependencies = null; + // clear out any listeners that were set up by the AnimatorSet; these will + // be set up when the clone's nodes are sorted + ArrayList cloneListeners = nodeClone.animation.getListeners(); + if (cloneListeners != null) { + ArrayList listenersToRemove = null; + for (AnimatorListener listener : cloneListeners) { + if (listener instanceof AnimatorSetListener) { + if (listenersToRemove == null) { + listenersToRemove = new ArrayList(); + } + listenersToRemove.add(listener); + } + } + if (listenersToRemove != null) { + for (AnimatorListener listener : listenersToRemove) { + cloneListeners.remove(listener); + } + } + } + } + // Now that we've cloned all of the nodes, we're ready to walk through their + // dependencies, mapping the old dependencies to the new nodes + for (Node node : mNodes) { + Node nodeClone = nodeCloneMap.get(node); + if (node.dependencies != null) { + for (Dependency dependency : node.dependencies) { + Node clonedDependencyNode = nodeCloneMap.get(dependency.node); + Dependency cloneDependency = new Dependency(clonedDependencyNode, + dependency.rule); + nodeClone.addDependency(cloneDependency); + } + } + } + + return anim; + } + + /** + * This class is the mechanism by which animations are started based on events in other + * animations. If an animation has multiple dependencies on other animations, then + * all dependencies must be satisfied before the animation is started. + */ + private static class DependencyListener implements AnimatorListener { + + private AnimatorSet mAnimatorSet; + + // The node upon which the dependency is based. + private Node mNode; + + // The Dependency rule (WITH or AFTER) that the listener should wait for on + // the node + private int mRule; + + public DependencyListener(AnimatorSet animatorSet, Node node, int rule) { + this.mAnimatorSet = animatorSet; + this.mNode = node; + this.mRule = rule; + } + + /** + * Ignore cancel events for now. We may want to handle this eventually, + * to prevent follow-on animations from running when some dependency + * animation is canceled. + */ + public void onAnimationCancel(Animator animation) { + } + + /** + * An end event is received - see if this is an event we are listening for + */ + public void onAnimationEnd(Animator animation) { + if (mRule == Dependency.AFTER) { + startIfReady(animation); + } + } + + /** + * Ignore repeat events for now + */ + public void onAnimationRepeat(Animator animation) { + } + + /** + * A start event is received - see if this is an event we are listening for + */ + public void onAnimationStart(Animator animation) { + if (mRule == Dependency.WITH) { + startIfReady(animation); + } + } + + /** + * Check whether the event received is one that the node was waiting for. + * If so, mark it as complete and see whether it's time to start + * the animation. + * @param dependencyAnimation the animation that sent the event. + */ + private void startIfReady(Animator dependencyAnimation) { + if (mAnimatorSet.mTerminated) { + // if the parent AnimatorSet was canceled, then don't start any dependent anims + return; + } + Dependency dependencyToRemove = null; + int numDependencies = mNode.tmpDependencies.size(); + for (int i = 0; i < numDependencies; ++i) { + Dependency dependency = mNode.tmpDependencies.get(i); + if (dependency.rule == mRule && + dependency.node.animation == dependencyAnimation) { + // rule fired - remove the dependency and listener and check to + // see whether it's time to start the animation + dependencyToRemove = dependency; + dependencyAnimation.removeListener(this); + break; + } + } + mNode.tmpDependencies.remove(dependencyToRemove); + if (mNode.tmpDependencies.size() == 0) { + // all dependencies satisfied: start the animation + mNode.animation.start(); + mAnimatorSet.mPlayingSet.add(mNode.animation); + } + } + + } + + private class AnimatorSetListener implements AnimatorListener { + + private AnimatorSet mAnimatorSet; + + AnimatorSetListener(AnimatorSet animatorSet) { + mAnimatorSet = animatorSet; + } + + public void onAnimationCancel(Animator animation) { + if (!mTerminated) { + // Listeners are already notified of the AnimatorSet canceling in cancel(). + // The logic below only kicks in when animations end normally + if (mPlayingSet.size() == 0) { + if (mListeners != null) { + int numListeners = mListeners.size(); + for (int i = 0; i < numListeners; ++i) { + mListeners.get(i).onAnimationCancel(mAnimatorSet); + } + } + } + } + } + + public void onAnimationEnd(Animator animation) { + animation.removeListener(this); + mPlayingSet.remove(animation); + Node animNode = mAnimatorSet.mNodeMap.get(animation); + animNode.done = true; + if (!mTerminated) { + // Listeners are already notified of the AnimatorSet ending in cancel() or + // end(); the logic below only kicks in when animations end normally + ArrayList sortedNodes = mAnimatorSet.mSortedNodes; + boolean allDone = true; + int numSortedNodes = sortedNodes.size(); + for (int i = 0; i < numSortedNodes; ++i) { + if (!sortedNodes.get(i).done) { + allDone = false; + break; + } + } + if (allDone) { + // If this was the last child animation to end, then notify listeners that this + // AnimatorSet has ended + if (mListeners != null) { + ArrayList tmpListeners = + (ArrayList) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (int i = 0; i < numListeners; ++i) { + tmpListeners.get(i).onAnimationEnd(mAnimatorSet); + } + } + mAnimatorSet.mStarted = false; + } + } + } + + // Nothing to do + public void onAnimationRepeat(Animator animation) { + } + + // Nothing to do + public void onAnimationStart(Animator animation) { + } + + } + + /** + * This method sorts the current set of nodes, if needed. The sort is a simple + * DependencyGraph sort, which goes like this: + * - All nodes without dependencies become 'roots' + * - while roots list is not null + * - for each root r + * - add r to sorted list + * - remove r as a dependency from any other node + * - any nodes with no dependencies are added to the roots list + */ + private void sortNodes() { + if (mNeedsSort) { + mSortedNodes.clear(); + ArrayList roots = new ArrayList(); + int numNodes = mNodes.size(); + for (int i = 0; i < numNodes; ++i) { + Node node = mNodes.get(i); + if (node.dependencies == null || node.dependencies.size() == 0) { + roots.add(node); + } + } + ArrayList tmpRoots = new ArrayList(); + while (roots.size() > 0) { + int numRoots = roots.size(); + for (int i = 0; i < numRoots; ++i) { + Node root = roots.get(i); + mSortedNodes.add(root); + if (root.nodeDependents != null) { + int numDependents = root.nodeDependents.size(); + for (int j = 0; j < numDependents; ++j) { + Node node = root.nodeDependents.get(j); + node.nodeDependencies.remove(root); + if (node.nodeDependencies.size() == 0) { + tmpRoots.add(node); + } + } + } + } + roots.clear(); + roots.addAll(tmpRoots); + tmpRoots.clear(); + } + mNeedsSort = false; + if (mSortedNodes.size() != mNodes.size()) { + throw new IllegalStateException("Circular dependencies cannot exist" + + " in AnimatorSet"); + } + } else { + // Doesn't need sorting, but still need to add in the nodeDependencies list + // because these get removed as the event listeners fire and the dependencies + // are satisfied + int numNodes = mNodes.size(); + for (int i = 0; i < numNodes; ++i) { + Node node = mNodes.get(i); + if (node.dependencies != null && node.dependencies.size() > 0) { + int numDependencies = node.dependencies.size(); + for (int j = 0; j < numDependencies; ++j) { + Dependency dependency = node.dependencies.get(j); + if (node.nodeDependencies == null) { + node.nodeDependencies = new ArrayList(); + } + if (!node.nodeDependencies.contains(dependency.node)) { + node.nodeDependencies.add(dependency.node); + } + } + } + // nodes are 'done' by default; they become un-done when started, and done + // again when ended + node.done = false; + } + } + } + + /** + * Dependency holds information about the node that some other node is + * dependent upon and the nature of that dependency. + * + */ + private static class Dependency { + static final int WITH = 0; // dependent node must start with this dependency node + static final int AFTER = 1; // dependent node must start when this dependency node finishes + + // The node that the other node with this Dependency is dependent upon + public Node node; + + // The nature of the dependency (WITH or AFTER) + public int rule; + + public Dependency(Node node, int rule) { + this.node = node; + this.rule = rule; + } + } + + /** + * A Node is an embodiment of both the Animator that it wraps as well as + * any dependencies that are associated with that Animation. This includes + * both dependencies upon other nodes (in the dependencies list) as + * well as dependencies of other nodes upon this (in the nodeDependents list). + */ + private static class Node implements Cloneable { + public Animator animation; + + /** + * These are the dependencies that this node's animation has on other + * nodes. For example, if this node's animation should begin with some + * other animation ends, then there will be an item in this node's + * dependencies list for that other animation's node. + */ + public ArrayList dependencies = null; + + /** + * tmpDependencies is a runtime detail. We use the dependencies list for sorting. + * But we also use the list to keep track of when multiple dependencies are satisfied, + * but removing each dependency as it is satisfied. We do not want to remove + * the dependency itself from the list, because we need to retain that information + * if the AnimatorSet is launched in the future. So we create a copy of the dependency + * list when the AnimatorSet starts and use this tmpDependencies list to track the + * list of satisfied dependencies. + */ + public ArrayList tmpDependencies = null; + + /** + * nodeDependencies is just a list of the nodes that this Node is dependent upon. + * This information is used in sortNodes(), to determine when a node is a root. + */ + public ArrayList nodeDependencies = null; + + /** + * nodeDepdendents is the list of nodes that have this node as a dependency. This + * is a utility field used in sortNodes to facilitate removing this node as a + * dependency when it is a root node. + */ + public ArrayList nodeDependents = null; + + /** + * Flag indicating whether the animation in this node is finished. This flag + * is used by AnimatorSet to check, as each animation ends, whether all child animations + * are done and it's time to send out an end event for the entire AnimatorSet. + */ + public boolean done = false; + + /** + * Constructs the Node with the animation that it encapsulates. A Node has no + * dependencies by default; dependencies are added via the addDependency() + * method. + * + * @param animation The animation that the Node encapsulates. + */ + public Node(Animator animation) { + this.animation = animation; + } + + /** + * Add a dependency to this Node. The dependency includes information about the + * node that this node is dependency upon and the nature of the dependency. + * @param dependency + */ + public void addDependency(Dependency dependency) { + if (dependencies == null) { + dependencies = new ArrayList(); + nodeDependencies = new ArrayList(); + } + dependencies.add(dependency); + if (!nodeDependencies.contains(dependency.node)) { + nodeDependencies.add(dependency.node); + } + Node dependencyNode = dependency.node; + if (dependencyNode.nodeDependents == null) { + dependencyNode.nodeDependents = new ArrayList(); + } + dependencyNode.nodeDependents.add(this); + } + + @Override + public Node clone() { + try { + Node node = (Node) super.clone(); + node.animation = animation.clone(); + return node; + } catch (CloneNotSupportedException e) { + throw new AssertionError(); + } + } + } + + /** + * The Builder object is a utility class to facilitate adding animations to a + * AnimatorSet along with the relationships between the various animations. The + * intention of the Builder methods, along with the {@link + * AnimatorSet#play(Animator) play()} method of AnimatorSet is to make it possible + * to express the dependency relationships of animations in a natural way. Developers can also + * use the {@link AnimatorSet#playTogether(Animator[]) playTogether()} and {@link + * AnimatorSet#playSequentially(Animator[]) playSequentially()} methods if these suit the need, + * but it might be easier in some situations to express the AnimatorSet of animations in pairs. + *

+ *

The Builder object cannot be constructed directly, but is rather constructed + * internally via a call to {@link AnimatorSet#play(Animator)}.

+ *

+ *

For example, this sets up a AnimatorSet to play anim1 and anim2 at the same time, anim3 to + * play when anim2 finishes, and anim4 to play when anim3 finishes:

+ *
+     *     AnimatorSet s = new AnimatorSet();
+     *     s.play(anim1).with(anim2);
+     *     s.play(anim2).before(anim3);
+     *     s.play(anim4).after(anim3);
+     * 
+ *

+ *

Note in the example that both {@link Builder#before(Animator)} and {@link + * Builder#after(Animator)} are used. These are just different ways of expressing the same + * relationship and are provided to make it easier to say things in a way that is more natural, + * depending on the situation.

+ *

+ *

It is possible to make several calls into the same Builder object to express + * multiple relationships. However, note that it is only the animation passed into the initial + * {@link AnimatorSet#play(Animator)} method that is the dependency in any of the successive + * calls to the Builder object. For example, the following code starts both anim2 + * and anim3 when anim1 ends; there is no direct dependency relationship between anim2 and + * anim3: + *

+     *   AnimatorSet s = new AnimatorSet();
+     *   s.play(anim1).before(anim2).before(anim3);
+     * 
+ * If the desired result is to play anim1 then anim2 then anim3, this code expresses the + * relationship correctly:

+ *
+     *   AnimatorSet s = new AnimatorSet();
+     *   s.play(anim1).before(anim2);
+     *   s.play(anim2).before(anim3);
+     * 
+ *

+ *

Note that it is possible to express relationships that cannot be resolved and will not + * result in sensible results. For example, play(anim1).after(anim1) makes no + * sense. In general, circular dependencies like this one (or more indirect ones where a depends + * on b, which depends on c, which depends on a) should be avoided. Only create AnimatorSets + * that can boil down to a simple, one-way relationship of animations starting with, before, and + * after other, different, animations.

+ */ + public class Builder { + + /** + * This tracks the current node being processed. It is supplied to the play() method + * of AnimatorSet and passed into the constructor of Builder. + */ + private Node mCurrentNode; + + /** + * package-private constructor. Builders are only constructed by AnimatorSet, when the + * play() method is called. + * + * @param anim The animation that is the dependency for the other animations passed into + * the other methods of this Builder object. + */ + Builder(Animator anim) { + mCurrentNode = mNodeMap.get(anim); + if (mCurrentNode == null) { + mCurrentNode = new Node(anim); + mNodeMap.put(anim, mCurrentNode); + mNodes.add(mCurrentNode); + } + } + + /** + * Sets up the given animation to play at the same time as the animation supplied in the + * {@link AnimatorSet#play(Animator)} call that created this Builder object. + * + * @param anim The animation that will play when the animation supplied to the + * {@link AnimatorSet#play(Animator)} method starts. + */ + public Builder with(Animator anim) { + Node node = mNodeMap.get(anim); + if (node == null) { + node = new Node(anim); + mNodeMap.put(anim, node); + mNodes.add(node); + } + Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH); + node.addDependency(dependency); + return this; + } + + /** + * Sets up the given animation to play when the animation supplied in the + * {@link AnimatorSet#play(Animator)} call that created this Builder object + * ends. + * + * @param anim The animation that will play when the animation supplied to the + * {@link AnimatorSet#play(Animator)} method ends. + */ + public Builder before(Animator anim) { + Node node = mNodeMap.get(anim); + if (node == null) { + node = new Node(anim); + mNodeMap.put(anim, node); + mNodes.add(node); + } + Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER); + node.addDependency(dependency); + return this; + } + + /** + * Sets up the given animation to play when the animation supplied in the + * {@link AnimatorSet#play(Animator)} call that created this Builder object + * to start when the animation supplied in this method call ends. + * + * @param anim The animation whose end will cause the animation supplied to the + * {@link AnimatorSet#play(Animator)} method to play. + */ + public Builder after(Animator anim) { + Node node = mNodeMap.get(anim); + if (node == null) { + node = new Node(anim); + mNodeMap.put(anim, node); + mNodes.add(node); + } + Dependency dependency = new Dependency(node, Dependency.AFTER); + mCurrentNode.addDependency(dependency); + return this; + } + + /** + * Sets up the animation supplied in the + * {@link AnimatorSet#play(Animator)} call that created this Builder object + * to play when the given amount of time elapses. + * + * @param delay The number of milliseconds that should elapse before the + * animation starts. + */ + public Builder after(long delay) { + // setup dummy ValueAnimator just to run the clock + ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); + anim.setDuration(delay); + after(anim); + return this; + } + + } + +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatEvaluator.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatEvaluator.java new file mode 100644 index 00000000..e4101936 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatEvaluator.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +/** + * This evaluator can be used to perform type interpolation between float values. + */ +public class FloatEvaluator implements TypeEvaluator { + + /** + * This function returns the result of linearly interpolating the start and end values, with + * fraction representing the proportion between the start and end values. The + * calculation is a simple parametric calculation: result = x0 + t * (v1 - v0), + * where x0 is startValue, x1 is endValue, + * and t is fraction. + * + * @param fraction The fraction from the starting to the ending values + * @param startValue The start value; should be of type float or + * Float + * @param endValue The end value; should be of type float or Float + * @return A linear interpolation between the start and end values, given the + * fraction parameter. + */ + public Float evaluate(float fraction, Number startValue, Number endValue) { + float startFloat = startValue.floatValue(); + return startFloat + fraction * (endValue.floatValue() - startFloat); + } +} \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatKeyframeSet.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatKeyframeSet.java new file mode 100644 index 00000000..6d9dafa7 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatKeyframeSet.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +import java.util.ArrayList; +import android.view.animation.Interpolator; + +import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.FloatKeyframe; + +/** + * This class holds a collection of FloatKeyframe objects and is called by ValueAnimator to calculate + * values between those keyframes for a given animation. The class internal to the animation + * package because it is an implementation detail of how Keyframes are stored and used. + * + *

This type-specific subclass of KeyframeSet, along with the other type-specific subclass for + * int, exists to speed up the getValue() method when there is no custom + * TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the + * Object equivalents of these primitive types.

+ */ +@SuppressWarnings("unchecked") +class FloatKeyframeSet extends KeyframeSet { + private float firstValue; + private float lastValue; + private float deltaValue; + private boolean firstTime = true; + + public FloatKeyframeSet(FloatKeyframe... keyframes) { + super(keyframes); + } + + @Override + public Object getValue(float fraction) { + return getFloatValue(fraction); + } + + @Override + public FloatKeyframeSet clone() { + ArrayList keyframes = mKeyframes; + int numKeyframes = mKeyframes.size(); + FloatKeyframe[] newKeyframes = new FloatKeyframe[numKeyframes]; + for (int i = 0; i < numKeyframes; ++i) { + newKeyframes[i] = (FloatKeyframe) keyframes.get(i).clone(); + } + FloatKeyframeSet newSet = new FloatKeyframeSet(newKeyframes); + return newSet; + } + + public float getFloatValue(float fraction) { + if (mNumKeyframes == 2) { + if (firstTime) { + firstTime = false; + firstValue = ((FloatKeyframe) mKeyframes.get(0)).getFloatValue(); + lastValue = ((FloatKeyframe) mKeyframes.get(1)).getFloatValue(); + deltaValue = lastValue - firstValue; + } + if (mInterpolator != null) { + fraction = mInterpolator.getInterpolation(fraction); + } + if (mEvaluator == null) { + return firstValue + fraction * deltaValue; + } else { + return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).floatValue(); + } + } + if (fraction <= 0f) { + final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0); + final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1); + float prevValue = prevKeyframe.getFloatValue(); + float nextValue = nextKeyframe.getFloatValue(); + float prevFraction = prevKeyframe.getFraction(); + float nextFraction = nextKeyframe.getFraction(); + final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction); + return mEvaluator == null ? + prevValue + intervalFraction * (nextValue - prevValue) : + ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)). + floatValue(); + } else if (fraction >= 1f) { + final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2); + final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 1); + float prevValue = prevKeyframe.getFloatValue(); + float nextValue = nextKeyframe.getFloatValue(); + float prevFraction = prevKeyframe.getFraction(); + float nextFraction = nextKeyframe.getFraction(); + final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction); + return mEvaluator == null ? + prevValue + intervalFraction * (nextValue - prevValue) : + ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)). + floatValue(); + } + FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0); + for (int i = 1; i < mNumKeyframes; ++i) { + FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i); + if (fraction < nextKeyframe.getFraction()) { + final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevKeyframe.getFraction()) / + (nextKeyframe.getFraction() - prevKeyframe.getFraction()); + float prevValue = prevKeyframe.getFloatValue(); + float nextValue = nextKeyframe.getFloatValue(); + return mEvaluator == null ? + prevValue + intervalFraction * (nextValue - prevValue) : + ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)). + floatValue(); + } + prevKeyframe = nextKeyframe; + } + // shouldn't get here + return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue(); + } + +} + diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntEvaluator.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntEvaluator.java new file mode 100644 index 00000000..ed5e79ec --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntEvaluator.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +/** + * This evaluator can be used to perform type interpolation between int values. + */ +public class IntEvaluator implements TypeEvaluator { + + /** + * This function returns the result of linearly interpolating the start and end values, with + * fraction representing the proportion between the start and end values. The + * calculation is a simple parametric calculation: result = x0 + t * (v1 - v0), + * where x0 is startValue, x1 is endValue, + * and t is fraction. + * + * @param fraction The fraction from the starting to the ending values + * @param startValue The start value; should be of type int or + * Integer + * @param endValue The end value; should be of type int or Integer + * @return A linear interpolation between the start and end values, given the + * fraction parameter. + */ + public Integer evaluate(float fraction, Integer startValue, Integer endValue) { + int startInt = startValue; + return (int)(startInt + fraction * (endValue - startInt)); + } +} \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntKeyframeSet.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntKeyframeSet.java new file mode 100644 index 00000000..e9215e7f --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntKeyframeSet.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +import java.util.ArrayList; +import android.view.animation.Interpolator; + +import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.IntKeyframe; + +/** + * This class holds a collection of IntKeyframe objects and is called by ValueAnimator to calculate + * values between those keyframes for a given animation. The class internal to the animation + * package because it is an implementation detail of how Keyframes are stored and used. + * + *

This type-specific subclass of KeyframeSet, along with the other type-specific subclass for + * float, exists to speed up the getValue() method when there is no custom + * TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the + * Object equivalents of these primitive types.

+ */ +@SuppressWarnings("unchecked") +class IntKeyframeSet extends KeyframeSet { + private int firstValue; + private int lastValue; + private int deltaValue; + private boolean firstTime = true; + + public IntKeyframeSet(IntKeyframe... keyframes) { + super(keyframes); + } + + @Override + public Object getValue(float fraction) { + return getIntValue(fraction); + } + + @Override + public IntKeyframeSet clone() { + ArrayList keyframes = mKeyframes; + int numKeyframes = mKeyframes.size(); + IntKeyframe[] newKeyframes = new IntKeyframe[numKeyframes]; + for (int i = 0; i < numKeyframes; ++i) { + newKeyframes[i] = (IntKeyframe) keyframes.get(i).clone(); + } + IntKeyframeSet newSet = new IntKeyframeSet(newKeyframes); + return newSet; + } + + public int getIntValue(float fraction) { + if (mNumKeyframes == 2) { + if (firstTime) { + firstTime = false; + firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue(); + lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue(); + deltaValue = lastValue - firstValue; + } + if (mInterpolator != null) { + fraction = mInterpolator.getInterpolation(fraction); + } + if (mEvaluator == null) { + return firstValue + (int)(fraction * deltaValue); + } else { + return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue(); + } + } + if (fraction <= 0f) { + final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0); + final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(1); + int prevValue = prevKeyframe.getIntValue(); + int nextValue = nextKeyframe.getIntValue(); + float prevFraction = prevKeyframe.getFraction(); + float nextFraction = nextKeyframe.getFraction(); + final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction); + return mEvaluator == null ? + prevValue + (int)(intervalFraction * (nextValue - prevValue)) : + ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)). + intValue(); + } else if (fraction >= 1f) { + final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 2); + final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 1); + int prevValue = prevKeyframe.getIntValue(); + int nextValue = nextKeyframe.getIntValue(); + float prevFraction = prevKeyframe.getFraction(); + float nextFraction = nextKeyframe.getFraction(); + final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction); + return mEvaluator == null ? + prevValue + (int)(intervalFraction * (nextValue - prevValue)) : + ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue(); + } + IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0); + for (int i = 1; i < mNumKeyframes; ++i) { + IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(i); + if (fraction < nextKeyframe.getFraction()) { + final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevKeyframe.getFraction()) / + (nextKeyframe.getFraction() - prevKeyframe.getFraction()); + int prevValue = prevKeyframe.getIntValue(); + int nextValue = nextKeyframe.getIntValue(); + return mEvaluator == null ? + prevValue + (int)(intervalFraction * (nextValue - prevValue)) : + ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)). + intValue(); + } + prevKeyframe = nextKeyframe; + } + // shouldn't get here + return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).intValue(); + } + +} + diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe.java new file mode 100644 index 00000000..ab76fa7f --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe.java @@ -0,0 +1,361 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +import android.view.animation.Interpolator; + +/** + * This class holds a time/value pair for an animation. The Keyframe class is used + * by {@link ValueAnimator} to define the values that the animation target will have over the course + * of the animation. As the time proceeds from one keyframe to the other, the value of the + * target object will animate between the value at the previous keyframe and the value at the + * next keyframe. Each keyframe also holds an optional {@link TimeInterpolator} + * object, which defines the time interpolation over the intervalue preceding the keyframe. + * + *

The Keyframe class itself is abstract. The type-specific factory methods will return + * a subclass of Keyframe specific to the type of value being stored. This is done to improve + * performance when dealing with the most common cases (e.g., float and + * int values). Other types will fall into a more general Keyframe class that + * treats its values as Objects. Unless your animation requires dealing with a custom type + * or a data structure that needs to be animated directly (and evaluated using an implementation + * of {@link TypeEvaluator}), you should stick to using float and int as animations using those + * types have lower runtime overhead than other types.

+ */ +@SuppressWarnings("rawtypes") +public abstract class Keyframe implements Cloneable { + /** + * The time at which mValue will hold true. + */ + float mFraction; + + /** + * The type of the value in this Keyframe. This type is determined at construction time, + * based on the type of the value object passed into the constructor. + */ + Class mValueType; + + /** + * The optional time interpolator for the interval preceding this keyframe. A null interpolator + * (the default) results in linear interpolation over the interval. + */ + private /*Time*/Interpolator mInterpolator = null; + + /** + * Flag to indicate whether this keyframe has a valid value. This flag is used when an + * animation first starts, to populate placeholder keyframes with real values derived + * from the target object. + */ + boolean mHasValue = false; + + /** + * Constructs a Keyframe object with the given time and value. The time defines the + * time, as a proportion of an overall animation's duration, at which the value will hold true + * for the animation. The value for the animation between keyframes will be calculated as + * an interpolation between the values at those keyframes. + * + * @param fraction The time, expressed as a value between 0 and 1, representing the fraction + * of time elapsed of the overall animation duration. + * @param value The value that the object will animate to as the animation time approaches + * the time in this keyframe, and the the value animated from as the time passes the time in + * this keyframe. + */ + public static Keyframe ofInt(float fraction, int value) { + return new IntKeyframe(fraction, value); + } + + /** + * Constructs a Keyframe object with the given time. The value at this time will be derived + * from the target object when the animation first starts (note that this implies that keyframes + * with no initial value must be used as part of an {@link ObjectAnimator}). + * The time defines the + * time, as a proportion of an overall animation's duration, at which the value will hold true + * for the animation. The value for the animation between keyframes will be calculated as + * an interpolation between the values at those keyframes. + * + * @param fraction The time, expressed as a value between 0 and 1, representing the fraction + * of time elapsed of the overall animation duration. + */ + public static Keyframe ofInt(float fraction) { + return new IntKeyframe(fraction); + } + + /** + * Constructs a Keyframe object with the given time and value. The time defines the + * time, as a proportion of an overall animation's duration, at which the value will hold true + * for the animation. The value for the animation between keyframes will be calculated as + * an interpolation between the values at those keyframes. + * + * @param fraction The time, expressed as a value between 0 and 1, representing the fraction + * of time elapsed of the overall animation duration. + * @param value The value that the object will animate to as the animation time approaches + * the time in this keyframe, and the the value animated from as the time passes the time in + * this keyframe. + */ + public static Keyframe ofFloat(float fraction, float value) { + return new FloatKeyframe(fraction, value); + } + + /** + * Constructs a Keyframe object with the given time. The value at this time will be derived + * from the target object when the animation first starts (note that this implies that keyframes + * with no initial value must be used as part of an {@link ObjectAnimator}). + * The time defines the + * time, as a proportion of an overall animation's duration, at which the value will hold true + * for the animation. The value for the animation between keyframes will be calculated as + * an interpolation between the values at those keyframes. + * + * @param fraction The time, expressed as a value between 0 and 1, representing the fraction + * of time elapsed of the overall animation duration. + */ + public static Keyframe ofFloat(float fraction) { + return new FloatKeyframe(fraction); + } + + /** + * Constructs a Keyframe object with the given time and value. The time defines the + * time, as a proportion of an overall animation's duration, at which the value will hold true + * for the animation. The value for the animation between keyframes will be calculated as + * an interpolation between the values at those keyframes. + * + * @param fraction The time, expressed as a value between 0 and 1, representing the fraction + * of time elapsed of the overall animation duration. + * @param value The value that the object will animate to as the animation time approaches + * the time in this keyframe, and the the value animated from as the time passes the time in + * this keyframe. + */ + public static Keyframe ofObject(float fraction, Object value) { + return new ObjectKeyframe(fraction, value); + } + + /** + * Constructs a Keyframe object with the given time. The value at this time will be derived + * from the target object when the animation first starts (note that this implies that keyframes + * with no initial value must be used as part of an {@link ObjectAnimator}). + * The time defines the + * time, as a proportion of an overall animation's duration, at which the value will hold true + * for the animation. The value for the animation between keyframes will be calculated as + * an interpolation between the values at those keyframes. + * + * @param fraction The time, expressed as a value between 0 and 1, representing the fraction + * of time elapsed of the overall animation duration. + */ + public static Keyframe ofObject(float fraction) { + return new ObjectKeyframe(fraction, null); + } + + /** + * Indicates whether this keyframe has a valid value. This method is called internally when + * an {@link ObjectAnimator} first starts; keyframes without values are assigned values at + * that time by deriving the value for the property from the target object. + * + * @return boolean Whether this object has a value assigned. + */ + public boolean hasValue() { + return mHasValue; + } + + /** + * Gets the value for this Keyframe. + * + * @return The value for this Keyframe. + */ + public abstract Object getValue(); + + /** + * Sets the value for this Keyframe. + * + * @param value value for this Keyframe. + */ + public abstract void setValue(Object value); + + /** + * Gets the time for this keyframe, as a fraction of the overall animation duration. + * + * @return The time associated with this keyframe, as a fraction of the overall animation + * duration. This should be a value between 0 and 1. + */ + public float getFraction() { + return mFraction; + } + + /** + * Sets the time for this keyframe, as a fraction of the overall animation duration. + * + * @param fraction time associated with this keyframe, as a fraction of the overall animation + * duration. This should be a value between 0 and 1. + */ + public void setFraction(float fraction) { + mFraction = fraction; + } + + /** + * Gets the optional interpolator for this Keyframe. A value of null indicates + * that there is no interpolation, which is the same as linear interpolation. + * + * @return The optional interpolator for this Keyframe. + */ + public /*Time*/Interpolator getInterpolator() { + return mInterpolator; + } + + /** + * Sets the optional interpolator for this Keyframe. A value of null indicates + * that there is no interpolation, which is the same as linear interpolation. + * + * @return The optional interpolator for this Keyframe. + */ + public void setInterpolator(/*Time*/Interpolator interpolator) { + mInterpolator = interpolator; + } + + /** + * Gets the type of keyframe. This information is used by ValueAnimator to determine the type of + * {@link TypeEvaluator} to use when calculating values between keyframes. The type is based + * on the type of Keyframe created. + * + * @return The type of the value stored in the Keyframe. + */ + public Class getType() { + return mValueType; + } + + @Override + public abstract Keyframe clone(); + + /** + * This internal subclass is used for all types which are not int or float. + */ + static class ObjectKeyframe extends Keyframe { + + /** + * The value of the animation at the time mFraction. + */ + Object mValue; + + ObjectKeyframe(float fraction, Object value) { + mFraction = fraction; + mValue = value; + mHasValue = (value != null); + mValueType = mHasValue ? value.getClass() : Object.class; + } + + public Object getValue() { + return mValue; + } + + public void setValue(Object value) { + mValue = value; + mHasValue = (value != null); + } + + @Override + public ObjectKeyframe clone() { + ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mValue); + kfClone.setInterpolator(getInterpolator()); + return kfClone; + } + } + + /** + * Internal subclass used when the keyframe value is of type int. + */ + static class IntKeyframe extends Keyframe { + + /** + * The value of the animation at the time mFraction. + */ + int mValue; + + IntKeyframe(float fraction, int value) { + mFraction = fraction; + mValue = value; + mValueType = int.class; + mHasValue = true; + } + + IntKeyframe(float fraction) { + mFraction = fraction; + mValueType = int.class; + } + + public int getIntValue() { + return mValue; + } + + public Object getValue() { + return mValue; + } + + public void setValue(Object value) { + if (value != null && value.getClass() == Integer.class) { + mValue = ((Integer)value).intValue(); + mHasValue = true; + } + } + + @Override + public IntKeyframe clone() { + IntKeyframe kfClone = new IntKeyframe(getFraction(), mValue); + kfClone.setInterpolator(getInterpolator()); + return kfClone; + } + } + + /** + * Internal subclass used when the keyframe value is of type float. + */ + static class FloatKeyframe extends Keyframe { + /** + * The value of the animation at the time mFraction. + */ + float mValue; + + FloatKeyframe(float fraction, float value) { + mFraction = fraction; + mValue = value; + mValueType = float.class; + mHasValue = true; + } + + FloatKeyframe(float fraction) { + mFraction = fraction; + mValueType = float.class; + } + + public float getFloatValue() { + return mValue; + } + + public Object getValue() { + return mValue; + } + + public void setValue(Object value) { + if (value != null && value.getClass() == Float.class) { + mValue = ((Float)value).floatValue(); + mHasValue = true; + } + } + + @Override + public FloatKeyframe clone() { + FloatKeyframe kfClone = new FloatKeyframe(getFraction(), mValue); + kfClone.setInterpolator(getInterpolator()); + return kfClone; + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/KeyframeSet.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/KeyframeSet.java new file mode 100644 index 00000000..a71e1ad3 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/KeyframeSet.java @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +import java.util.ArrayList; +import java.util.Arrays; +import android.view.animation.Interpolator; + +import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.FloatKeyframe; +import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.IntKeyframe; +import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.ObjectKeyframe; + +/** + * This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate + * values between those keyframes for a given animation. The class internal to the animation + * package because it is an implementation detail of how Keyframes are stored and used. + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +class KeyframeSet { + + int mNumKeyframes; + + Keyframe mFirstKeyframe; + Keyframe mLastKeyframe; + /*Time*/Interpolator mInterpolator; // only used in the 2-keyframe case + ArrayList mKeyframes; // only used when there are not 2 keyframes + TypeEvaluator mEvaluator; + + + public KeyframeSet(Keyframe... keyframes) { + mNumKeyframes = keyframes.length; + mKeyframes = new ArrayList(); + mKeyframes.addAll(Arrays.asList(keyframes)); + mFirstKeyframe = mKeyframes.get(0); + mLastKeyframe = mKeyframes.get(mNumKeyframes - 1); + mInterpolator = mLastKeyframe.getInterpolator(); + } + + public static KeyframeSet ofInt(int... values) { + int numKeyframes = values.length; + IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)]; + if (numKeyframes == 1) { + keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f); + keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]); + } else { + keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]); + for (int i = 1; i < numKeyframes; ++i) { + keyframes[i] = (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]); + } + } + return new IntKeyframeSet(keyframes); + } + + public static KeyframeSet ofFloat(float... values) { + int numKeyframes = values.length; + FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)]; + if (numKeyframes == 1) { + keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f); + keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]); + } else { + keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]); + for (int i = 1; i < numKeyframes; ++i) { + keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]); + } + } + return new FloatKeyframeSet(keyframes); + } + + public static KeyframeSet ofKeyframe(Keyframe... keyframes) { + // if all keyframes of same primitive type, create the appropriate KeyframeSet + int numKeyframes = keyframes.length; + boolean hasFloat = false; + boolean hasInt = false; + boolean hasOther = false; + for (int i = 0; i < numKeyframes; ++i) { + if (keyframes[i] instanceof FloatKeyframe) { + hasFloat = true; + } else if (keyframes[i] instanceof IntKeyframe) { + hasInt = true; + } else { + hasOther = true; + } + } + if (hasFloat && !hasInt && !hasOther) { + FloatKeyframe floatKeyframes[] = new FloatKeyframe[numKeyframes]; + for (int i = 0; i < numKeyframes; ++i) { + floatKeyframes[i] = (FloatKeyframe) keyframes[i]; + } + return new FloatKeyframeSet(floatKeyframes); + } else if (hasInt && !hasFloat && !hasOther) { + IntKeyframe intKeyframes[] = new IntKeyframe[numKeyframes]; + for (int i = 0; i < numKeyframes; ++i) { + intKeyframes[i] = (IntKeyframe) keyframes[i]; + } + return new IntKeyframeSet(intKeyframes); + } else { + return new KeyframeSet(keyframes); + } + } + + public static KeyframeSet ofObject(Object... values) { + int numKeyframes = values.length; + ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes,2)]; + if (numKeyframes == 1) { + keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f); + keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]); + } else { + keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]); + for (int i = 1; i < numKeyframes; ++i) { + keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]); + } + } + return new KeyframeSet(keyframes); + } + + /** + * Sets the TypeEvaluator to be used when calculating animated values. This object + * is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet, + * both of which assume their own evaluator to speed up calculations with those primitive + * types. + * + * @param evaluator The TypeEvaluator to be used to calculate animated values. + */ + public void setEvaluator(TypeEvaluator evaluator) { + mEvaluator = evaluator; + } + + @Override + public KeyframeSet clone() { + ArrayList keyframes = mKeyframes; + int numKeyframes = mKeyframes.size(); + Keyframe[] newKeyframes = new Keyframe[numKeyframes]; + for (int i = 0; i < numKeyframes; ++i) { + newKeyframes[i] = keyframes.get(i).clone(); + } + KeyframeSet newSet = new KeyframeSet(newKeyframes); + return newSet; + } + + /** + * Gets the animated value, given the elapsed fraction of the animation (interpolated by the + * animation's interpolator) and the evaluator used to calculate in-between values. This + * function maps the input fraction to the appropriate keyframe interval and a fraction + * between them and returns the interpolated value. Note that the input fraction may fall + * outside the [0-1] bounds, if the animation's interpolator made that happen (e.g., a + * spring interpolation that might send the fraction past 1.0). We handle this situation by + * just using the two keyframes at the appropriate end when the value is outside those bounds. + * + * @param fraction The elapsed fraction of the animation + * @return The animated value. + */ + public Object getValue(float fraction) { + + // Special-case optimization for the common case of only two keyframes + if (mNumKeyframes == 2) { + if (mInterpolator != null) { + fraction = mInterpolator.getInterpolation(fraction); + } + return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(), + mLastKeyframe.getValue()); + } + if (fraction <= 0f) { + final Keyframe nextKeyframe = mKeyframes.get(1); + final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + final float prevFraction = mFirstKeyframe.getFraction(); + float intervalFraction = (fraction - prevFraction) / + (nextKeyframe.getFraction() - prevFraction); + return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(), + nextKeyframe.getValue()); + } else if (fraction >= 1f) { + final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2); + final /*Time*/Interpolator interpolator = mLastKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + final float prevFraction = prevKeyframe.getFraction(); + float intervalFraction = (fraction - prevFraction) / + (mLastKeyframe.getFraction() - prevFraction); + return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(), + mLastKeyframe.getValue()); + } + Keyframe prevKeyframe = mFirstKeyframe; + for (int i = 1; i < mNumKeyframes; ++i) { + Keyframe nextKeyframe = mKeyframes.get(i); + if (fraction < nextKeyframe.getFraction()) { + final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + final float prevFraction = prevKeyframe.getFraction(); + float intervalFraction = (fraction - prevFraction) / + (nextKeyframe.getFraction() - prevFraction); + return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(), + nextKeyframe.getValue()); + } + prevKeyframe = nextKeyframe; + } + // shouldn't reach here + return mLastKeyframe.getValue(); + } + + @Override + public String toString() { + String returnVal = " "; + for (int i = 0; i < mNumKeyframes; ++i) { + returnVal += mKeyframes.get(i).getValue() + " "; + } + return returnVal; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/ObjectAnimator.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/ObjectAnimator.java new file mode 100644 index 00000000..21d15c02 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/ObjectAnimator.java @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +import android.util.Log; +//import android.util.Property; + +//import java.lang.reflect.Method; +import java.util.ArrayList; + +/** + * This subclass of {@link ValueAnimator} provides support for animating properties on target objects. + * The constructors of this class take parameters to define the target object that will be animated + * as well as the name of the property that will be animated. Appropriate set/get functions + * are then determined internally and the animation will call these functions as necessary to + * animate the property. + * + * @see #setPropertyName(String) + * + */ +@SuppressWarnings("rawtypes") +public final class ObjectAnimator extends ValueAnimator { + private static final boolean DBG = false; + + // The target object on which the property exists, set in the constructor + private Object mTarget; + + private String mPropertyName; + + //private Property mProperty; + + /** + * Sets the name of the property that will be animated. This name is used to derive + * a setter function that will be called to set animated values. + * For example, a property name of foo will result + * in a call to the function setFoo() on the target object. If either + * valueFrom or valueTo is null, then a getter function will + * also be derived and called. + * + *

For best performance of the mechanism that calls the setter function determined by the + * name of the property being animated, use float or int typed values, + * and make the setter function for those properties have a void return value. This + * will cause the code to take an optimized path for these constrained circumstances. Other + * property types and return types will work, but will have more overhead in processing + * the requests due to normal reflection mechanisms.

+ * + *

Note that the setter function derived from this property name + * must take the same parameter type as the + * valueFrom and valueTo properties, otherwise the call to + * the setter function will fail.

+ * + *

If this ObjectAnimator has been set up to animate several properties together, + * using more than one PropertyValuesHolder objects, then setting the propertyName simply + * sets the propertyName in the first of those PropertyValuesHolder objects.

+ * + * @param propertyName The name of the property being animated. Should not be null. + */ + public void setPropertyName(String propertyName) { + // mValues could be null if this is being constructed piecemeal. Just record the + // propertyName to be used later when setValues() is called if so. + if (mValues != null) { + PropertyValuesHolder valuesHolder = mValues[0]; + String oldName = valuesHolder.getPropertyName(); + valuesHolder.setPropertyName(propertyName); + mValuesMap.remove(oldName); + mValuesMap.put(propertyName, valuesHolder); + } + mPropertyName = propertyName; + // New property/values/target should cause re-initialization prior to starting + mInitialized = false; + } + + /** + * Sets the property that will be animated. Property objects will take precedence over + * properties specified by the {@link #setPropertyName(String)} method. Animations should + * be set up to use one or the other, not both. + * + * @param property The property being animated. Should not be null. + */ + //public void setProperty(Property property) { + // // mValues could be null if this is being constructed piecemeal. Just record the + // // propertyName to be used later when setValues() is called if so. + // if (mValues != null) { + // PropertyValuesHolder valuesHolder = mValues[0]; + // String oldName = valuesHolder.getPropertyName(); + // valuesHolder.setProperty(property); + // mValuesMap.remove(oldName); + // mValuesMap.put(mPropertyName, valuesHolder); + // } + // if (mProperty != null) { + // mPropertyName = property.getName(); + // } + // mProperty = property; + // // New property/values/target should cause re-initialization prior to starting + // mInitialized = false; + //} + + /** + * Gets the name of the property that will be animated. This name will be used to derive + * a setter function that will be called to set animated values. + * For example, a property name of foo will result + * in a call to the function setFoo() on the target object. If either + * valueFrom or valueTo is null, then a getter function will + * also be derived and called. + */ + public String getPropertyName() { + return mPropertyName; + } + + /** + * Creates a new ObjectAnimator object. This default constructor is primarily for + * use internally; the other constructors which take parameters are more generally + * useful. + */ + public ObjectAnimator() { + } + + /** + * Private utility constructor that initializes the target object and name of the + * property being animated. + * + * @param target The object whose property is to be animated. This object should + * have a public method on it called setName(), where name is + * the value of the propertyName parameter. + * @param propertyName The name of the property being animated. + */ + private ObjectAnimator(Object target, String propertyName) { + mTarget = target; + setPropertyName(propertyName); + } + + /** + * Private utility constructor that initializes the target object and property being animated. + * + * @param target The object whose property is to be animated. + * @param property The property being animated. + */ + //private ObjectAnimator(T target, Property property) { + // mTarget = target; + // setProperty(property); + //} + + /** + * Constructs and returns an ObjectAnimator that animates between int values. A single + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). + * + * @param target The object whose property is to be animated. This object should + * have a public method on it called setName(), where name is + * the value of the propertyName parameter. + * @param propertyName The name of the property being animated. + * @param values A set of values that the animation will animate between over time. + * @return An ObjectAnimator object that is set up to animate between the given values. + */ + public static ObjectAnimator ofInt(Object target, String propertyName, int... values) { + ObjectAnimator anim = new ObjectAnimator(target, propertyName); + anim.setIntValues(values); + return anim; + } + + /** + * Constructs and returns an ObjectAnimator that animates between int values. A single + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). + * + * @param target The object whose property is to be animated. + * @param property The property being animated. + * @param values A set of values that the animation will animate between over time. + * @return An ObjectAnimator object that is set up to animate between the given values. + */ + //public static ObjectAnimator ofInt(T target, Property property, int... values) { + // ObjectAnimator anim = new ObjectAnimator(target, property); + // anim.setIntValues(values); + // return anim; + //} + + /** + * Constructs and returns an ObjectAnimator that animates between float values. A single + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). + * + * @param target The object whose property is to be animated. This object should + * have a public method on it called setName(), where name is + * the value of the propertyName parameter. + * @param propertyName The name of the property being animated. + * @param values A set of values that the animation will animate between over time. + * @return An ObjectAnimator object that is set up to animate between the given values. + */ + public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { + ObjectAnimator anim = new ObjectAnimator(target, propertyName); + anim.setFloatValues(values); + return anim; + } + + /** + * Constructs and returns an ObjectAnimator that animates between float values. A single + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). + * + * @param target The object whose property is to be animated. + * @param property The property being animated. + * @param values A set of values that the animation will animate between over time. + * @return An ObjectAnimator object that is set up to animate between the given values. + */ + //public static ObjectAnimator ofFloat(T target, Property property, + // float... values) { + // ObjectAnimator anim = new ObjectAnimator(target, property); + // anim.setFloatValues(values); + // return anim; + //} + + /** + * Constructs and returns an ObjectAnimator that animates between Object values. A single + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). + * + * @param target The object whose property is to be animated. This object should + * have a public method on it called setName(), where name is + * the value of the propertyName parameter. + * @param propertyName The name of the property being animated. + * @param evaluator A TypeEvaluator that will be called on each animation frame to + * provide the necessary interpolation between the Object values to derive the animated + * value. + * @param values A set of values that the animation will animate between over time. + * @return An ObjectAnimator object that is set up to animate between the given values. + */ + public static ObjectAnimator ofObject(Object target, String propertyName, + TypeEvaluator evaluator, Object... values) { + ObjectAnimator anim = new ObjectAnimator(target, propertyName); + anim.setObjectValues(values); + anim.setEvaluator(evaluator); + return anim; + } + + /** + * Constructs and returns an ObjectAnimator that animates between Object values. A single + * value implies that that value is the one being animated to. Two values imply a starting + * and ending values. More than two values imply a starting value, values to animate through + * along the way, and an ending value (these values will be distributed evenly across + * the duration of the animation). + * + * @param target The object whose property is to be animated. + * @param property The property being animated. + * @param evaluator A TypeEvaluator that will be called on each animation frame to + * provide the necessary interpolation between the Object values to derive the animated + * value. + * @param values A set of values that the animation will animate between over time. + * @return An ObjectAnimator object that is set up to animate between the given values. + */ + //public static ObjectAnimator ofObject(T target, Property property, + // TypeEvaluator evaluator, V... values) { + // ObjectAnimator anim = new ObjectAnimator(target, property); + // anim.setObjectValues(values); + // anim.setEvaluator(evaluator); + // return anim; + //} + + /** + * Constructs and returns an ObjectAnimator that animates between the sets of values specified + * in PropertyValueHolder objects. This variant should be used when animating + * several properties at once with the same ObjectAnimator, since PropertyValuesHolder allows + * you to associate a set of animation values with a property name. + * + * @param target The object whose property is to be animated. Depending on how the + * PropertyValuesObjects were constructed, the target object should either have the {@link + * android.util.Property} objects used to construct the PropertyValuesHolder objects or (if the + * PropertyValuesHOlder objects were created with property names) the target object should have + * public methods on it called setName(), where name is the name of + * the property passed in as the propertyName parameter for each of the + * PropertyValuesHolder objects. + * @param values A set of PropertyValuesHolder objects whose values will be animated between + * over time. + * @return An ObjectAnimator object that is set up to animate between the given values. + */ + public static ObjectAnimator ofPropertyValuesHolder(Object target, + PropertyValuesHolder... values) { + ObjectAnimator anim = new ObjectAnimator(); + anim.mTarget = target; + anim.setValues(values); + return anim; + } + + @Override + public void setIntValues(int... values) { + if (mValues == null || mValues.length == 0) { + // No values yet - this animator is being constructed piecemeal. Init the values with + // whatever the current propertyName is + //if (mProperty != null) { + // setValues(PropertyValuesHolder.ofInt(mProperty, values)); + //} else { + setValues(PropertyValuesHolder.ofInt(mPropertyName, values)); + //} + } else { + super.setIntValues(values); + } + } + + @Override + public void setFloatValues(float... values) { + if (mValues == null || mValues.length == 0) { + // No values yet - this animator is being constructed piecemeal. Init the values with + // whatever the current propertyName is + //if (mProperty != null) { + // setValues(PropertyValuesHolder.ofFloat(mProperty, values)); + //} else { + setValues(PropertyValuesHolder.ofFloat(mPropertyName, values)); + //} + } else { + super.setFloatValues(values); + } + } + + @Override + public void setObjectValues(Object... values) { + if (mValues == null || mValues.length == 0) { + // No values yet - this animator is being constructed piecemeal. Init the values with + // whatever the current propertyName is + //if (mProperty != null) { + // setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator)null, values)); + //} else { + setValues(PropertyValuesHolder.ofObject(mPropertyName, (TypeEvaluator)null, values)); + //} + } else { + super.setObjectValues(values); + } + } + + @Override + public void start() { + if (DBG) { + Log.d("ObjectAnimator", "Anim target, duration: " + mTarget + ", " + getDuration()); + for (int i = 0; i < mValues.length; ++i) { + PropertyValuesHolder pvh = mValues[i]; + ArrayList keyframes = pvh.mKeyframeSet.mKeyframes; + Log.d("ObjectAnimator", " Values[" + i + "]: " + + pvh.getPropertyName() + ", " + keyframes.get(0).getValue() + ", " + + keyframes.get(pvh.mKeyframeSet.mNumKeyframes - 1).getValue()); + } + } + super.start(); + } + + /** + * This function is called immediately before processing the first animation + * frame of an animation. If there is a nonzero startDelay, the + * function is called after that delay ends. + * It takes care of the final initialization steps for the + * animation. This includes setting mEvaluator, if the user has not yet + * set it up, and the setter/getter methods, if the user did not supply + * them. + * + *

Overriders of this method should call the superclass method to cause + * internal mechanisms to be set up correctly.

+ */ + @Override + void initAnimation() { + if (!mInitialized) { + // mValueType may change due to setter/getter setup; do this before calling super.init(), + // which uses mValueType to set up the default type evaluator. + int numValues = mValues.length; + for (int i = 0; i < numValues; ++i) { + mValues[i].setupSetterAndGetter(mTarget); + } + super.initAnimation(); + } + } + + /** + * Sets the length of the animation. The default duration is 300 milliseconds. + * + * @param duration The length of the animation, in milliseconds. + * @return ObjectAnimator The object called with setDuration(). This return + * value makes it easier to compose statements together that construct and then set the + * duration, as in + * ObjectAnimator.ofInt(target, propertyName, 0, 10).setDuration(500).start(). + */ + @Override + public ObjectAnimator setDuration(long duration) { + super.setDuration(duration); + return this; + } + + + /** + * The target object whose property will be animated by this animation + * + * @return The object being animated + */ + public Object getTarget() { + return mTarget; + } + + /** + * Sets the target object whose property will be animated by this animation + * + * @param target The object being animated + */ + @Override + public void setTarget(Object target) { + if (mTarget != target) { + final Object oldTarget = mTarget; + mTarget = target; + if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) { + return; + } + // New target type should cause re-initialization prior to starting + mInitialized = false; + } + } + + @Override + public void setupStartValues() { + initAnimation(); + int numValues = mValues.length; + for (int i = 0; i < numValues; ++i) { + mValues[i].setupStartValue(mTarget); + } + } + + @Override + public void setupEndValues() { + initAnimation(); + int numValues = mValues.length; + for (int i = 0; i < numValues; ++i) { + mValues[i].setupEndValue(mTarget); + } + } + + /** + * This method is called with the elapsed fraction of the animation during every + * animation frame. This function turns the elapsed fraction into an interpolated fraction + * and then into an animated value (from the evaluator. The function is called mostly during + * animation updates, but it is also called when the end() + * function is called, to set the final value on the property. + * + *

Overrides of this method must call the superclass to perform the calculation + * of the animated value.

+ * + * @param fraction The elapsed fraction of the animation. + */ + @Override + void animateValue(float fraction) { + super.animateValue(fraction); + int numValues = mValues.length; + for (int i = 0; i < numValues; ++i) { + mValues[i].setAnimatedValue(mTarget); + } + } + + @Override + public ObjectAnimator clone() { + final ObjectAnimator anim = (ObjectAnimator) super.clone(); + return anim; + } + + @Override + public String toString() { + String returnVal = "ObjectAnimator@" + Integer.toHexString(hashCode()) + ", target " + + mTarget; + if (mValues != null) { + for (int i = 0; i < mValues.length; ++i) { + returnVal += "\n " + mValues[i].toString(); + } + } + return returnVal; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java new file mode 100644 index 00000000..84f7504a --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java @@ -0,0 +1,1012 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +//import android.util.FloatProperty; +//import android.util.IntProperty; +import android.util.Log; +//import android.util.Property; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * This class holds information about a property and the values that that property + * should take on during an animation. PropertyValuesHolder objects can be used to create + * animations with ValueAnimator or ObjectAnimator that operate on several different properties + * in parallel. + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public class PropertyValuesHolder implements Cloneable { + + /** + * The name of the property associated with the values. This need not be a real property, + * unless this object is being used with ObjectAnimator. But this is the name by which + * aniamted values are looked up with getAnimatedValue(String) in ValueAnimator. + */ + String mPropertyName; + + /** + * @hide + */ + //protected Property mProperty; + + /** + * The setter function, if needed. ObjectAnimator hands off this functionality to + * PropertyValuesHolder, since it holds all of the per-property information. This + * property is automatically + * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator. + */ + Method mSetter = null; + + /** + * The getter function, if needed. ObjectAnimator hands off this functionality to + * PropertyValuesHolder, since it holds all of the per-property information. This + * property is automatically + * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator. + * The getter is only derived and used if one of the values is null. + */ + private Method mGetter = null; + + /** + * The type of values supplied. This information is used both in deriving the setter/getter + * functions and in deriving the type of TypeEvaluator. + */ + Class mValueType; + + /** + * The set of keyframes (time/value pairs) that define this animation. + */ + KeyframeSet mKeyframeSet = null; + + + // type evaluators for the primitive types handled by this implementation + private static final TypeEvaluator sIntEvaluator = new IntEvaluator(); + private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator(); + + // We try several different types when searching for appropriate setter/getter functions. + // The caller may have supplied values in a type that does not match the setter/getter + // functions (such as the integers 0 and 1 to represent floating point values for alpha). + // Also, the use of generics in constructors means that we end up with the Object versions + // of primitive types (Float vs. float). But most likely, the setter/getter functions + // will take primitive types instead. + // So we supply an ordered array of other types to try before giving up. + private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class, + Double.class, Integer.class}; + private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class, + Float.class, Double.class}; + private static Class[] DOUBLE_VARIANTS = {double.class, Double.class, float.class, int.class, + Float.class, Integer.class}; + + // These maps hold all property entries for a particular class. This map + // is used to speed up property/setter/getter lookups for a given class/property + // combination. No need to use reflection on the combination more than once. + private static final HashMap> sSetterPropertyMap = + new HashMap>(); + private static final HashMap> sGetterPropertyMap = + new HashMap>(); + + // This lock is used to ensure that only one thread is accessing the property maps + // at a time. + final ReentrantReadWriteLock mPropertyMapLock = new ReentrantReadWriteLock(); + + // Used to pass single value to varargs parameter in setter invocation + final Object[] mTmpValueArray = new Object[1]; + + /** + * The type evaluator used to calculate the animated values. This evaluator is determined + * automatically based on the type of the start/end objects passed into the constructor, + * but the system only knows about the primitive types int and float. Any other + * type will need to set the evaluator to a custom evaluator for that type. + */ + private TypeEvaluator mEvaluator; + + /** + * The value most recently calculated by calculateValue(). This is set during + * that function and might be retrieved later either by ValueAnimator.animatedValue() or + * by the property-setting logic in ObjectAnimator.animatedValue(). + */ + private Object mAnimatedValue; + + /** + * Internal utility constructor, used by the factory methods to set the property name. + * @param propertyName The name of the property for this holder. + */ + private PropertyValuesHolder(String propertyName) { + mPropertyName = propertyName; + } + + /** + * Internal utility constructor, used by the factory methods to set the property. + * @param property The property for this holder. + */ + //private PropertyValuesHolder(Property property) { + // mProperty = property; + // if (property != null) { + // mPropertyName = property.getName(); + // } + //} + + /** + * Constructs and returns a PropertyValuesHolder with a given property name and + * set of int values. + * @param propertyName The name of the property being animated. + * @param values The values that the named property will animate between. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + */ + public static PropertyValuesHolder ofInt(String propertyName, int... values) { + return new IntPropertyValuesHolder(propertyName, values); + } + + /** + * Constructs and returns a PropertyValuesHolder with a given property and + * set of int values. + * @param property The property being animated. Should not be null. + * @param values The values that the property will animate between. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + */ + //public static PropertyValuesHolder ofInt(Property property, int... values) { + // return new IntPropertyValuesHolder(property, values); + //} + + /** + * Constructs and returns a PropertyValuesHolder with a given property name and + * set of float values. + * @param propertyName The name of the property being animated. + * @param values The values that the named property will animate between. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + */ + public static PropertyValuesHolder ofFloat(String propertyName, float... values) { + return new FloatPropertyValuesHolder(propertyName, values); + } + + /** + * Constructs and returns a PropertyValuesHolder with a given property and + * set of float values. + * @param property The property being animated. Should not be null. + * @param values The values that the property will animate between. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + */ + //public static PropertyValuesHolder ofFloat(Property property, float... values) { + // return new FloatPropertyValuesHolder(property, values); + //} + + /** + * Constructs and returns a PropertyValuesHolder with a given property name and + * set of Object values. This variant also takes a TypeEvaluator because the system + * cannot automatically interpolate between objects of unknown type. + * + * @param propertyName The name of the property being animated. + * @param evaluator A TypeEvaluator that will be called on each animation frame to + * provide the necessary interpolation between the Object values to derive the animated + * value. + * @param values The values that the named property will animate between. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + */ + public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator, + Object... values) { + PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName); + pvh.setObjectValues(values); + pvh.setEvaluator(evaluator); + return pvh; + } + + /** + * Constructs and returns a PropertyValuesHolder with a given property and + * set of Object values. This variant also takes a TypeEvaluator because the system + * cannot automatically interpolate between objects of unknown type. + * + * @param property The property being animated. Should not be null. + * @param evaluator A TypeEvaluator that will be called on each animation frame to + * provide the necessary interpolation between the Object values to derive the animated + * value. + * @param values The values that the property will animate between. + * @return PropertyValuesHolder The constructed PropertyValuesHolder object. + */ + //public static PropertyValuesHolder ofObject(Property property, + // TypeEvaluator evaluator, V... values) { + // PropertyValuesHolder pvh = new PropertyValuesHolder(property); + // pvh.setObjectValues(values); + // pvh.setEvaluator(evaluator); + // return pvh; + //} + + /** + * Constructs and returns a PropertyValuesHolder object with the specified property name and set + * of values. These values can be of any type, but the type should be consistent so that + * an appropriate {@link android.animation.TypeEvaluator} can be found that matches + * the common type. + *

If there is only one value, it is assumed to be the end value of an animation, + * and an initial value will be derived, if possible, by calling a getter function + * on the object. Also, if any value is null, the value will be filled in when the animation + * starts in the same way. This mechanism of automatically getting null values only works + * if the PropertyValuesHolder object is used in conjunction + * {@link ObjectAnimator}, and with a getter function + * derived automatically from propertyName, since otherwise PropertyValuesHolder has + * no way of determining what the value should be. + * @param propertyName The name of the property associated with this set of values. This + * can be the actual property name to be used when using a ObjectAnimator object, or + * just a name used to get animated values, such as if this object is used with an + * ValueAnimator object. + * @param values The set of values to animate between. + */ + public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) { + KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values); + if (keyframeSet instanceof IntKeyframeSet) { + return new IntPropertyValuesHolder(propertyName, (IntKeyframeSet) keyframeSet); + } else if (keyframeSet instanceof FloatKeyframeSet) { + return new FloatPropertyValuesHolder(propertyName, (FloatKeyframeSet) keyframeSet); + } + else { + PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName); + pvh.mKeyframeSet = keyframeSet; + pvh.mValueType = values[0].getType(); + return pvh; + } + } + + /** + * Constructs and returns a PropertyValuesHolder object with the specified property and set + * of values. These values can be of any type, but the type should be consistent so that + * an appropriate {@link android.animation.TypeEvaluator} can be found that matches + * the common type. + *

If there is only one value, it is assumed to be the end value of an animation, + * and an initial value will be derived, if possible, by calling the property's + * {@link android.util.Property#get(Object)} function. + * Also, if any value is null, the value will be filled in when the animation + * starts in the same way. This mechanism of automatically getting null values only works + * if the PropertyValuesHolder object is used in conjunction with + * {@link ObjectAnimator}, since otherwise PropertyValuesHolder has + * no way of determining what the value should be. + * @param property The property associated with this set of values. Should not be null. + * @param values The set of values to animate between. + */ + //public static PropertyValuesHolder ofKeyframe(Property property, Keyframe... values) { + // KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values); + // if (keyframeSet instanceof IntKeyframeSet) { + // return new IntPropertyValuesHolder(property, (IntKeyframeSet) keyframeSet); + // } else if (keyframeSet instanceof FloatKeyframeSet) { + // return new FloatPropertyValuesHolder(property, (FloatKeyframeSet) keyframeSet); + // } + // else { + // PropertyValuesHolder pvh = new PropertyValuesHolder(property); + // pvh.mKeyframeSet = keyframeSet; + // pvh.mValueType = ((Keyframe)values[0]).getType(); + // return pvh; + // } + //} + + /** + * Set the animated values for this object to this set of ints. + * If there is only one value, it is assumed to be the end value of an animation, + * and an initial value will be derived, if possible, by calling a getter function + * on the object. Also, if any value is null, the value will be filled in when the animation + * starts in the same way. This mechanism of automatically getting null values only works + * if the PropertyValuesHolder object is used in conjunction + * {@link ObjectAnimator}, and with a getter function + * derived automatically from propertyName, since otherwise PropertyValuesHolder has + * no way of determining what the value should be. + * + * @param values One or more values that the animation will animate between. + */ + public void setIntValues(int... values) { + mValueType = int.class; + mKeyframeSet = KeyframeSet.ofInt(values); + } + + /** + * Set the animated values for this object to this set of floats. + * If there is only one value, it is assumed to be the end value of an animation, + * and an initial value will be derived, if possible, by calling a getter function + * on the object. Also, if any value is null, the value will be filled in when the animation + * starts in the same way. This mechanism of automatically getting null values only works + * if the PropertyValuesHolder object is used in conjunction + * {@link ObjectAnimator}, and with a getter function + * derived automatically from propertyName, since otherwise PropertyValuesHolder has + * no way of determining what the value should be. + * + * @param values One or more values that the animation will animate between. + */ + public void setFloatValues(float... values) { + mValueType = float.class; + mKeyframeSet = KeyframeSet.ofFloat(values); + } + + /** + * Set the animated values for this object to this set of Keyframes. + * + * @param values One or more values that the animation will animate between. + */ + public void setKeyframes(Keyframe... values) { + int numKeyframes = values.length; + Keyframe keyframes[] = new Keyframe[Math.max(numKeyframes,2)]; + mValueType = values[0].getType(); + for (int i = 0; i < numKeyframes; ++i) { + keyframes[i] = values[i]; + } + mKeyframeSet = new KeyframeSet(keyframes); + } + + /** + * Set the animated values for this object to this set of Objects. + * If there is only one value, it is assumed to be the end value of an animation, + * and an initial value will be derived, if possible, by calling a getter function + * on the object. Also, if any value is null, the value will be filled in when the animation + * starts in the same way. This mechanism of automatically getting null values only works + * if the PropertyValuesHolder object is used in conjunction + * {@link ObjectAnimator}, and with a getter function + * derived automatically from propertyName, since otherwise PropertyValuesHolder has + * no way of determining what the value should be. + * + * @param values One or more values that the animation will animate between. + */ + public void setObjectValues(Object... values) { + mValueType = values[0].getClass(); + mKeyframeSet = KeyframeSet.ofObject(values); + } + + /** + * Determine the setter or getter function using the JavaBeans convention of setFoo or + * getFoo for a property named 'foo'. This function figures out what the name of the + * function should be and uses reflection to find the Method with that name on the + * target object. + * + * @param targetClass The class to search for the method + * @param prefix "set" or "get", depending on whether we need a setter or getter. + * @param valueType The type of the parameter (in the case of a setter). This type + * is derived from the values set on this PropertyValuesHolder. This type is used as + * a first guess at the parameter type, but we check for methods with several different + * types to avoid problems with slight mis-matches between supplied values and actual + * value types used on the setter. + * @return Method the method associated with mPropertyName. + */ + private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) { + // TODO: faster implementation... + Method returnVal = null; + String methodName = getMethodName(prefix, mPropertyName); + Class args[] = null; + if (valueType == null) { + try { + returnVal = targetClass.getMethod(methodName, args); + } catch (NoSuchMethodException e) { + Log.e("PropertyValuesHolder", targetClass.getSimpleName() + " - " + + "Couldn't find no-arg method for property " + mPropertyName + ": " + e); + } + } else { + args = new Class[1]; + Class typeVariants[]; + if (mValueType.equals(Float.class)) { + typeVariants = FLOAT_VARIANTS; + } else if (mValueType.equals(Integer.class)) { + typeVariants = INTEGER_VARIANTS; + } else if (mValueType.equals(Double.class)) { + typeVariants = DOUBLE_VARIANTS; + } else { + typeVariants = new Class[1]; + typeVariants[0] = mValueType; + } + for (Class typeVariant : typeVariants) { + args[0] = typeVariant; + try { + returnVal = targetClass.getMethod(methodName, args); + // change the value type to suit + mValueType = typeVariant; + return returnVal; + } catch (NoSuchMethodException e) { + // Swallow the error and keep trying other variants + } + } + // If we got here, then no appropriate function was found + Log.e("PropertyValuesHolder", + "Couldn't find " + prefix + "ter property " + mPropertyName + + " for " + targetClass.getSimpleName() + + " with value type "+ mValueType); + } + + return returnVal; + } + + + /** + * Returns the setter or getter requested. This utility function checks whether the + * requested method exists in the propertyMapMap cache. If not, it calls another + * utility function to request the Method from the targetClass directly. + * @param targetClass The Class on which the requested method should exist. + * @param propertyMapMap The cache of setters/getters derived so far. + * @param prefix "set" or "get", for the setter or getter. + * @param valueType The type of parameter passed into the method (null for getter). + * @return Method the method associated with mPropertyName. + */ + private Method setupSetterOrGetter(Class targetClass, + HashMap> propertyMapMap, + String prefix, Class valueType) { + Method setterOrGetter = null; + try { + // Have to lock property map prior to reading it, to guard against + // another thread putting something in there after we've checked it + // but before we've added an entry to it + mPropertyMapLock.writeLock().lock(); + HashMap propertyMap = propertyMapMap.get(targetClass); + if (propertyMap != null) { + setterOrGetter = propertyMap.get(mPropertyName); + } + if (setterOrGetter == null) { + setterOrGetter = getPropertyFunction(targetClass, prefix, valueType); + if (propertyMap == null) { + propertyMap = new HashMap(); + propertyMapMap.put(targetClass, propertyMap); + } + propertyMap.put(mPropertyName, setterOrGetter); + } + } finally { + mPropertyMapLock.writeLock().unlock(); + } + return setterOrGetter; + } + + /** + * Utility function to get the setter from targetClass + * @param targetClass The Class on which the requested method should exist. + */ + void setupSetter(Class targetClass) { + mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType); + } + + /** + * Utility function to get the getter from targetClass + */ + private void setupGetter(Class targetClass) { + mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null); + } + + /** + * Internal function (called from ObjectAnimator) to set up the setter and getter + * prior to running the animation. If the setter has not been manually set for this + * object, it will be derived automatically given the property name, target object, and + * types of values supplied. If no getter has been set, it will be supplied iff any of the + * supplied values was null. If there is a null value, then the getter (supplied or derived) + * will be called to set those null values to the current value of the property + * on the target object. + * @param target The object on which the setter (and possibly getter) exist. + */ + void setupSetterAndGetter(Object target) { + //if (mProperty != null) { + // // check to make sure that mProperty is on the class of target + // try { + // Object testValue = mProperty.get(target); + // for (Keyframe kf : mKeyframeSet.mKeyframes) { + // if (!kf.hasValue()) { + // kf.setValue(mProperty.get(target)); + // } + // } + // return; + // } catch (ClassCastException e) { + // Log.e("PropertyValuesHolder","No such property (" + mProperty.getName() + + // ") on target object " + target + ". Trying reflection instead"); + // mProperty = null; + // } + //} + Class targetClass = target.getClass(); + if (mSetter == null) { + setupSetter(targetClass); + } + for (Keyframe kf : mKeyframeSet.mKeyframes) { + if (!kf.hasValue()) { + if (mGetter == null) { + setupGetter(targetClass); + } + try { + kf.setValue(mGetter.invoke(target)); + } catch (InvocationTargetException e) { + Log.e("PropertyValuesHolder", e.toString()); + } catch (IllegalAccessException e) { + Log.e("PropertyValuesHolder", e.toString()); + } + } + } + } + + /** + * Utility function to set the value stored in a particular Keyframe. The value used is + * whatever the value is for the property name specified in the keyframe on the target object. + * + * @param target The target object from which the current value should be extracted. + * @param kf The keyframe which holds the property name and value. + */ + private void setupValue(Object target, Keyframe kf) { + //if (mProperty != null) { + // kf.setValue(mProperty.get(target)); + //} + try { + if (mGetter == null) { + Class targetClass = target.getClass(); + setupGetter(targetClass); + } + kf.setValue(mGetter.invoke(target)); + } catch (InvocationTargetException e) { + Log.e("PropertyValuesHolder", e.toString()); + } catch (IllegalAccessException e) { + Log.e("PropertyValuesHolder", e.toString()); + } + } + + /** + * This function is called by ObjectAnimator when setting the start values for an animation. + * The start values are set according to the current values in the target object. The + * property whose value is extracted is whatever is specified by the propertyName of this + * PropertyValuesHolder object. + * + * @param target The object which holds the start values that should be set. + */ + void setupStartValue(Object target) { + setupValue(target, mKeyframeSet.mKeyframes.get(0)); + } + + /** + * This function is called by ObjectAnimator when setting the end values for an animation. + * The end values are set according to the current values in the target object. The + * property whose value is extracted is whatever is specified by the propertyName of this + * PropertyValuesHolder object. + * + * @param target The object which holds the start values that should be set. + */ + void setupEndValue(Object target) { + setupValue(target, mKeyframeSet.mKeyframes.get(mKeyframeSet.mKeyframes.size() - 1)); + } + + @Override + public PropertyValuesHolder clone() { + try { + PropertyValuesHolder newPVH = (PropertyValuesHolder) super.clone(); + newPVH.mPropertyName = mPropertyName; + //newPVH.mProperty = mProperty; + newPVH.mKeyframeSet = mKeyframeSet.clone(); + newPVH.mEvaluator = mEvaluator; + return newPVH; + } catch (CloneNotSupportedException e) { + // won't reach here + return null; + } + } + + /** + * Internal function to set the value on the target object, using the setter set up + * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator + * to handle turning the value calculated by ValueAnimator into a value set on the object + * according to the name of the property. + * @param target The target object on which the value is set + */ + void setAnimatedValue(Object target) { + //if (mProperty != null) { + // mProperty.set(target, getAnimatedValue()); + //} + if (mSetter != null) { + try { + mTmpValueArray[0] = getAnimatedValue(); + mSetter.invoke(target, mTmpValueArray); + } catch (InvocationTargetException e) { + Log.e("PropertyValuesHolder", e.toString()); + } catch (IllegalAccessException e) { + Log.e("PropertyValuesHolder", e.toString()); + } + } + } + + /** + * Internal function, called by ValueAnimator, to set up the TypeEvaluator that will be used + * to calculate animated values. + */ + void init() { + if (mEvaluator == null) { + // We already handle int and float automatically, but not their Object + // equivalents + mEvaluator = (mValueType == Integer.class) ? sIntEvaluator : + (mValueType == Float.class) ? sFloatEvaluator : + null; + } + if (mEvaluator != null) { + // KeyframeSet knows how to evaluate the common types - only give it a custom + // evaluator if one has been set on this class + mKeyframeSet.setEvaluator(mEvaluator); + } + } + + /** + * The TypeEvaluator will the automatically determined based on the type of values + * supplied to PropertyValuesHolder. The evaluator can be manually set, however, if so + * desired. This may be important in cases where either the type of the values supplied + * do not match the way that they should be interpolated between, or if the values + * are of a custom type or one not currently understood by the animation system. Currently, + * only values of type float and int (and their Object equivalents: Float + * and Integer) are correctly interpolated; all other types require setting a TypeEvaluator. + * @param evaluator + */ + public void setEvaluator(TypeEvaluator evaluator) { + mEvaluator = evaluator; + mKeyframeSet.setEvaluator(evaluator); + } + + /** + * Function used to calculate the value according to the evaluator set up for + * this PropertyValuesHolder object. This function is called by ValueAnimator.animateValue(). + * + * @param fraction The elapsed, interpolated fraction of the animation. + */ + void calculateValue(float fraction) { + mAnimatedValue = mKeyframeSet.getValue(fraction); + } + + /** + * Sets the name of the property that will be animated. This name is used to derive + * a setter function that will be called to set animated values. + * For example, a property name of foo will result + * in a call to the function setFoo() on the target object. If either + * valueFrom or valueTo is null, then a getter function will + * also be derived and called. + * + *

Note that the setter function derived from this property name + * must take the same parameter type as the + * valueFrom and valueTo properties, otherwise the call to + * the setter function will fail.

+ * + * @param propertyName The name of the property being animated. + */ + public void setPropertyName(String propertyName) { + mPropertyName = propertyName; + } + + /** + * Sets the property that will be animated. + * + *

Note that if this PropertyValuesHolder object is used with ObjectAnimator, the property + * must exist on the target object specified in that ObjectAnimator.

+ * + * @param property The property being animated. + */ + //public void setProperty(Property property) { + // mProperty = property; + //} + + /** + * Gets the name of the property that will be animated. This name will be used to derive + * a setter function that will be called to set animated values. + * For example, a property name of foo will result + * in a call to the function setFoo() on the target object. If either + * valueFrom or valueTo is null, then a getter function will + * also be derived and called. + */ + public String getPropertyName() { + return mPropertyName; + } + + /** + * Internal function, called by ValueAnimator and ObjectAnimator, to retrieve the value + * most recently calculated in calculateValue(). + * @return + */ + Object getAnimatedValue() { + return mAnimatedValue; + } + + @Override + public String toString() { + return mPropertyName + ": " + mKeyframeSet.toString(); + } + + /** + * Utility method to derive a setter/getter method name from a property name, where the + * prefix is typically "set" or "get" and the first letter of the property name is + * capitalized. + * + * @param prefix The precursor to the method name, before the property name begins, typically + * "set" or "get". + * @param propertyName The name of the property that represents the bulk of the method name + * after the prefix. The first letter of this word will be capitalized in the resulting + * method name. + * @return String the property name converted to a method name according to the conventions + * specified above. + */ + static String getMethodName(String prefix, String propertyName) { + if (propertyName == null || propertyName.length() == 0) { + // shouldn't get here + return prefix; + } + char firstLetter = Character.toUpperCase(propertyName.charAt(0)); + String theRest = propertyName.substring(1); + return prefix + firstLetter + theRest; + } + + static class IntPropertyValuesHolder extends PropertyValuesHolder { + + // Cache JNI functions to avoid looking them up twice + //private static final HashMap> sJNISetterPropertyMap = + // new HashMap>(); + //int mJniSetter; + //private IntProperty mIntProperty; + + IntKeyframeSet mIntKeyframeSet; + int mIntAnimatedValue; + + public IntPropertyValuesHolder(String propertyName, IntKeyframeSet keyframeSet) { + super(propertyName); + mValueType = int.class; + mKeyframeSet = keyframeSet; + mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet; + } + + //public IntPropertyValuesHolder(Property property, IntKeyframeSet keyframeSet) { + // super(property); + // mValueType = int.class; + // mKeyframeSet = keyframeSet; + // mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet; + // if (property instanceof IntProperty) { + // mIntProperty = (IntProperty) mProperty; + // } + //} + + public IntPropertyValuesHolder(String propertyName, int... values) { + super(propertyName); + setIntValues(values); + } + + //public IntPropertyValuesHolder(Property property, int... values) { + // super(property); + // setIntValues(values); + // if (property instanceof IntProperty) { + // mIntProperty = (IntProperty) mProperty; + // } + //} + + @Override + public void setIntValues(int... values) { + super.setIntValues(values); + mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet; + } + + @Override + void calculateValue(float fraction) { + mIntAnimatedValue = mIntKeyframeSet.getIntValue(fraction); + } + + @Override + Object getAnimatedValue() { + return mIntAnimatedValue; + } + + @Override + public IntPropertyValuesHolder clone() { + IntPropertyValuesHolder newPVH = (IntPropertyValuesHolder) super.clone(); + newPVH.mIntKeyframeSet = (IntKeyframeSet) newPVH.mKeyframeSet; + return newPVH; + } + + /** + * Internal function to set the value on the target object, using the setter set up + * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator + * to handle turning the value calculated by ValueAnimator into a value set on the object + * according to the name of the property. + * @param target The target object on which the value is set + */ + @Override + void setAnimatedValue(Object target) { + //if (mIntProperty != null) { + // mIntProperty.setValue(target, mIntAnimatedValue); + // return; + //} + //if (mProperty != null) { + // mProperty.set(target, mIntAnimatedValue); + // return; + //} + //if (mJniSetter != 0) { + // nCallIntMethod(target, mJniSetter, mIntAnimatedValue); + // return; + //} + if (mSetter != null) { + try { + mTmpValueArray[0] = mIntAnimatedValue; + mSetter.invoke(target, mTmpValueArray); + } catch (InvocationTargetException e) { + Log.e("PropertyValuesHolder", e.toString()); + } catch (IllegalAccessException e) { + Log.e("PropertyValuesHolder", e.toString()); + } + } + } + + @Override + void setupSetter(Class targetClass) { + //if (mProperty != null) { + // return; + //} + // Check new static hashmap for setter method + //try { + // mPropertyMapLock.writeLock().lock(); + // HashMap propertyMap = sJNISetterPropertyMap.get(targetClass); + // if (propertyMap != null) { + // Integer mJniSetterInteger = propertyMap.get(mPropertyName); + // if (mJniSetterInteger != null) { + // mJniSetter = mJniSetterInteger; + // } + // } + // if (mJniSetter == 0) { + // String methodName = getMethodName("set", mPropertyName); + // mJniSetter = nGetIntMethod(targetClass, methodName); + // if (mJniSetter != 0) { + // if (propertyMap == null) { + // propertyMap = new HashMap(); + // sJNISetterPropertyMap.put(targetClass, propertyMap); + // } + // propertyMap.put(mPropertyName, mJniSetter); + // } + // } + //} catch (NoSuchMethodError e) { + // Log.d("PropertyValuesHolder", + // "Can't find native method using JNI, use reflection" + e); + //} finally { + // mPropertyMapLock.writeLock().unlock(); + //} + //if (mJniSetter == 0) { + // Couldn't find method through fast JNI approach - just use reflection + super.setupSetter(targetClass); + //} + } + } + + static class FloatPropertyValuesHolder extends PropertyValuesHolder { + + // Cache JNI functions to avoid looking them up twice + //private static final HashMap> sJNISetterPropertyMap = + // new HashMap>(); + //int mJniSetter; + //private FloatProperty mFloatProperty; + + FloatKeyframeSet mFloatKeyframeSet; + float mFloatAnimatedValue; + + public FloatPropertyValuesHolder(String propertyName, FloatKeyframeSet keyframeSet) { + super(propertyName); + mValueType = float.class; + mKeyframeSet = keyframeSet; + mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; + } + + //public FloatPropertyValuesHolder(Property property, FloatKeyframeSet keyframeSet) { + // super(property); + // mValueType = float.class; + // mKeyframeSet = keyframeSet; + // mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; + // if (property instanceof FloatProperty) { + // mFloatProperty = (FloatProperty) mProperty; + // } + //} + + public FloatPropertyValuesHolder(String propertyName, float... values) { + super(propertyName); + setFloatValues(values); + } + + //public FloatPropertyValuesHolder(Property property, float... values) { + // super(property); + // setFloatValues(values); + // if (property instanceof FloatProperty) { + // mFloatProperty = (FloatProperty) mProperty; + // } + //} + + @Override + public void setFloatValues(float... values) { + super.setFloatValues(values); + mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; + } + + @Override + void calculateValue(float fraction) { + mFloatAnimatedValue = mFloatKeyframeSet.getFloatValue(fraction); + } + + @Override + Object getAnimatedValue() { + return mFloatAnimatedValue; + } + + @Override + public FloatPropertyValuesHolder clone() { + FloatPropertyValuesHolder newPVH = (FloatPropertyValuesHolder) super.clone(); + newPVH.mFloatKeyframeSet = (FloatKeyframeSet) newPVH.mKeyframeSet; + return newPVH; + } + + /** + * Internal function to set the value on the target object, using the setter set up + * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator + * to handle turning the value calculated by ValueAnimator into a value set on the object + * according to the name of the property. + * @param target The target object on which the value is set + */ + @Override + void setAnimatedValue(Object target) { + //if (mFloatProperty != null) { + // mFloatProperty.setValue(target, mFloatAnimatedValue); + // return; + //} + //if (mProperty != null) { + // mProperty.set(target, mFloatAnimatedValue); + // return; + //} + //if (mJniSetter != 0) { + // nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue); + // return; + //} + if (mSetter != null) { + try { + mTmpValueArray[0] = mFloatAnimatedValue; + mSetter.invoke(target, mTmpValueArray); + } catch (InvocationTargetException e) { + Log.e("PropertyValuesHolder", e.toString()); + } catch (IllegalAccessException e) { + Log.e("PropertyValuesHolder", e.toString()); + } + } + } + + @Override + void setupSetter(Class targetClass) { + //if (mProperty != null) { + // return; + //} + // Check new static hashmap for setter method + //try { + // mPropertyMapLock.writeLock().lock(); + // HashMap propertyMap = sJNISetterPropertyMap.get(targetClass); + // if (propertyMap != null) { + // Integer mJniSetterInteger = propertyMap.get(mPropertyName); + // if (mJniSetterInteger != null) { + // mJniSetter = mJniSetterInteger; + // } + // } + // if (mJniSetter == 0) { + // String methodName = getMethodName("set", mPropertyName); + // mJniSetter = nGetFloatMethod(targetClass, methodName); + // if (mJniSetter != 0) { + // if (propertyMap == null) { + // propertyMap = new HashMap(); + // sJNISetterPropertyMap.put(targetClass, propertyMap); + // } + // propertyMap.put(mPropertyName, mJniSetter); + // } + // } + //} catch (NoSuchMethodError e) { + // Log.d("PropertyValuesHolder", + // "Can't find native method using JNI, use reflection" + e); + //} finally { + // mPropertyMapLock.writeLock().unlock(); + //} + //if (mJniSetter == 0) { + // Couldn't find method through fast JNI approach - just use reflection + super.setupSetter(targetClass); + //} + } + + } + + //native static private int nGetIntMethod(Class targetClass, String methodName); + //native static private int nGetFloatMethod(Class targetClass, String methodName); + //native static private void nCallIntMethod(Object target, int methodID, int arg); + //native static private void nCallFloatMethod(Object target, int methodID, float arg); +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/TypeEvaluator.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/TypeEvaluator.java new file mode 100644 index 00000000..0ea31924 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/TypeEvaluator.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +/** + * Interface for use with the {@link ValueAnimator#setEvaluator(TypeEvaluator)} function. Evaluators + * allow developers to create animations on arbitrary property types, by allowing them to supply + * custom evaulators for types that are not automatically understood and used by the animation + * system. + * + * @see ValueAnimator#setEvaluator(TypeEvaluator) + */ +public interface TypeEvaluator { + + /** + * This function returns the result of linearly interpolating the start and end values, with + * fraction representing the proportion between the start and end values. The + * calculation is a simple parametric calculation: result = x0 + t * (v1 - v0), + * where x0 is startValue, x1 is endValue, + * and t is fraction. + * + * @param fraction The fraction from the starting to the ending values + * @param startValue The start value. + * @param endValue The end value. + * @return A linear interpolation between the start and end values, given the + * fraction parameter. + */ + public T evaluate(float fraction, T startValue, T endValue); + +} \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java new file mode 100644 index 00000000..d8a12c68 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java @@ -0,0 +1,1265 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.nineoldandroids.animation; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.AndroidRuntimeException; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; + +import java.util.ArrayList; +import java.util.HashMap; + +/** + * This class provides a simple timing engine for running animations + * which calculate animated values and set them on target objects. + * + *

There is a single timing pulse that all animations use. It runs in a + * custom handler to ensure that property changes happen on the UI thread.

+ * + *

By default, ValueAnimator uses non-linear time interpolation, via the + * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates + * out of an animation. This behavior can be changed by calling + * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.

+ */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public class ValueAnimator extends Animator { + + /** + * Internal constants + */ + + /* + * The default amount of time in ms between animation frames + */ + private static final long DEFAULT_FRAME_DELAY = 10; + + /** + * Messages sent to timing handler: START is sent when an animation first begins, FRAME is sent + * by the handler to itself to process the next animation frame + */ + static final int ANIMATION_START = 0; + static final int ANIMATION_FRAME = 1; + + /** + * Values used with internal variable mPlayingState to indicate the current state of an + * animation. + */ + static final int STOPPED = 0; // Not yet playing + static final int RUNNING = 1; // Playing normally + static final int SEEKED = 2; // Seeked to some time value + + /** + * Internal variables + * NOTE: This object implements the clone() method, making a deep copy of any referenced + * objects. As other non-trivial fields are added to this class, make sure to add logic + * to clone() to make deep copies of them. + */ + + // The first time that the animation's animateFrame() method is called. This time is used to + // determine elapsed time (and therefore the elapsed fraction) in subsequent calls + // to animateFrame() + long mStartTime; + + /** + * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked + * to a value. + */ + long mSeekTime = -1; + + // TODO: We access the following ThreadLocal variables often, some of them on every update. + // If ThreadLocal access is significantly expensive, we may want to put all of these + // fields into a structure sot hat we just access ThreadLocal once to get the reference + // to that structure, then access the structure directly for each field. + + // The static sAnimationHandler processes the internal timing loop on which all animations + // are based + private static ThreadLocal sAnimationHandler = + new ThreadLocal(); + + // The per-thread list of all active animations + private static final ThreadLocal> sAnimations = + new ThreadLocal>() { + @Override + protected ArrayList initialValue() { + return new ArrayList(); + } + }; + + // The per-thread set of animations to be started on the next animation frame + private static final ThreadLocal> sPendingAnimations = + new ThreadLocal>() { + @Override + protected ArrayList initialValue() { + return new ArrayList(); + } + }; + + /** + * Internal per-thread collections used to avoid set collisions as animations start and end + * while being processed. + */ + private static final ThreadLocal> sDelayedAnims = + new ThreadLocal>() { + @Override + protected ArrayList initialValue() { + return new ArrayList(); + } + }; + + private static final ThreadLocal> sEndingAnims = + new ThreadLocal>() { + @Override + protected ArrayList initialValue() { + return new ArrayList(); + } + }; + + private static final ThreadLocal> sReadyAnims = + new ThreadLocal>() { + @Override + protected ArrayList initialValue() { + return new ArrayList(); + } + }; + + // The time interpolator to be used if none is set on the animation + private static final /*Time*/Interpolator sDefaultInterpolator = + new AccelerateDecelerateInterpolator(); + + // type evaluators for the primitive types handled by this implementation + //private static final TypeEvaluator sIntEvaluator = new IntEvaluator(); + //private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator(); + + /** + * Used to indicate whether the animation is currently playing in reverse. This causes the + * elapsed fraction to be inverted to calculate the appropriate values. + */ + private boolean mPlayingBackwards = false; + + /** + * This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the + * repeatCount (if repeatCount!=INFINITE), the animation ends + */ + private int mCurrentIteration = 0; + + /** + * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction(). + */ + private float mCurrentFraction = 0f; + + /** + * Tracks whether a startDelay'd animation has begun playing through the startDelay. + */ + private boolean mStartedDelay = false; + + /** + * Tracks the time at which the animation began playing through its startDelay. This is + * different from the mStartTime variable, which is used to track when the animation became + * active (which is when the startDelay expired and the animation was added to the active + * animations list). + */ + private long mDelayStartTime; + + /** + * Flag that represents the current state of the animation. Used to figure out when to start + * an animation (if state == STOPPED). Also used to end an animation that + * has been cancel()'d or end()'d since the last animation frame. Possible values are + * STOPPED, RUNNING, SEEKED. + */ + int mPlayingState = STOPPED; + + /** + * Additional playing state to indicate whether an animator has been start()'d. There is + * some lag between a call to start() and the first animation frame. We should still note + * that the animation has been started, even if it's first animation frame has not yet + * happened, and reflect that state in isRunning(). + * Note that delayed animations are different: they are not started until their first + * animation frame, which occurs after their delay elapses. + */ + private boolean mRunning = false; + + /** + * Additional playing state to indicate whether an animator has been start()'d, whether or + * not there is a nonzero startDelay. + */ + private boolean mStarted = false; + + /** + * Flag that denotes whether the animation is set up and ready to go. Used to + * set up animation that has not yet been started. + */ + boolean mInitialized = false; + + // + // Backing variables + // + + // How long the animation should last in ms + private long mDuration = 300; + + // The amount of time in ms to delay starting the animation after start() is called + private long mStartDelay = 0; + + // The number of milliseconds between animation frames + private static long sFrameDelay = DEFAULT_FRAME_DELAY; + + // The number of times the animation will repeat. The default is 0, which means the animation + // will play only once + private int mRepeatCount = 0; + + /** + * The type of repetition that will occur when repeatMode is nonzero. RESTART means the + * animation will start from the beginning on every new cycle. REVERSE means the animation + * will reverse directions on each iteration. + */ + private int mRepeatMode = RESTART; + + /** + * The time interpolator to be used. The elapsed fraction of the animation will be passed + * through this interpolator to calculate the interpolated fraction, which is then used to + * calculate the animated values. + */ + private /*Time*/Interpolator mInterpolator = sDefaultInterpolator; + + /** + * The set of listeners to be sent events through the life of an animation. + */ + private ArrayList mUpdateListeners = null; + + /** + * The property/value sets being animated. + */ + PropertyValuesHolder[] mValues; + + /** + * A hashmap of the PropertyValuesHolder objects. This map is used to lookup animated values + * by property name during calls to getAnimatedValue(String). + */ + HashMap mValuesMap; + + /** + * Public constants + */ + + /** + * When the animation reaches the end and repeatCount is INFINITE + * or a positive value, the animation restarts from the beginning. + */ + public static final int RESTART = 1; + /** + * When the animation reaches the end and repeatCount is INFINITE + * or a positive value, the animation reverses direction on every iteration. + */ + public static final int REVERSE = 2; + /** + * This value used used with the {@link #setRepeatCount(int)} property to repeat + * the animation indefinitely. + */ + public static final int INFINITE = -1; + + /** + * Creates a new ValueAnimator object. This default constructor is primarily for + * use internally; the factory methods which take parameters are more generally + * useful. + */ + public ValueAnimator() { + } + + /** + * Constructs and returns a ValueAnimator that animates between int values. A single + * value implies that that value is the one being animated to. However, this is not typically + * useful in a ValueAnimator object because there is no way for the object to determine the + * starting value for the animation (unlike ObjectAnimator, which can derive that value + * from the target object and property being animated). Therefore, there should typically + * be two or more values. + * + * @param values A set of values that the animation will animate between over time. + * @return A ValueAnimator object that is set up to animate between the given values. + */ + public static ValueAnimator ofInt(int... values) { + ValueAnimator anim = new ValueAnimator(); + anim.setIntValues(values); + return anim; + } + + /** + * Constructs and returns a ValueAnimator that animates between float values. A single + * value implies that that value is the one being animated to. However, this is not typically + * useful in a ValueAnimator object because there is no way for the object to determine the + * starting value for the animation (unlike ObjectAnimator, which can derive that value + * from the target object and property being animated). Therefore, there should typically + * be two or more values. + * + * @param values A set of values that the animation will animate between over time. + * @return A ValueAnimator object that is set up to animate between the given values. + */ + public static ValueAnimator ofFloat(float... values) { + ValueAnimator anim = new ValueAnimator(); + anim.setFloatValues(values); + return anim; + } + + /** + * Constructs and returns a ValueAnimator that animates between the values + * specified in the PropertyValuesHolder objects. + * + * @param values A set of PropertyValuesHolder objects whose values will be animated + * between over time. + * @return A ValueAnimator object that is set up to animate between the given values. + */ + public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) { + ValueAnimator anim = new ValueAnimator(); + anim.setValues(values); + return anim; + } + /** + * Constructs and returns a ValueAnimator that animates between Object values. A single + * value implies that that value is the one being animated to. However, this is not typically + * useful in a ValueAnimator object because there is no way for the object to determine the + * starting value for the animation (unlike ObjectAnimator, which can derive that value + * from the target object and property being animated). Therefore, there should typically + * be two or more values. + * + *

Since ValueAnimator does not know how to animate between arbitrary Objects, this + * factory method also takes a TypeEvaluator object that the ValueAnimator will use + * to perform that interpolation. + * + * @param evaluator A TypeEvaluator that will be called on each animation frame to + * provide the ncessry interpolation between the Object values to derive the animated + * value. + * @param values A set of values that the animation will animate between over time. + * @return A ValueAnimator object that is set up to animate between the given values. + */ + public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) { + ValueAnimator anim = new ValueAnimator(); + anim.setObjectValues(values); + anim.setEvaluator(evaluator); + return anim; + } + + /** + * Sets int values that will be animated between. A single + * value implies that that value is the one being animated to. However, this is not typically + * useful in a ValueAnimator object because there is no way for the object to determine the + * starting value for the animation (unlike ObjectAnimator, which can derive that value + * from the target object and property being animated). Therefore, there should typically + * be two or more values. + * + *

If there are already multiple sets of values defined for this ValueAnimator via more + * than one PropertyValuesHolder object, this method will set the values for the first + * of those objects.

+ * + * @param values A set of values that the animation will animate between over time. + */ + public void setIntValues(int... values) { + if (values == null || values.length == 0) { + return; + } + if (mValues == null || mValues.length == 0) { + setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofInt("", values)}); + } else { + PropertyValuesHolder valuesHolder = mValues[0]; + valuesHolder.setIntValues(values); + } + // New property/values/target should cause re-initialization prior to starting + mInitialized = false; + } + + /** + * Sets float values that will be animated between. A single + * value implies that that value is the one being animated to. However, this is not typically + * useful in a ValueAnimator object because there is no way for the object to determine the + * starting value for the animation (unlike ObjectAnimator, which can derive that value + * from the target object and property being animated). Therefore, there should typically + * be two or more values. + * + *

If there are already multiple sets of values defined for this ValueAnimator via more + * than one PropertyValuesHolder object, this method will set the values for the first + * of those objects.

+ * + * @param values A set of values that the animation will animate between over time. + */ + public void setFloatValues(float... values) { + if (values == null || values.length == 0) { + return; + } + if (mValues == null || mValues.length == 0) { + setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofFloat("", values)}); + } else { + PropertyValuesHolder valuesHolder = mValues[0]; + valuesHolder.setFloatValues(values); + } + // New property/values/target should cause re-initialization prior to starting + mInitialized = false; + } + + /** + * Sets the values to animate between for this animation. A single + * value implies that that value is the one being animated to. However, this is not typically + * useful in a ValueAnimator object because there is no way for the object to determine the + * starting value for the animation (unlike ObjectAnimator, which can derive that value + * from the target object and property being animated). Therefore, there should typically + * be two or more values. + * + *

If there are already multiple sets of values defined for this ValueAnimator via more + * than one PropertyValuesHolder object, this method will set the values for the first + * of those objects.

+ * + *

There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate + * between these value objects. ValueAnimator only knows how to interpolate between the + * primitive types specified in the other setValues() methods.

+ * + * @param values The set of values to animate between. + */ + public void setObjectValues(Object... values) { + if (values == null || values.length == 0) { + return; + } + if (mValues == null || mValues.length == 0) { + setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofObject("", + (TypeEvaluator)null, values)}); + } else { + PropertyValuesHolder valuesHolder = mValues[0]; + valuesHolder.setObjectValues(values); + } + // New property/values/target should cause re-initialization prior to starting + mInitialized = false; + } + + /** + * Sets the values, per property, being animated between. This function is called internally + * by the constructors of ValueAnimator that take a list of values. But an ValueAnimator can + * be constructed without values and this method can be called to set the values manually + * instead. + * + * @param values The set of values, per property, being animated between. + */ + public void setValues(PropertyValuesHolder... values) { + int numValues = values.length; + mValues = values; + mValuesMap = new HashMap(numValues); + for (int i = 0; i < numValues; ++i) { + PropertyValuesHolder valuesHolder = values[i]; + mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder); + } + // New property/values/target should cause re-initialization prior to starting + mInitialized = false; + } + + /** + * Returns the values that this ValueAnimator animates between. These values are stored in + * PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list + * of value objects instead. + * + * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the + * values, per property, that define the animation. + */ + public PropertyValuesHolder[] getValues() { + return mValues; + } + + /** + * This function is called immediately before processing the first animation + * frame of an animation. If there is a nonzero startDelay, the + * function is called after that delay ends. + * It takes care of the final initialization steps for the + * animation. + * + *

Overrides of this method should call the superclass method to ensure + * that internal mechanisms for the animation are set up correctly.

+ */ + void initAnimation() { + if (!mInitialized) { + int numValues = mValues.length; + for (int i = 0; i < numValues; ++i) { + mValues[i].init(); + } + mInitialized = true; + } + } + + + /** + * Sets the length of the animation. The default duration is 300 milliseconds. + * + * @param duration The length of the animation, in milliseconds. This value cannot + * be negative. + * @return ValueAnimator The object called with setDuration(). This return + * value makes it easier to compose statements together that construct and then set the + * duration, as in ValueAnimator.ofInt(0, 10).setDuration(500).start(). + */ + public ValueAnimator setDuration(long duration) { + if (duration < 0) { + throw new IllegalArgumentException("Animators cannot have negative duration: " + + duration); + } + mDuration = duration; + return this; + } + + /** + * Gets the length of the animation. The default duration is 300 milliseconds. + * + * @return The length of the animation, in milliseconds. + */ + public long getDuration() { + return mDuration; + } + + /** + * Sets the position of the animation to the specified point in time. This time should + * be between 0 and the total duration of the animation, including any repetition. If + * the animation has not yet been started, then it will not advance forward after it is + * set to this time; it will simply set the time to this value and perform any appropriate + * actions based on that time. If the animation is already running, then setCurrentPlayTime() + * will set the current playing time to this value and continue playing from that point. + * + * @param playTime The time, in milliseconds, to which the animation is advanced or rewound. + */ + public void setCurrentPlayTime(long playTime) { + initAnimation(); + long currentTime = AnimationUtils.currentAnimationTimeMillis(); + if (mPlayingState != RUNNING) { + mSeekTime = playTime; + mPlayingState = SEEKED; + } + mStartTime = currentTime - playTime; + animationFrame(currentTime); + } + + /** + * Gets the current position of the animation in time, which is equal to the current + * time minus the time that the animation started. An animation that is not yet started will + * return a value of zero. + * + * @return The current position in time of the animation. + */ + public long getCurrentPlayTime() { + if (!mInitialized || mPlayingState == STOPPED) { + return 0; + } + return AnimationUtils.currentAnimationTimeMillis() - mStartTime; + } + + /** + * This custom, static handler handles the timing pulse that is shared by + * all active animations. This approach ensures that the setting of animation + * values will happen on the UI thread and that all animations will share + * the same times for calculating their values, which makes synchronizing + * animations possible. + * + */ + private static class AnimationHandler extends Handler { + /** + * There are only two messages that we care about: ANIMATION_START and + * ANIMATION_FRAME. The START message is sent when an animation's start() + * method is called. It cannot start synchronously when start() is called + * because the call may be on the wrong thread, and it would also not be + * synchronized with other animations because it would not start on a common + * timing pulse. So each animation sends a START message to the handler, which + * causes the handler to place the animation on the active animations queue and + * start processing frames for that animation. + * The FRAME message is the one that is sent over and over while there are any + * active animations to process. + */ + @Override + public void handleMessage(Message msg) { + boolean callAgain = true; + ArrayList animations = sAnimations.get(); + ArrayList delayedAnims = sDelayedAnims.get(); + switch (msg.what) { + // TODO: should we avoid sending frame message when starting if we + // were already running? + case ANIMATION_START: + ArrayList pendingAnimations = sPendingAnimations.get(); + if (animations.size() > 0 || delayedAnims.size() > 0) { + callAgain = false; + } + // pendingAnims holds any animations that have requested to be started + // We're going to clear sPendingAnimations, but starting animation may + // cause more to be added to the pending list (for example, if one animation + // starting triggers another starting). So we loop until sPendingAnimations + // is empty. + while (pendingAnimations.size() > 0) { + ArrayList pendingCopy = + (ArrayList) pendingAnimations.clone(); + pendingAnimations.clear(); + int count = pendingCopy.size(); + for (int i = 0; i < count; ++i) { + ValueAnimator anim = pendingCopy.get(i); + // If the animation has a startDelay, place it on the delayed list + if (anim.mStartDelay == 0) { + anim.startAnimation(); + } else { + delayedAnims.add(anim); + } + } + } + // fall through to process first frame of new animations + case ANIMATION_FRAME: + // currentTime holds the common time for all animations processed + // during this frame + long currentTime = AnimationUtils.currentAnimationTimeMillis(); + ArrayList readyAnims = sReadyAnims.get(); + ArrayList endingAnims = sEndingAnims.get(); + + // First, process animations currently sitting on the delayed queue, adding + // them to the active animations if they are ready + int numDelayedAnims = delayedAnims.size(); + for (int i = 0; i < numDelayedAnims; ++i) { + ValueAnimator anim = delayedAnims.get(i); + if (anim.delayedAnimationFrame(currentTime)) { + readyAnims.add(anim); + } + } + int numReadyAnims = readyAnims.size(); + if (numReadyAnims > 0) { + for (int i = 0; i < numReadyAnims; ++i) { + ValueAnimator anim = readyAnims.get(i); + anim.startAnimation(); + anim.mRunning = true; + delayedAnims.remove(anim); + } + readyAnims.clear(); + } + + // Now process all active animations. The return value from animationFrame() + // tells the handler whether it should now be ended + int numAnims = animations.size(); + int i = 0; + while (i < numAnims) { + ValueAnimator anim = animations.get(i); + if (anim.animationFrame(currentTime)) { + endingAnims.add(anim); + } + if (animations.size() == numAnims) { + ++i; + } else { + // An animation might be canceled or ended by client code + // during the animation frame. Check to see if this happened by + // seeing whether the current index is the same as it was before + // calling animationFrame(). Another approach would be to copy + // animations to a temporary list and process that list instead, + // but that entails garbage and processing overhead that would + // be nice to avoid. + --numAnims; + endingAnims.remove(anim); + } + } + if (endingAnims.size() > 0) { + for (i = 0; i < endingAnims.size(); ++i) { + endingAnims.get(i).endAnimation(); + } + endingAnims.clear(); + } + + // If there are still active or delayed animations, call the handler again + // after the frameDelay + if (callAgain && (!animations.isEmpty() || !delayedAnims.isEmpty())) { + sendEmptyMessageDelayed(ANIMATION_FRAME, Math.max(0, sFrameDelay - + (AnimationUtils.currentAnimationTimeMillis() - currentTime))); + } + break; + } + } + } + + /** + * The amount of time, in milliseconds, to delay starting the animation after + * {@link #start()} is called. + * + * @return the number of milliseconds to delay running the animation + */ + public long getStartDelay() { + return mStartDelay; + } + + /** + * The amount of time, in milliseconds, to delay starting the animation after + * {@link #start()} is called. + + * @param startDelay The amount of the delay, in milliseconds + */ + public void setStartDelay(long startDelay) { + this.mStartDelay = startDelay; + } + + /** + * The amount of time, in milliseconds, between each frame of the animation. This is a + * requested time that the animation will attempt to honor, but the actual delay between + * frames may be different, depending on system load and capabilities. This is a static + * function because the same delay will be applied to all animations, since they are all + * run off of a single timing loop. + * + * @return the requested time between frames, in milliseconds + */ + public static long getFrameDelay() { + return sFrameDelay; + } + + /** + * The amount of time, in milliseconds, between each frame of the animation. This is a + * requested time that the animation will attempt to honor, but the actual delay between + * frames may be different, depending on system load and capabilities. This is a static + * function because the same delay will be applied to all animations, since they are all + * run off of a single timing loop. + * + * @param frameDelay the requested time between frames, in milliseconds + */ + public static void setFrameDelay(long frameDelay) { + sFrameDelay = frameDelay; + } + + /** + * The most recent value calculated by this ValueAnimator when there is just one + * property being animated. This value is only sensible while the animation is running. The main + * purpose for this read-only property is to retrieve the value from the ValueAnimator + * during a call to {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which + * is called during each animation frame, immediately after the value is calculated. + * + * @return animatedValue The value most recently calculated by this ValueAnimator for + * the single property being animated. If there are several properties being animated + * (specified by several PropertyValuesHolder objects in the constructor), this function + * returns the animated value for the first of those objects. + */ + public Object getAnimatedValue() { + if (mValues != null && mValues.length > 0) { + return mValues[0].getAnimatedValue(); + } + // Shouldn't get here; should always have values unless ValueAnimator was set up wrong + return null; + } + + /** + * The most recent value calculated by this ValueAnimator for propertyName. + * The main purpose for this read-only property is to retrieve the value from the + * ValueAnimator during a call to + * {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which + * is called during each animation frame, immediately after the value is calculated. + * + * @return animatedValue The value most recently calculated for the named property + * by this ValueAnimator. + */ + public Object getAnimatedValue(String propertyName) { + PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName); + if (valuesHolder != null) { + return valuesHolder.getAnimatedValue(); + } else { + // At least avoid crashing if called with bogus propertyName + return null; + } + } + + /** + * Sets how many times the animation should be repeated. If the repeat + * count is 0, the animation is never repeated. If the repeat count is + * greater than 0 or {@link #INFINITE}, the repeat mode will be taken + * into account. The repeat count is 0 by default. + * + * @param value the number of times the animation should be repeated + */ + public void setRepeatCount(int value) { + mRepeatCount = value; + } + /** + * Defines how many times the animation should repeat. The default value + * is 0. + * + * @return the number of times the animation should repeat, or {@link #INFINITE} + */ + public int getRepeatCount() { + return mRepeatCount; + } + + /** + * Defines what this animation should do when it reaches the end. This + * setting is applied only when the repeat count is either greater than + * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}. + * + * @param value {@link #RESTART} or {@link #REVERSE} + */ + public void setRepeatMode(int value) { + mRepeatMode = value; + } + + /** + * Defines what this animation should do when it reaches the end. + * + * @return either one of {@link #REVERSE} or {@link #RESTART} + */ + public int getRepeatMode() { + return mRepeatMode; + } + + /** + * Adds a listener to the set of listeners that are sent update events through the life of + * an animation. This method is called on all listeners for every frame of the animation, + * after the values for the animation have been calculated. + * + * @param listener the listener to be added to the current set of listeners for this animation. + */ + public void addUpdateListener(AnimatorUpdateListener listener) { + if (mUpdateListeners == null) { + mUpdateListeners = new ArrayList(); + } + mUpdateListeners.add(listener); + } + + /** + * Removes all listeners from the set listening to frame updates for this animation. + */ + public void removeAllUpdateListeners() { + if (mUpdateListeners == null) { + return; + } + mUpdateListeners.clear(); + mUpdateListeners = null; + } + + /** + * Removes a listener from the set listening to frame updates for this animation. + * + * @param listener the listener to be removed from the current set of update listeners + * for this animation. + */ + public void removeUpdateListener(AnimatorUpdateListener listener) { + if (mUpdateListeners == null) { + return; + } + mUpdateListeners.remove(listener); + if (mUpdateListeners.size() == 0) { + mUpdateListeners = null; + } + } + + + /** + * The time interpolator used in calculating the elapsed fraction of this animation. The + * interpolator determines whether the animation runs with linear or non-linear motion, + * such as acceleration and deceleration. The default value is + * {@link android.view.animation.AccelerateDecelerateInterpolator} + * + * @param value the interpolator to be used by this animation. A value of null + * will result in linear interpolation. + */ + @Override + public void setInterpolator(/*Time*/Interpolator value) { + if (value != null) { + mInterpolator = value; + } else { + mInterpolator = new LinearInterpolator(); + } + } + + /** + * Returns the timing interpolator that this ValueAnimator uses. + * + * @return The timing interpolator for this ValueAnimator. + */ + public /*Time*/Interpolator getInterpolator() { + return mInterpolator; + } + + /** + * The type evaluator to be used when calculating the animated values of this animation. + * The system will automatically assign a float or int evaluator based on the type + * of startValue and endValue in the constructor. But if these values + * are not one of these primitive types, or if different evaluation is desired (such as is + * necessary with int values that represent colors), a custom evaluator needs to be assigned. + * For example, when running an animation on color values, the {@link ArgbEvaluator} + * should be used to get correct RGB color interpolation. + * + *

If this ValueAnimator has only one set of values being animated between, this evaluator + * will be used for that set. If there are several sets of values being animated, which is + * the case if PropertyValuesHOlder objects were set on the ValueAnimator, then the evaluator + * is assigned just to the first PropertyValuesHolder object.

+ * + * @param value the evaluator to be used this animation + */ + public void setEvaluator(TypeEvaluator value) { + if (value != null && mValues != null && mValues.length > 0) { + mValues[0].setEvaluator(value); + } + } + + /** + * Start the animation playing. This version of start() takes a boolean flag that indicates + * whether the animation should play in reverse. The flag is usually false, but may be set + * to true if called from the reverse() method. + * + *

The animation started by calling this method will be run on the thread that called + * this method. This thread should have a Looper on it (a runtime exception will be thrown if + * this is not the case). Also, if the animation will animate + * properties of objects in the view hierarchy, then the calling thread should be the UI + * thread for that view hierarchy.

+ * + * @param playBackwards Whether the ValueAnimator should start playing in reverse. + */ + private void start(boolean playBackwards) { + if (Looper.myLooper() == null) { + throw new AndroidRuntimeException("Animators may only be run on Looper threads"); + } + mPlayingBackwards = playBackwards; + mCurrentIteration = 0; + mPlayingState = STOPPED; + mStarted = true; + mStartedDelay = false; + sPendingAnimations.get().add(this); + if (mStartDelay == 0) { + // This sets the initial value of the animation, prior to actually starting it running + setCurrentPlayTime(getCurrentPlayTime()); + mPlayingState = STOPPED; + mRunning = true; + + if (mListeners != null) { + ArrayList tmpListeners = + (ArrayList) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (int i = 0; i < numListeners; ++i) { + tmpListeners.get(i).onAnimationStart(this); + } + } + } + AnimationHandler animationHandler = sAnimationHandler.get(); + if (animationHandler == null) { + animationHandler = new AnimationHandler(); + sAnimationHandler.set(animationHandler); + } + animationHandler.sendEmptyMessage(ANIMATION_START); + } + + @Override + public void start() { + start(false); + } + + @Override + public void cancel() { + // Only cancel if the animation is actually running or has been started and is about + // to run + if (mPlayingState != STOPPED || sPendingAnimations.get().contains(this) || + sDelayedAnims.get().contains(this)) { + // Only notify listeners if the animator has actually started + if (mRunning && mListeners != null) { + ArrayList tmpListeners = + (ArrayList) mListeners.clone(); + for (AnimatorListener listener : tmpListeners) { + listener.onAnimationCancel(this); + } + } + endAnimation(); + } + } + + @Override + public void end() { + if (!sAnimations.get().contains(this) && !sPendingAnimations.get().contains(this)) { + // Special case if the animation has not yet started; get it ready for ending + mStartedDelay = false; + startAnimation(); + } else if (!mInitialized) { + initAnimation(); + } + // The final value set on the target varies, depending on whether the animation + // was supposed to repeat an odd number of times + if (mRepeatCount > 0 && (mRepeatCount & 0x01) == 1) { + animateValue(0f); + } else { + animateValue(1f); + } + endAnimation(); + } + + @Override + public boolean isRunning() { + return (mPlayingState == RUNNING || mRunning); + } + + @Override + public boolean isStarted() { + return mStarted; + } + + /** + * Plays the ValueAnimator in reverse. If the animation is already running, + * it will stop itself and play backwards from the point reached when reverse was called. + * If the animation is not currently running, then it will start from the end and + * play backwards. This behavior is only set for the current animation; future playing + * of the animation will use the default behavior of playing forward. + */ + public void reverse() { + mPlayingBackwards = !mPlayingBackwards; + if (mPlayingState == RUNNING) { + long currentTime = AnimationUtils.currentAnimationTimeMillis(); + long currentPlayTime = currentTime - mStartTime; + long timeLeft = mDuration - currentPlayTime; + mStartTime = currentTime - timeLeft; + } else { + start(true); + } + } + + /** + * Called internally to end an animation by removing it from the animations list. Must be + * called on the UI thread. + */ + private void endAnimation() { + sAnimations.get().remove(this); + sPendingAnimations.get().remove(this); + sDelayedAnims.get().remove(this); + mPlayingState = STOPPED; + if (mRunning && mListeners != null) { + ArrayList tmpListeners = + (ArrayList) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (int i = 0; i < numListeners; ++i) { + tmpListeners.get(i).onAnimationEnd(this); + } + } + mRunning = false; + mStarted = false; + } + + /** + * Called internally to start an animation by adding it to the active animations list. Must be + * called on the UI thread. + */ + private void startAnimation() { + initAnimation(); + sAnimations.get().add(this); + if (mStartDelay > 0 && mListeners != null) { + // Listeners were already notified in start() if startDelay is 0; this is + // just for delayed animations + ArrayList tmpListeners = + (ArrayList) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (int i = 0; i < numListeners; ++i) { + tmpListeners.get(i).onAnimationStart(this); + } + } + } + + /** + * Internal function called to process an animation frame on an animation that is currently + * sleeping through its startDelay phase. The return value indicates whether it + * should be woken up and put on the active animations queue. + * + * @param currentTime The current animation time, used to calculate whether the animation + * has exceeded its startDelay and should be started. + * @return True if the animation's startDelay has been exceeded and the animation + * should be added to the set of active animations. + */ + private boolean delayedAnimationFrame(long currentTime) { + if (!mStartedDelay) { + mStartedDelay = true; + mDelayStartTime = currentTime; + } else { + long deltaTime = currentTime - mDelayStartTime; + if (deltaTime > mStartDelay) { + // startDelay ended - start the anim and record the + // mStartTime appropriately + mStartTime = currentTime - (deltaTime - mStartDelay); + mPlayingState = RUNNING; + return true; + } + } + return false; + } + + /** + * This internal function processes a single animation frame for a given animation. The + * currentTime parameter is the timing pulse sent by the handler, used to calculate the + * elapsed duration, and therefore + * the elapsed fraction, of the animation. The return value indicates whether the animation + * should be ended (which happens when the elapsed time of the animation exceeds the + * animation's duration, including the repeatCount). + * + * @param currentTime The current time, as tracked by the static timing handler + * @return true if the animation's duration, including any repetitions due to + * repeatCount has been exceeded and the animation should be ended. + */ + boolean animationFrame(long currentTime) { + boolean done = false; + + if (mPlayingState == STOPPED) { + mPlayingState = RUNNING; + if (mSeekTime < 0) { + mStartTime = currentTime; + } else { + mStartTime = currentTime - mSeekTime; + // Now that we're playing, reset the seek time + mSeekTime = -1; + } + } + switch (mPlayingState) { + case RUNNING: + case SEEKED: + float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f; + if (fraction >= 1f) { + if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) { + // Time to repeat + if (mListeners != null) { + int numListeners = mListeners.size(); + for (int i = 0; i < numListeners; ++i) { + mListeners.get(i).onAnimationRepeat(this); + } + } + if (mRepeatMode == REVERSE) { + mPlayingBackwards = mPlayingBackwards ? false : true; + } + mCurrentIteration += (int)fraction; + fraction = fraction % 1f; + mStartTime += mDuration; + } else { + done = true; + fraction = Math.min(fraction, 1.0f); + } + } + if (mPlayingBackwards) { + fraction = 1f - fraction; + } + animateValue(fraction); + break; + } + + return done; + } + + /** + * Returns the current animation fraction, which is the elapsed/interpolated fraction used in + * the most recent frame update on the animation. + * + * @return Elapsed/interpolated fraction of the animation. + */ + public float getAnimatedFraction() { + return mCurrentFraction; + } + + /** + * This method is called with the elapsed fraction of the animation during every + * animation frame. This function turns the elapsed fraction into an interpolated fraction + * and then into an animated value (from the evaluator. The function is called mostly during + * animation updates, but it is also called when the end() + * function is called, to set the final value on the property. + * + *

Overrides of this method must call the superclass to perform the calculation + * of the animated value.

+ * + * @param fraction The elapsed fraction of the animation. + */ + void animateValue(float fraction) { + fraction = mInterpolator.getInterpolation(fraction); + mCurrentFraction = fraction; + int numValues = mValues.length; + for (int i = 0; i < numValues; ++i) { + mValues[i].calculateValue(fraction); + } + if (mUpdateListeners != null) { + int numListeners = mUpdateListeners.size(); + for (int i = 0; i < numListeners; ++i) { + mUpdateListeners.get(i).onAnimationUpdate(this); + } + } + } + + @Override + public ValueAnimator clone() { + final ValueAnimator anim = (ValueAnimator) super.clone(); + if (mUpdateListeners != null) { + ArrayList oldListeners = mUpdateListeners; + anim.mUpdateListeners = new ArrayList(); + int numListeners = oldListeners.size(); + for (int i = 0; i < numListeners; ++i) { + anim.mUpdateListeners.add(oldListeners.get(i)); + } + } + anim.mSeekTime = -1; + anim.mPlayingBackwards = false; + anim.mCurrentIteration = 0; + anim.mInitialized = false; + anim.mPlayingState = STOPPED; + anim.mStartedDelay = false; + PropertyValuesHolder[] oldValues = mValues; + if (oldValues != null) { + int numValues = oldValues.length; + anim.mValues = new PropertyValuesHolder[numValues]; + anim.mValuesMap = new HashMap(numValues); + for (int i = 0; i < numValues; ++i) { + PropertyValuesHolder newValuesHolder = oldValues[i].clone(); + anim.mValues[i] = newValuesHolder; + anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder); + } + } + return anim; + } + + /** + * Implementors of this interface can add themselves as update listeners + * to an ValueAnimator instance to receive callbacks on every animation + * frame, after the current frame's values have been calculated for that + * ValueAnimator. + */ + public static interface AnimatorUpdateListener { + /** + *

Notifies the occurrence of another frame of the animation.

+ * + * @param animation The animation which was repeated. + */ + void onAnimationUpdate(ValueAnimator animation); + + } + + /** + * Return the number of animations currently running. + * + * Used by StrictMode internally to annotate violations. Only + * called on the main thread. + * + * @hide + */ + public static int getCurrentAnimationsCount() { + return sAnimations.get().size(); + } + + /** + * Clear all animations on this thread, without canceling or ending them. + * This should be used with caution. + * + * @hide + */ + public static void clearAllAnimations() { + sAnimations.get().clear(); + sPendingAnimations.get().clear(); + sDelayedAnims.get().clear(); + } + + @Override + public String toString() { + String returnVal = "ValueAnimator@" + Integer.toHexString(hashCode()); + if (mValues != null) { + for (int i = 0; i < mValues.length; ++i) { + returnVal += "\n " + mValues[i].toString(); + } + } + return returnVal; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.java new file mode 100644 index 00000000..7b830b9c --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.java @@ -0,0 +1,79 @@ +package com.actionbarsherlock.internal.nineoldandroids.view; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.ViewGroup; + +import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy; + +public abstract class NineViewGroup extends ViewGroup { + private final AnimatorProxy mProxy; + + public NineViewGroup(Context context) { + super(context); + mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null; + } + public NineViewGroup(Context context, AttributeSet attrs) { + super(context, attrs); + mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null; + } + public NineViewGroup(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null; + } + + @Override + public void setVisibility(int visibility) { + if (mProxy != null) { + if (visibility == GONE) { + clearAnimation(); + } else if (visibility == VISIBLE) { + setAnimation(mProxy); + } + } + super.setVisibility(visibility); + } + + public float getAlpha() { + if (AnimatorProxy.NEEDS_PROXY) { + return mProxy.getAlpha(); + } else { + return super.getAlpha(); + } + } + public void setAlpha(float alpha) { + if (AnimatorProxy.NEEDS_PROXY) { + mProxy.setAlpha(alpha); + } else { + super.setAlpha(alpha); + } + } + public float getTranslationX() { + if (AnimatorProxy.NEEDS_PROXY) { + return mProxy.getTranslationX(); + } else { + return super.getTranslationX(); + } + } + public void setTranslationX(float translationX) { + if (AnimatorProxy.NEEDS_PROXY) { + mProxy.setTranslationX(translationX); + } else { + super.setTranslationX(translationX); + } + } + public float getTranslationY() { + if (AnimatorProxy.NEEDS_PROXY) { + return mProxy.getTranslationY(); + } else { + return super.getTranslationY(); + } + } + public void setTranslationY(float translationY) { + if (AnimatorProxy.NEEDS_PROXY) { + mProxy.setTranslationY(translationY); + } else { + super.setTranslationY(translationY); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.java new file mode 100644 index 00000000..067d0494 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.java @@ -0,0 +1,212 @@ +package com.actionbarsherlock.internal.nineoldandroids.view.animation; + +import java.lang.ref.WeakReference; +import java.util.WeakHashMap; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.os.Build; +import android.util.FloatMath; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +public final class AnimatorProxy extends Animation { + public static final boolean NEEDS_PROXY = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB; + + private static final WeakHashMap PROXIES = + new WeakHashMap(); + + public static AnimatorProxy wrap(View view) { + AnimatorProxy proxy = PROXIES.get(view); + if (proxy == null) { + proxy = new AnimatorProxy(view); + PROXIES.put(view, proxy); + } + return proxy; + } + + private final WeakReference mView; + + private float mAlpha = 1; + private float mScaleX = 1; + private float mScaleY = 1; + private float mTranslationX; + private float mTranslationY; + + private final RectF mBefore = new RectF(); + private final RectF mAfter = new RectF(); + private final Matrix mTempMatrix = new Matrix(); + + private AnimatorProxy(View view) { + setDuration(0); //perform transformation immediately + setFillAfter(true); //persist transformation beyond duration + view.setAnimation(this); + mView = new WeakReference(view); + } + + public float getAlpha() { + return mAlpha; + } + public void setAlpha(float alpha) { + if (mAlpha != alpha) { + mAlpha = alpha; + View view = mView.get(); + if (view != null) { + view.invalidate(); + } + } + } + public float getScaleX() { + return mScaleX; + } + public void setScaleX(float scaleX) { + if (mScaleX != scaleX) { + prepareForUpdate(); + mScaleX = scaleX; + invalidateAfterUpdate(); + } + } + public float getScaleY() { + return mScaleY; + } + public void setScaleY(float scaleY) { + if (mScaleY != scaleY) { + prepareForUpdate(); + mScaleY = scaleY; + invalidateAfterUpdate(); + } + } + public int getScrollX() { + View view = mView.get(); + if (view == null) { + return 0; + } + return view.getScrollX(); + } + public void setScrollX(int value) { + View view = mView.get(); + if (view != null) { + view.scrollTo(value, view.getScrollY()); + } + } + public int getScrollY() { + View view = mView.get(); + if (view == null) { + return 0; + } + return view.getScrollY(); + } + public void setScrollY(int value) { + View view = mView.get(); + if (view != null) { + view.scrollTo(view.getScrollY(), value); + } + } + + public float getTranslationX() { + return mTranslationX; + } + public void setTranslationX(float translationX) { + if (mTranslationX != translationX) { + prepareForUpdate(); + mTranslationX = translationX; + invalidateAfterUpdate(); + } + } + public float getTranslationY() { + return mTranslationY; + } + public void setTranslationY(float translationY) { + if (mTranslationY != translationY) { + prepareForUpdate(); + mTranslationY = translationY; + invalidateAfterUpdate(); + } + } + + private void prepareForUpdate() { + View view = mView.get(); + if (view != null) { + computeRect(mBefore, view); + } + } + private void invalidateAfterUpdate() { + View view = mView.get(); + if (view == null) { + return; + } + View parent = (View)view.getParent(); + if (parent == null) { + return; + } + + view.setAnimation(this); + + final RectF after = mAfter; + computeRect(after, view); + after.union(mBefore); + + parent.invalidate( + (int) FloatMath.floor(after.left), + (int) FloatMath.floor(after.top), + (int) FloatMath.ceil(after.right), + (int) FloatMath.ceil(after.bottom)); + } + + private void computeRect(final RectF r, View view) { + // compute current rectangle according to matrix transformation + final float w = view.getWidth(); + final float h = view.getHeight(); + + // use a rectangle at 0,0 to make sure we don't run into issues with scaling + r.set(0, 0, w, h); + + final Matrix m = mTempMatrix; + m.reset(); + transformMatrix(m, view); + mTempMatrix.mapRect(r); + + r.offset(view.getLeft(), view.getTop()); + + // Straighten coords if rotations flipped them + if (r.right < r.left) { + final float f = r.right; + r.right = r.left; + r.left = f; + } + if (r.bottom < r.top) { + final float f = r.top; + r.top = r.bottom; + r.bottom = f; + } + } + + private void transformMatrix(Matrix m, View view) { + final float w = view.getWidth(); + final float h = view.getHeight(); + + final float sX = mScaleX; + final float sY = mScaleY; + if ((sX != 1.0f) || (sY != 1.0f)) { + final float deltaSX = ((sX * w) - w) / 2f; + final float deltaSY = ((sY * h) - h) / 2f; + m.postScale(sX, sY); + m.postTranslate(-deltaSX, -deltaSY); + } + m.postTranslate(mTranslationX, mTranslationY); + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + View view = mView.get(); + if (view != null) { + t.setAlpha(mAlpha); + transformMatrix(t.getMatrix(), view); + } + } + + @Override + public void reset() { + /* Do nothing. */ + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.java new file mode 100644 index 00000000..953e3e84 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.java @@ -0,0 +1,57 @@ +package com.actionbarsherlock.internal.nineoldandroids.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy; + +public class NineFrameLayout extends FrameLayout { + private final AnimatorProxy mProxy; + + public NineFrameLayout(Context context, AttributeSet attrs) { + super(context, attrs); + mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null; + } + + @Override + public void setVisibility(int visibility) { + if (mProxy != null) { + if (visibility == GONE) { + clearAnimation(); + } else if (visibility == VISIBLE) { + setAnimation(mProxy); + } + } + super.setVisibility(visibility); + } + + public float getAlpha() { + if (AnimatorProxy.NEEDS_PROXY) { + return mProxy.getAlpha(); + } else { + return super.getAlpha(); + } + } + public void setAlpha(float alpha) { + if (AnimatorProxy.NEEDS_PROXY) { + mProxy.setAlpha(alpha); + } else { + super.setAlpha(alpha); + } + } + public float getTranslationY() { + if (AnimatorProxy.NEEDS_PROXY) { + return mProxy.getTranslationY(); + } else { + return super.getTranslationY(); + } + } + public void setTranslationY(float translationY) { + if (AnimatorProxy.NEEDS_PROXY) { + mProxy.setTranslationY(translationY); + } else { + super.setTranslationY(translationY); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.java new file mode 100644 index 00000000..129b5aaa --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.java @@ -0,0 +1,41 @@ +package com.actionbarsherlock.internal.nineoldandroids.widget; + +import android.content.Context; +import android.widget.HorizontalScrollView; +import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy; + +public class NineHorizontalScrollView extends HorizontalScrollView { + private final AnimatorProxy mProxy; + + public NineHorizontalScrollView(Context context) { + super(context); + mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null; + } + + @Override + public void setVisibility(int visibility) { + if (mProxy != null) { + if (visibility == GONE) { + clearAnimation(); + } else if (visibility == VISIBLE) { + setAnimation(mProxy); + } + } + super.setVisibility(visibility); + } + + public float getAlpha() { + if (AnimatorProxy.NEEDS_PROXY) { + return mProxy.getAlpha(); + } else { + return super.getAlpha(); + } + } + public void setAlpha(float alpha) { + if (AnimatorProxy.NEEDS_PROXY) { + mProxy.setAlpha(alpha); + } else { + super.setAlpha(alpha); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.java new file mode 100644 index 00000000..1f381013 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.java @@ -0,0 +1,57 @@ +package com.actionbarsherlock.internal.nineoldandroids.widget; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.LinearLayout; + +import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy; + +public class NineLinearLayout extends LinearLayout { + private final AnimatorProxy mProxy; + + public NineLinearLayout(Context context, AttributeSet attrs) { + super(context, attrs); + mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null; + } + + @Override + public void setVisibility(int visibility) { + if (mProxy != null) { + if (visibility == GONE) { + clearAnimation(); + } else if (visibility == VISIBLE) { + setAnimation(mProxy); + } + } + super.setVisibility(visibility); + } + + public float getAlpha() { + if (AnimatorProxy.NEEDS_PROXY) { + return mProxy.getAlpha(); + } else { + return super.getAlpha(); + } + } + public void setAlpha(float alpha) { + if (AnimatorProxy.NEEDS_PROXY) { + mProxy.setAlpha(alpha); + } else { + super.setAlpha(alpha); + } + } + public float getTranslationX() { + if (AnimatorProxy.NEEDS_PROXY) { + return mProxy.getTranslationX(); + } else { + return super.getTranslationX(); + } + } + public void setTranslationX(float translationX) { + if (AnimatorProxy.NEEDS_PROXY) { + mProxy.setTranslationX(translationX); + } else { + super.setTranslationX(translationX); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/ActionProviderWrapper.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/ActionProviderWrapper.java new file mode 100644 index 00000000..b136d50f --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/ActionProviderWrapper.java @@ -0,0 +1,40 @@ +package com.actionbarsherlock.internal.view; + +import com.actionbarsherlock.internal.view.menu.SubMenuWrapper; +import com.actionbarsherlock.view.ActionProvider; +import android.view.View; + +public class ActionProviderWrapper extends android.view.ActionProvider { + private final ActionProvider mProvider; + + + public ActionProviderWrapper(ActionProvider provider) { + super(null/*TODO*/); //XXX this *should* be unused + mProvider = provider; + } + + + public ActionProvider unwrap() { + return mProvider; + } + + @Override + public View onCreateActionView() { + return mProvider.onCreateActionView(); + } + + @Override + public boolean hasSubMenu() { + return mProvider.hasSubMenu(); + } + + @Override + public boolean onPerformDefaultAction() { + return mProvider.onPerformDefaultAction(); + } + + @Override + public void onPrepareSubMenu(android.view.SubMenu subMenu) { + mProvider.onPrepareSubMenu(new SubMenuWrapper(subMenu)); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/StandaloneActionMode.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/StandaloneActionMode.java new file mode 100644 index 00000000..0a87bd3f --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/StandaloneActionMode.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.actionbarsherlock.internal.view; + +import android.content.Context; +import android.view.View; +import android.view.accessibility.AccessibilityEvent; + +import java.lang.ref.WeakReference; + +import com.actionbarsherlock.internal.view.menu.MenuBuilder; +import com.actionbarsherlock.internal.view.menu.MenuPopupHelper; +import com.actionbarsherlock.internal.view.menu.SubMenuBuilder; +import com.actionbarsherlock.internal.widget.ActionBarContextView; +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +public class StandaloneActionMode extends ActionMode implements MenuBuilder.Callback { + private Context mContext; + private ActionBarContextView mContextView; + private ActionMode.Callback mCallback; + private WeakReference mCustomView; + private boolean mFinished; + private boolean mFocusable; + + private MenuBuilder mMenu; + + public StandaloneActionMode(Context context, ActionBarContextView view, + ActionMode.Callback callback, boolean isFocusable) { + mContext = context; + mContextView = view; + mCallback = callback; + + mMenu = new MenuBuilder(context).setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); + mMenu.setCallback(this); + mFocusable = isFocusable; + } + + @Override + public void setTitle(CharSequence title) { + mContextView.setTitle(title); + } + + @Override + public void setSubtitle(CharSequence subtitle) { + mContextView.setSubtitle(subtitle); + } + + @Override + public void setTitle(int resId) { + setTitle(mContext.getString(resId)); + } + + @Override + public void setSubtitle(int resId) { + setSubtitle(mContext.getString(resId)); + } + + @Override + public void setCustomView(View view) { + mContextView.setCustomView(view); + mCustomView = view != null ? new WeakReference(view) : null; + } + + @Override + public void invalidate() { + mCallback.onPrepareActionMode(this, mMenu); + } + + @Override + public void finish() { + if (mFinished) { + return; + } + mFinished = true; + + mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); + mCallback.onDestroyActionMode(this); + } + + @Override + public Menu getMenu() { + return mMenu; + } + + @Override + public CharSequence getTitle() { + return mContextView.getTitle(); + } + + @Override + public CharSequence getSubtitle() { + return mContextView.getSubtitle(); + } + + @Override + public View getCustomView() { + return mCustomView != null ? mCustomView.get() : null; + } + + @Override + public MenuInflater getMenuInflater() { + return new MenuInflater(mContext); + } + + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) { + return mCallback.onActionItemClicked(this, item); + } + + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + } + + public boolean onSubMenuSelected(SubMenuBuilder subMenu) { + if (!subMenu.hasVisibleItems()) { + return true; + } + + new MenuPopupHelper(mContext, subMenu).show(); + return true; + } + + public void onCloseSubMenu(SubMenuBuilder menu) { + } + + public void onMenuModeChange(MenuBuilder menu) { + invalidate(); + mContextView.showOverflowMenu(); + } + + public boolean isUiFocusable() { + return mFocusable; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/View_HasStateListenerSupport.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/View_HasStateListenerSupport.java new file mode 100644 index 00000000..7d45e81b --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/View_HasStateListenerSupport.java @@ -0,0 +1,6 @@ +package com.actionbarsherlock.internal.view; + +public interface View_HasStateListenerSupport { + void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener); + void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener); +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/View_OnAttachStateChangeListener.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/View_OnAttachStateChangeListener.java new file mode 100644 index 00000000..3869d329 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/View_OnAttachStateChangeListener.java @@ -0,0 +1,8 @@ +package com.actionbarsherlock.internal.view; + +import android.view.View; + +public interface View_OnAttachStateChangeListener { + void onViewAttachedToWindow(View v); + void onViewDetachedFromWindow(View v); +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenu.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenu.java new file mode 100644 index 00000000..0354ad1a --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenu.java @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.view.menu; + +import java.util.ArrayList; +import java.util.List; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.view.KeyEvent; + +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; + +/** + * @hide + */ +public class ActionMenu implements Menu { + private Context mContext; + + private boolean mIsQwerty; + + private ArrayList mItems; + + public ActionMenu(Context context) { + mContext = context; + mItems = new ArrayList(); + } + + public Context getContext() { + return mContext; + } + + public MenuItem add(CharSequence title) { + return add(0, 0, 0, title); + } + + public MenuItem add(int titleRes) { + return add(0, 0, 0, titleRes); + } + + public MenuItem add(int groupId, int itemId, int order, int titleRes) { + return add(groupId, itemId, order, mContext.getResources().getString(titleRes)); + } + + public MenuItem add(int groupId, int itemId, int order, CharSequence title) { + ActionMenuItem item = new ActionMenuItem(getContext(), + groupId, itemId, 0, order, title); + mItems.add(order, item); + return item; + } + + public int addIntentOptions(int groupId, int itemId, int order, + ComponentName caller, Intent[] specifics, Intent intent, int flags, + MenuItem[] outSpecificItems) { + PackageManager pm = mContext.getPackageManager(); + final List lri = + pm.queryIntentActivityOptions(caller, specifics, intent, 0); + final int N = lri != null ? lri.size() : 0; + + if ((flags & FLAG_APPEND_TO_GROUP) == 0) { + removeGroup(groupId); + } + + for (int i=0; i= 0) { + outSpecificItems[ri.specificIndex] = item; + } + } + + return N; + } + + public SubMenu addSubMenu(CharSequence title) { + // TODO Implement submenus + return null; + } + + public SubMenu addSubMenu(int titleRes) { + // TODO Implement submenus + return null; + } + + public SubMenu addSubMenu(int groupId, int itemId, int order, + CharSequence title) { + // TODO Implement submenus + return null; + } + + public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) { + // TODO Implement submenus + return null; + } + + public void clear() { + mItems.clear(); + } + + public void close() { + } + + private int findItemIndex(int id) { + final ArrayList items = mItems; + final int itemCount = items.size(); + for (int i = 0; i < itemCount; i++) { + if (items.get(i).getItemId() == id) { + return i; + } + } + + return -1; + } + + public MenuItem findItem(int id) { + return mItems.get(findItemIndex(id)); + } + + public MenuItem getItem(int index) { + return mItems.get(index); + } + + public boolean hasVisibleItems() { + final ArrayList items = mItems; + final int itemCount = items.size(); + + for (int i = 0; i < itemCount; i++) { + if (items.get(i).isVisible()) { + return true; + } + } + + return false; + } + + private ActionMenuItem findItemWithShortcut(int keyCode, KeyEvent event) { + // TODO Make this smarter. + final boolean qwerty = mIsQwerty; + final ArrayList items = mItems; + final int itemCount = items.size(); + + for (int i = 0; i < itemCount; i++) { + ActionMenuItem item = items.get(i); + final char shortcut = qwerty ? item.getAlphabeticShortcut() : + item.getNumericShortcut(); + if (keyCode == shortcut) { + return item; + } + } + return null; + } + + public boolean isShortcutKey(int keyCode, KeyEvent event) { + return findItemWithShortcut(keyCode, event) != null; + } + + public boolean performIdentifierAction(int id, int flags) { + final int index = findItemIndex(id); + if (index < 0) { + return false; + } + + return mItems.get(index).invoke(); + } + + public boolean performShortcut(int keyCode, KeyEvent event, int flags) { + ActionMenuItem item = findItemWithShortcut(keyCode, event); + if (item == null) { + return false; + } + + return item.invoke(); + } + + public void removeGroup(int groupId) { + final ArrayList items = mItems; + int itemCount = items.size(); + int i = 0; + while (i < itemCount) { + if (items.get(i).getGroupId() == groupId) { + items.remove(i); + itemCount--; + } else { + i++; + } + } + } + + public void removeItem(int id) { + mItems.remove(findItemIndex(id)); + } + + public void setGroupCheckable(int group, boolean checkable, + boolean exclusive) { + final ArrayList items = mItems; + final int itemCount = items.size(); + + for (int i = 0; i < itemCount; i++) { + ActionMenuItem item = items.get(i); + if (item.getGroupId() == group) { + item.setCheckable(checkable); + item.setExclusiveCheckable(exclusive); + } + } + } + + public void setGroupEnabled(int group, boolean enabled) { + final ArrayList items = mItems; + final int itemCount = items.size(); + + for (int i = 0; i < itemCount; i++) { + ActionMenuItem item = items.get(i); + if (item.getGroupId() == group) { + item.setEnabled(enabled); + } + } + } + + public void setGroupVisible(int group, boolean visible) { + final ArrayList items = mItems; + final int itemCount = items.size(); + + for (int i = 0; i < itemCount; i++) { + ActionMenuItem item = items.get(i); + if (item.getGroupId() == group) { + item.setVisible(visible); + } + } + } + + public void setQwertyMode(boolean isQwerty) { + mIsQwerty = isQwerty; + } + + public int size() { + return mItems.size(); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuItem.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuItem.java index 6c32fed3..510b9748 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuItem.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuItem.java @@ -1,255 +1,278 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.actionbarsherlock.internal.view.menu; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; -import android.support.v4.view.MenuItem; -import android.support.v4.view.SubMenu; -import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; import android.view.View; +import com.actionbarsherlock.view.ActionProvider; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; + +/** + * @hide + */ public class ActionMenuItem implements MenuItem { - private static final int CHECKABLE = MenuItemImpl.CHECKABLE; - private static final int CHECKED = MenuItemImpl.CHECKED; - private static final int ENABLED = MenuItemImpl.ENABLED; - private static final int EXCLUSIVE = MenuItemImpl.EXCLUSIVE; - private static final int HIDDEN = MenuItemImpl.HIDDEN; - private static final int NO_ICON = 0; - - //XXX UNUSED: private final int mCategoryOrder; - private MenuItem.OnMenuItemClickListener mClickListener; - private Context mContext; - private int mFlags = ENABLED; - private final int mGroup; - private Drawable mIconDrawable; - private int mIconResId = NO_ICON; private final int mId; - private Intent mIntent; + private final int mGroup; + //UNUSED private final int mCategoryOrder; private final int mOrdering; - private char mShortcutAlphabeticChar; - private char mShortcutNumericChar; + private CharSequence mTitle; private CharSequence mTitleCondensed; + private Intent mIntent; + private char mShortcutNumericChar; + private char mShortcutAlphabeticChar; + + private Drawable mIconDrawable; + //UNUSED private int mIconResId = NO_ICON; + + private Context mContext; + + private MenuItem.OnMenuItemClickListener mClickListener; - public ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering, CharSequence title) { + //UNUSED private static final int NO_ICON = 0; + + private int mFlags = ENABLED; + private static final int CHECKABLE = 0x00000001; + private static final int CHECKED = 0x00000002; + private static final int EXCLUSIVE = 0x00000004; + private static final int HIDDEN = 0x00000008; + private static final int ENABLED = 0x00000010; + + public ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering, + CharSequence title) { mContext = context; mId = id; mGroup = group; - //XXX UNUSED mCategoryOrder = categoryOrder; + //UNUSED mCategoryOrder = categoryOrder; mOrdering = ordering; mTitle = title; } - @Override - public View getActionView() { - return null; - } - - @Override public char getAlphabeticShortcut() { return mShortcutAlphabeticChar; } - @Override public int getGroupId() { return mGroup; } - @Override public Drawable getIcon() { return mIconDrawable; } - @Override public Intent getIntent() { return mIntent; } - @Override public int getItemId() { return mId; } - @Override - public ContextMenu.ContextMenuInfo getMenuInfo() { + public ContextMenuInfo getMenuInfo() { return null; } - @Override public char getNumericShortcut() { return mShortcutNumericChar; } - @Override public int getOrder() { return mOrdering; } - @Override public SubMenu getSubMenu() { return null; } - @Override public CharSequence getTitle() { return mTitle; } - @Override public CharSequence getTitleCondensed() { return mTitleCondensed; } - @Override public boolean hasSubMenu() { return false; } - public boolean invoke() { - if ((mClickListener != null) && mClickListener.onMenuItemClick(this)) { - return true; - } else if (mIntent != null) { - mContext.startActivity(mIntent); - return true; - } - return false; - } - - @Override public boolean isCheckable() { return (mFlags & CHECKABLE) != 0; } - @Override public boolean isChecked() { return (mFlags & CHECKED) != 0; } - @Override public boolean isEnabled() { return (mFlags & ENABLED) != 0; } - @Override public boolean isVisible() { return (mFlags & HIDDEN) == 0; } - @Override - public MenuItem setActionView(int layoutResId) { - throw new UnsupportedOperationException(); - } - - @Override - public MenuItem setActionView(View view) { - throw new UnsupportedOperationException(); - } - - @Override - public MenuItem setAlphabeticShortcut(char shortcut) { - mShortcutAlphabeticChar = shortcut; + public MenuItem setAlphabeticShortcut(char alphaChar) { + mShortcutAlphabeticChar = alphaChar; return this; } - @Override public MenuItem setCheckable(boolean checkable) { mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0); return this; } - @Override + public ActionMenuItem setExclusiveCheckable(boolean exclusive) { + mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0); + return this; + } + public MenuItem setChecked(boolean checked) { mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0); return this; } - @Override public MenuItem setEnabled(boolean enabled) { mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0); return this; } - public ActionMenuItem setExclusiveCheckable(boolean exclusive) { - mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0); + public MenuItem setIcon(Drawable icon) { + mIconDrawable = icon; + //UNUSED mIconResId = NO_ICON; return this; } - @Override - public MenuItem setIcon(int resId) { - mIconResId = resId; - mIconDrawable = mContext.getResources().getDrawable(mIconResId); + public MenuItem setIcon(int iconRes) { + //UNUSED mIconResId = iconRes; + mIconDrawable = mContext.getResources().getDrawable(iconRes); return this; } - @Override - public MenuItem setIcon(Drawable icon) { - mIconDrawable = icon; - mIconResId = NO_ICON; + public MenuItem setIntent(Intent intent) { + mIntent = intent; return this; } - @Override - public MenuItem setIntent(Intent intent) { - mIntent = intent; + public MenuItem setNumericShortcut(char numericChar) { + mShortcutNumericChar = numericChar; return this; } - @Override - public MenuItem setNumericShortcut(char shortcut) { - mShortcutNumericChar = shortcut; + public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) { + mClickListener = menuItemClickListener; return this; } - @Override - public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener listener) { - mClickListener = listener; + public MenuItem setShortcut(char numericChar, char alphaChar) { + mShortcutNumericChar = numericChar; + mShortcutAlphabeticChar = alphaChar; return this; } - @Override - public android.view.MenuItem setOnMenuItemClickListener(final android.view.MenuItem.OnMenuItemClickListener listener) { - mClickListener = new MenuItem.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - return listener.onMenuItemClick(item); - } - }; + public MenuItem setTitle(CharSequence title) { + mTitle = title; + return this; + } + + public MenuItem setTitle(int title) { + mTitle = mContext.getResources().getString(title); + return this; + } + + public MenuItem setTitleCondensed(CharSequence title) { + mTitleCondensed = title; + return this; + } + + public MenuItem setVisible(boolean visible) { + mFlags = (mFlags & HIDDEN) | (visible ? 0 : HIDDEN); + return this; + } + + public boolean invoke() { + if (mClickListener != null && mClickListener.onMenuItemClick(this)) { + return true; + } + + if (mIntent != null) { + mContext.startActivity(mIntent); + return true; + } + + return false; + } + + public void setShowAsAction(int show) { + // Do nothing. ActionMenuItems always show as action buttons. + } + + public MenuItem setActionView(View actionView) { + throw new UnsupportedOperationException(); + } + + public View getActionView() { return null; } @Override - public MenuItem setShortcut(char numericShortcut, char alphabeticShortcut) { - mShortcutNumericChar = numericShortcut; - mShortcutAlphabeticChar = alphabeticShortcut; - return this; + public MenuItem setActionView(int resId) { + throw new UnsupportedOperationException(); } @Override - public void setShowAsAction(int layoutResId) { - //No op + public ActionProvider getActionProvider() { + return null; } @Override - public MenuItem setTitle(int resId) { - this.mTitle = mContext.getResources().getString(resId); - return this; + public MenuItem setActionProvider(ActionProvider actionProvider) { + throw new UnsupportedOperationException(); } @Override - public MenuItem setTitle(CharSequence title) { - mTitle = title; + public MenuItem setShowAsActionFlags(int actionEnum) { + setShowAsAction(actionEnum); return this; } @Override - public MenuItem setTitleCondensed(CharSequence title) { - mTitleCondensed = title; - return this; + public boolean expandActionView() { + return false; } @Override - public MenuItem setVisible(boolean visible) { - mFlags = (mFlags & HIDDEN) | (visible ? 0 : HIDDEN); + public boolean collapseActionView() { + return false; + } + + @Override + public boolean isActionViewExpanded() { + return false; + } + + @Override + public MenuItem setOnActionExpandListener(OnActionExpandListener listener) { + // No need to save the listener; ActionMenuItem does not support collapsing items. return this; } -} \ No newline at end of file +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.java index 110c957c..dcb50f36 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.java @@ -1,149 +1,295 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.actionbarsherlock.internal.view.menu; -import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.Set; import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.TextUtils; import android.util.AttributeSet; +import android.view.Gravity; +import android.view.MotionEvent; import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TextView; +import android.view.accessibility.AccessibilityEvent; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.Toast; + import com.actionbarsherlock.R; +import com.actionbarsherlock.internal.view.View_HasStateListenerSupport; +import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener; +import com.actionbarsherlock.internal.widget.CapitalizingButton; + +import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean; + +/** + * @hide + */ +public class ActionMenuItemView extends LinearLayout + implements MenuView.ItemView, View.OnClickListener, View.OnLongClickListener, + ActionMenuView.ActionMenuChildView, View_HasStateListenerSupport { + //UNUSED private static final String TAG = "ActionMenuItemView"; + + private MenuItemImpl mItemData; + private CharSequence mTitle; + private MenuBuilder.ItemInvoker mItemInvoker; + + private ImageButton mImageButton; + private CapitalizingButton mTextButton; + private boolean mAllowTextWithIcon; + private boolean mExpandedFormat; + private int mMinWidth; -public class ActionMenuItemView extends RelativeLayout implements MenuView.ItemView, View.OnClickListener { - private ImageView mImageButton; - private TextView mTextButton; - private FrameLayout mCustomView; - private MenuItemImpl mMenuItem; - private WeakReference mDivider; + private final Set mListeners = new HashSet(); public ActionMenuItemView(Context context) { this(context, null); } + public ActionMenuItemView(Context context, AttributeSet attrs) { - this(context, attrs, R.attr.actionButtonStyle); + this(context, attrs, 0); } + public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - setOnClickListener(this); + //TODO super(context, attrs, defStyle); + super(context, attrs); + mAllowTextWithIcon = getResources_getBoolean(context, + R.bool.abs__config_allowActionMenuItemTextWithIcon); + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.SherlockActionMenuItemView, 0, 0); + mMinWidth = a.getDimensionPixelSize( + R.styleable.SherlockActionMenuItemView_android_minWidth, 0); + a.recycle(); + } + + @Override + public void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) { + mListeners.add(listener); + } + + @Override + public void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) { + mListeners.remove(listener); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + for (View_OnAttachStateChangeListener listener : mListeners) { + listener.onViewAttachedToWindow(this); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + for (View_OnAttachStateChangeListener listener : mListeners) { + listener.onViewDetachedFromWindow(this); + } } @Override - protected void onFinishInflate() { - super.onFinishInflate(); + public void onFinishInflate() { - mImageButton = (ImageView) findViewById(R.id.abs__item_icon); + mImageButton = (ImageButton) findViewById(R.id.abs__imageButton); + mTextButton = (CapitalizingButton) findViewById(R.id.abs__textButton); mImageButton.setOnClickListener(this); - mTextButton = (TextView) findViewById(R.id.abs__item_text); mTextButton.setOnClickListener(this); - mCustomView = (FrameLayout) findViewById(R.id.abs__item_custom); - mCustomView.setOnClickListener(this); + mImageButton.setOnLongClickListener(this); + setOnClickListener(this); + setOnLongClickListener(this); + } + + public MenuItemImpl getItemData() { + return mItemData; + } + + public void initialize(MenuItemImpl itemData, int menuType) { + mItemData = itemData; + + setIcon(itemData.getIcon()); + setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon + setId(itemData.getItemId()); + + setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE); + setEnabled(itemData.isEnabled()); } + @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); mImageButton.setEnabled(enabled); mTextButton.setEnabled(enabled); - mCustomView.setEnabled(enabled); } - public void setDivider(ImageView divider) { - mDivider = new WeakReference(divider); - //Ensure we are not displaying the divider when we are not visible - setDividerVisibility(getVisibility()); + public void onClick(View v) { + if (mItemInvoker != null) { + mItemInvoker.invokeItem(mItemData); + } } - public void setVisible(boolean visible) { - final int visibility = visible ? View.VISIBLE : View.GONE; - setDividerVisibility(visibility); - setVisibility(visibility); + public void setItemInvoker(MenuBuilder.ItemInvoker invoker) { + mItemInvoker = invoker; } - private void setDividerVisibility(int visibility) { - if ((mDivider != null) && (mDivider.get() != null)) { - mDivider.get().setVisibility(visibility); - } + public boolean prefersCondensedTitle() { + return true; } - public void reloadDisplay() { - final boolean hasCustomView = mCustomView.getChildCount() > 0; - final boolean hasText = mMenuItem.showsActionItemText() && !"".equals(mTextButton.getText()); + public void setCheckable(boolean checkable) { + // TODO Support checkable action items + } - if (hasCustomView) { - mCustomView.setVisibility(View.VISIBLE); - mImageButton.setVisibility(View.GONE); - mTextButton.setVisibility(View.GONE); - } else { - mCustomView.setVisibility(View.GONE); - mImageButton.setVisibility(View.VISIBLE); - mTextButton.setVisibility(hasText ? View.VISIBLE : View.GONE); + public void setChecked(boolean checked) { + // TODO Support checkable action items + } + + public void setExpandedFormat(boolean expandedFormat) { + if (mExpandedFormat != expandedFormat) { + mExpandedFormat = expandedFormat; + if (mItemData != null) { + mItemData.actionFormatChanged(); + } } } + private void updateTextButtonVisibility() { + boolean visible = !TextUtils.isEmpty(mTextButton.getText()); + visible &= mImageButton.getDrawable() == null || + (mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat)); + + mTextButton.setVisibility(visible ? VISIBLE : GONE); + } + public void setIcon(Drawable icon) { mImageButton.setImageDrawable(icon); - } + if (icon != null) { + mImageButton.setVisibility(VISIBLE); + } else { + mImageButton.setVisibility(GONE); + } - public void setTitle(CharSequence title) { - mTextButton.setText(title); - reloadDisplay(); + updateTextButtonVisibility(); } - @Override - public void initialize(MenuItemImpl itemData, int menuType) { - mMenuItem = itemData; - setId(itemData.getItemId()); - setIcon(itemData.getIcon()); - setTitle(itemData.getTitle()); - setEnabled(itemData.isEnabled()); - setActionView(itemData.getActionView()); - setVisible(itemData.isVisible()); + public boolean hasText() { + return mTextButton.getVisibility() != GONE; } - @Override - public MenuItemImpl getItemData() { - return mMenuItem; + public void setShortcut(boolean showShortcut, char shortcutKey) { + // Action buttons don't show text for shortcut keys. } - @Override - public void setCheckable(boolean checkable) { - // No-op + public void setTitle(CharSequence title) { + mTitle = title; + + mTextButton.setTextCompat(mTitle); + + setContentDescription(mTitle); + updateTextButtonVisibility(); } @Override - public void setChecked(boolean checked) { - // No-op + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + onPopulateAccessibilityEvent(event); + return true; } @Override - public void setShortcut(boolean showShortcut, char shortcutKey) { - // No-op + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + super.onPopulateAccessibilityEvent(event); + } + final CharSequence cdesc = getContentDescription(); + if (!TextUtils.isEmpty(cdesc)) { + event.getText().add(cdesc); + } } @Override - public void setActionView(View actionView) { - mCustomView.removeAllViews(); - if (actionView != null) { - mCustomView.addView(actionView); + public boolean dispatchHoverEvent(MotionEvent event) { + // Don't allow children to hover; we want this to be treated as a single component. + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + return onHoverEvent(event); } - reloadDisplay(); + return false; } - @Override - public boolean prefersCondensedTitle() { + public boolean showsIcon() { return true; } + public boolean needsDividerBefore() { + return hasText() && mItemData.getIcon() == null; + } + + public boolean needsDividerAfter() { + return hasText(); + } + @Override - public boolean showsIcon() { + public boolean onLongClick(View v) { + if (hasText()) { + // Don't show the cheat sheet for items that already show text. + return false; + } + + final int[] screenPos = new int[2]; + final Rect displayFrame = new Rect(); + getLocationOnScreen(screenPos); + getWindowVisibleDisplayFrame(displayFrame); + + final Context context = getContext(); + final int width = getWidth(); + final int height = getHeight(); + final int midy = screenPos[1] + height / 2; + final int screenWidth = context.getResources().getDisplayMetrics().widthPixels; + + Toast cheatSheet = Toast.makeText(context, mItemData.getTitle(), Toast.LENGTH_SHORT); + if (midy < displayFrame.height()) { + // Show along the top; follow action buttons + cheatSheet.setGravity(Gravity.TOP | Gravity.RIGHT, + screenWidth - screenPos[0] - width / 2, height); + } else { + // Show along the bottom center + cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height); + } + cheatSheet.show(); return true; } @Override - public void onClick(View v) { - if (mMenuItem != null) { - mMenuItem.invoke(); + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + final int widthMode = MeasureSpec.getMode(widthMeasureSpec); + final int specSize = MeasureSpec.getSize(widthMeasureSpec); + final int oldMeasuredWidth = getMeasuredWidth(); + final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(specSize, mMinWidth) + : mMinWidth; + + if (widthMode != MeasureSpec.EXACTLY && mMinWidth > 0 && oldMeasuredWidth < targetWidth) { + // Remeasure at exactly the minimum width. + super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY), + heightMeasureSpec); } } -} \ No newline at end of file +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java new file mode 100644 index 00000000..876a22c5 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java @@ -0,0 +1,714 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.view.menu; + +import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getInteger; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.SparseBooleanArray; +import android.view.SoundEffectConstants; +import android.view.View; +import android.view.View.MeasureSpec; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.widget.ImageButton; +import com.actionbarsherlock.R; +import com.actionbarsherlock.internal.view.View_HasStateListenerSupport; +import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener; +import com.actionbarsherlock.internal.view.menu.ActionMenuView.ActionMenuChildView; +import com.actionbarsherlock.view.ActionProvider; +import com.actionbarsherlock.view.MenuItem; + +/** + * MenuPresenter for building action menus as seen in the action bar and action modes. + */ +public class ActionMenuPresenter extends BaseMenuPresenter + implements ActionProvider.SubUiVisibilityListener { + //UNUSED private static final String TAG = "ActionMenuPresenter"; + + private View mOverflowButton; + private boolean mReserveOverflow; + private boolean mReserveOverflowSet; + private int mWidthLimit; + private int mActionItemWidthLimit; + private int mMaxItems; + private boolean mMaxItemsSet; + private boolean mStrictWidthLimit; + private boolean mWidthLimitSet; + private boolean mExpandedActionViewsExclusive; + + private int mMinCellSize; + + // Group IDs that have been added as actions - used temporarily, allocated here for reuse. + private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray(); + + private View mScrapActionButtonView; + + private OverflowPopup mOverflowPopup; + private ActionButtonSubmenu mActionButtonPopup; + + private OpenOverflowRunnable mPostedOpenRunnable; + + final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback(); + int mOpenSubMenuId; + + public ActionMenuPresenter(Context context) { + super(context, R.layout.abs__action_menu_layout, + R.layout.abs__action_menu_item_layout); + } + + @Override + public void initForMenu(Context context, MenuBuilder menu) { + super.initForMenu(context, menu); + + final Resources res = context.getResources(); + + if (!mReserveOverflowSet) { + mReserveOverflow = reserveOverflow(mContext); + } + + if (!mWidthLimitSet) { + mWidthLimit = res.getDisplayMetrics().widthPixels / 2; + } + + // Measure for initial configuration + if (!mMaxItemsSet) { + mMaxItems = getResources_getInteger(context, R.integer.abs__max_action_buttons); + } + + int width = mWidthLimit; + if (mReserveOverflow) { + if (mOverflowButton == null) { + mOverflowButton = new OverflowMenuButton(mSystemContext); + final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + mOverflowButton.measure(spec, spec); + } + width -= mOverflowButton.getMeasuredWidth(); + } else { + mOverflowButton = null; + } + + mActionItemWidthLimit = width; + + mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density); + + // Drop a scrap view as it may no longer reflect the proper context/config. + mScrapActionButtonView = null; + } + + public static boolean reserveOverflow(Context context) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB); + } else { + return !HasPermanentMenuKey.get(context); + } + } + + private static class HasPermanentMenuKey { + public static boolean get(Context context) { + return ViewConfiguration.get(context).hasPermanentMenuKey(); + } + } + + public void onConfigurationChanged(Configuration newConfig) { + if (!mMaxItemsSet) { + mMaxItems = getResources_getInteger(mContext, + R.integer.abs__max_action_buttons); + if (mMenu != null) { + mMenu.onItemsChanged(true); + } + } + } + + public void setWidthLimit(int width, boolean strict) { + mWidthLimit = width; + mStrictWidthLimit = strict; + mWidthLimitSet = true; + } + + public void setReserveOverflow(boolean reserveOverflow) { + mReserveOverflow = reserveOverflow; + mReserveOverflowSet = true; + } + + public void setItemLimit(int itemCount) { + mMaxItems = itemCount; + mMaxItemsSet = true; + } + + public void setExpandedActionViewsExclusive(boolean isExclusive) { + mExpandedActionViewsExclusive = isExclusive; + } + + @Override + public MenuView getMenuView(ViewGroup root) { + MenuView result = super.getMenuView(root); + ((ActionMenuView) result).setPresenter(this); + return result; + } + + @Override + public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) { + View actionView = item.getActionView(); + if (actionView == null || item.hasCollapsibleActionView()) { + if (!(convertView instanceof ActionMenuItemView)) { + convertView = null; + } + actionView = super.getItemView(item, convertView, parent); + } + actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE); + + final ActionMenuView menuParent = (ActionMenuView) parent; + final ViewGroup.LayoutParams lp = actionView.getLayoutParams(); + if (!menuParent.checkLayoutParams(lp)) { + actionView.setLayoutParams(menuParent.generateLayoutParams(lp)); + } + return actionView; + } + + @Override + public void bindItemView(MenuItemImpl item, MenuView.ItemView itemView) { + itemView.initialize(item, 0); + + final ActionMenuView menuView = (ActionMenuView) mMenuView; + ActionMenuItemView actionItemView = (ActionMenuItemView) itemView; + actionItemView.setItemInvoker(menuView); + } + + @Override + public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) { + return item.isActionButton(); + } + + @Override + public void updateMenuView(boolean cleared) { + super.updateMenuView(cleared); + + if (mMenu != null) { + final ArrayList actionItems = mMenu.getActionItems(); + final int count = actionItems.size(); + for (int i = 0; i < count; i++) { + final ActionProvider provider = actionItems.get(i).getActionProvider(); + if (provider != null) { + provider.setSubUiVisibilityListener(this); + } + } + } + + final ArrayList nonActionItems = mMenu != null ? + mMenu.getNonActionItems() : null; + + boolean hasOverflow = false; + if (mReserveOverflow && nonActionItems != null) { + final int count = nonActionItems.size(); + if (count == 1) { + hasOverflow = !nonActionItems.get(0).isActionViewExpanded(); + } else { + hasOverflow = count > 0; + } + } + + if (hasOverflow) { + if (mOverflowButton == null) { + mOverflowButton = new OverflowMenuButton(mSystemContext); + } + ViewGroup parent = (ViewGroup) mOverflowButton.getParent(); + if (parent != mMenuView) { + if (parent != null) { + parent.removeView(mOverflowButton); + } + ActionMenuView menuView = (ActionMenuView) mMenuView; + menuView.addView(mOverflowButton, menuView.generateOverflowButtonLayoutParams()); + } + } else if (mOverflowButton != null && mOverflowButton.getParent() == mMenuView) { + ((ViewGroup) mMenuView).removeView(mOverflowButton); + } + + ((ActionMenuView) mMenuView).setOverflowReserved(mReserveOverflow); + } + + @Override + public boolean filterLeftoverView(ViewGroup parent, int childIndex) { + if (parent.getChildAt(childIndex) == mOverflowButton) return false; + return super.filterLeftoverView(parent, childIndex); + } + + public boolean onSubMenuSelected(SubMenuBuilder subMenu) { + if (!subMenu.hasVisibleItems()) return false; + + SubMenuBuilder topSubMenu = subMenu; + while (topSubMenu.getParentMenu() != mMenu) { + topSubMenu = (SubMenuBuilder) topSubMenu.getParentMenu(); + } + View anchor = findViewForItem(topSubMenu.getItem()); + if (anchor == null) { + if (mOverflowButton == null) return false; + anchor = mOverflowButton; + } + + mOpenSubMenuId = subMenu.getItem().getItemId(); + mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu); + mActionButtonPopup.setAnchorView(anchor); + mActionButtonPopup.show(); + super.onSubMenuSelected(subMenu); + return true; + } + + private View findViewForItem(MenuItem item) { + final ViewGroup parent = (ViewGroup) mMenuView; + if (parent == null) return null; + + final int count = parent.getChildCount(); + for (int i = 0; i < count; i++) { + final View child = parent.getChildAt(i); + if (child instanceof MenuView.ItemView && + ((MenuView.ItemView) child).getItemData() == item) { + return child; + } + } + return null; + } + + /** + * Display the overflow menu if one is present. + * @return true if the overflow menu was shown, false otherwise. + */ + public boolean showOverflowMenu() { + if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null && + mPostedOpenRunnable == null && !mMenu.getNonActionItems().isEmpty()) { + OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true); + mPostedOpenRunnable = new OpenOverflowRunnable(popup); + // Post this for later; we might still need a layout for the anchor to be right. + ((View) mMenuView).post(mPostedOpenRunnable); + + // ActionMenuPresenter uses null as a callback argument here + // to indicate overflow is opening. + super.onSubMenuSelected(null); + + return true; + } + return false; + } + + /** + * Hide the overflow menu if it is currently showing. + * + * @return true if the overflow menu was hidden, false otherwise. + */ + public boolean hideOverflowMenu() { + if (mPostedOpenRunnable != null && mMenuView != null) { + ((View) mMenuView).removeCallbacks(mPostedOpenRunnable); + mPostedOpenRunnable = null; + return true; + } + + MenuPopupHelper popup = mOverflowPopup; + if (popup != null) { + popup.dismiss(); + return true; + } + return false; + } + + /** + * Dismiss all popup menus - overflow and submenus. + * @return true if popups were dismissed, false otherwise. (This can be because none were open.) + */ + public boolean dismissPopupMenus() { + boolean result = hideOverflowMenu(); + result |= hideSubMenus(); + return result; + } + + /** + * Dismiss all submenu popups. + * + * @return true if popups were dismissed, false otherwise. (This can be because none were open.) + */ + public boolean hideSubMenus() { + if (mActionButtonPopup != null) { + mActionButtonPopup.dismiss(); + return true; + } + return false; + } + + /** + * @return true if the overflow menu is currently showing + */ + public boolean isOverflowMenuShowing() { + return mOverflowPopup != null && mOverflowPopup.isShowing(); + } + + /** + * @return true if space has been reserved in the action menu for an overflow item. + */ + public boolean isOverflowReserved() { + return mReserveOverflow; + } + + public boolean flagActionItems() { + final ArrayList visibleItems = mMenu.getVisibleItems(); + final int itemsSize = visibleItems.size(); + int maxActions = mMaxItems; + int widthLimit = mActionItemWidthLimit; + final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + final ViewGroup parent = (ViewGroup) mMenuView; + + int requiredItems = 0; + int requestedItems = 0; + int firstActionWidth = 0; + boolean hasOverflow = false; + for (int i = 0; i < itemsSize; i++) { + MenuItemImpl item = visibleItems.get(i); + if (item.requiresActionButton()) { + requiredItems++; + } else if (item.requestsActionButton()) { + requestedItems++; + } else { + hasOverflow = true; + } + if (mExpandedActionViewsExclusive && item.isActionViewExpanded()) { + // Overflow everything if we have an expanded action view and we're + // space constrained. + maxActions = 0; + } + } + + // Reserve a spot for the overflow item if needed. + if (mReserveOverflow && + (hasOverflow || requiredItems + requestedItems > maxActions)) { + maxActions--; + } + maxActions -= requiredItems; + + final SparseBooleanArray seenGroups = mActionButtonGroups; + seenGroups.clear(); + + int cellSize = 0; + int cellsRemaining = 0; + if (mStrictWidthLimit) { + cellsRemaining = widthLimit / mMinCellSize; + final int cellSizeRemaining = widthLimit % mMinCellSize; + cellSize = mMinCellSize + cellSizeRemaining / cellsRemaining; + } + + // Flag as many more requested items as will fit. + for (int i = 0; i < itemsSize; i++) { + MenuItemImpl item = visibleItems.get(i); + + if (item.requiresActionButton()) { + View v = getItemView(item, mScrapActionButtonView, parent); + if (mScrapActionButtonView == null) { + mScrapActionButtonView = v; + } + if (mStrictWidthLimit) { + cellsRemaining -= ActionMenuView.measureChildForCells(v, + cellSize, cellsRemaining, querySpec, 0); + } else { + v.measure(querySpec, querySpec); + } + final int measuredWidth = v.getMeasuredWidth(); + widthLimit -= measuredWidth; + if (firstActionWidth == 0) { + firstActionWidth = measuredWidth; + } + final int groupId = item.getGroupId(); + if (groupId != 0) { + seenGroups.put(groupId, true); + } + item.setIsActionButton(true); + } else if (item.requestsActionButton()) { + // Items in a group with other items that already have an action slot + // can break the max actions rule, but not the width limit. + final int groupId = item.getGroupId(); + final boolean inGroup = seenGroups.get(groupId); + boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0 && + (!mStrictWidthLimit || cellsRemaining > 0); + + if (isAction) { + View v = getItemView(item, mScrapActionButtonView, parent); + if (mScrapActionButtonView == null) { + mScrapActionButtonView = v; + } + if (mStrictWidthLimit) { + final int cells = ActionMenuView.measureChildForCells(v, + cellSize, cellsRemaining, querySpec, 0); + cellsRemaining -= cells; + if (cells == 0) { + isAction = false; + } + } else { + v.measure(querySpec, querySpec); + } + final int measuredWidth = v.getMeasuredWidth(); + widthLimit -= measuredWidth; + if (firstActionWidth == 0) { + firstActionWidth = measuredWidth; + } + + if (mStrictWidthLimit) { + isAction &= widthLimit >= 0; + } else { + // Did this push the entire first item past the limit? + isAction &= widthLimit + firstActionWidth > 0; + } + } + + if (isAction && groupId != 0) { + seenGroups.put(groupId, true); + } else if (inGroup) { + // We broke the width limit. Demote the whole group, they all overflow now. + seenGroups.put(groupId, false); + for (int j = 0; j < i; j++) { + MenuItemImpl areYouMyGroupie = visibleItems.get(j); + if (areYouMyGroupie.getGroupId() == groupId) { + // Give back the action slot + if (areYouMyGroupie.isActionButton()) maxActions++; + areYouMyGroupie.setIsActionButton(false); + } + } + } + + if (isAction) maxActions--; + + item.setIsActionButton(isAction); + } + } + return true; + } + + @Override + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + dismissPopupMenus(); + super.onCloseMenu(menu, allMenusAreClosing); + } + + @Override + public Parcelable onSaveInstanceState() { + SavedState state = new SavedState(); + state.openSubMenuId = mOpenSubMenuId; + return state; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + SavedState saved = (SavedState) state; + if (saved.openSubMenuId > 0) { + MenuItem item = mMenu.findItem(saved.openSubMenuId); + if (item != null) { + SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu(); + onSubMenuSelected(subMenu); + } + } + } + + @Override + public void onSubUiVisibilityChanged(boolean isVisible) { + if (isVisible) { + // Not a submenu, but treat it like one. + super.onSubMenuSelected(null); + } else { + mMenu.close(false); + } + } + + private static class SavedState implements Parcelable { + public int openSubMenuId; + + SavedState() { + } + + SavedState(Parcel in) { + openSubMenuId = in.readInt(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(openSubMenuId); + } + + @SuppressWarnings("unused") + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + private class OverflowMenuButton extends ImageButton implements ActionMenuChildView, View_HasStateListenerSupport { + private final Set mListeners = new HashSet(); + + public OverflowMenuButton(Context context) { + super(context, null, R.attr.actionOverflowButtonStyle); + + setClickable(true); + setFocusable(true); + setVisibility(VISIBLE); + setEnabled(true); + } + + @Override + public boolean performClick() { + if (super.performClick()) { + return true; + } + + playSoundEffect(SoundEffectConstants.CLICK); + showOverflowMenu(); + return true; + } + + public boolean needsDividerBefore() { + return false; + } + + public boolean needsDividerAfter() { + return false; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + for (View_OnAttachStateChangeListener listener : mListeners) { + listener.onViewAttachedToWindow(this); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + for (View_OnAttachStateChangeListener listener : mListeners) { + listener.onViewDetachedFromWindow(this); + } + + if (mOverflowPopup != null) mOverflowPopup.dismiss(); + } + + @Override + public void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) { + mListeners.add(listener); + } + + @Override + public void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) { + mListeners.remove(listener); + } + } + + private class OverflowPopup extends MenuPopupHelper { + public OverflowPopup(Context context, MenuBuilder menu, View anchorView, + boolean overflowOnly) { + super(context, menu, anchorView, overflowOnly); + setCallback(mPopupPresenterCallback); + } + + @Override + public void onDismiss() { + super.onDismiss(); + mMenu.close(); + mOverflowPopup = null; + } + } + + private class ActionButtonSubmenu extends MenuPopupHelper { + //UNUSED private SubMenuBuilder mSubMenu; + + public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) { + super(context, subMenu); + //UNUSED mSubMenu = subMenu; + + MenuItemImpl item = (MenuItemImpl) subMenu.getItem(); + if (!item.isActionButton()) { + // Give a reasonable anchor to nested submenus. + setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton); + } + + setCallback(mPopupPresenterCallback); + + boolean preserveIconSpacing = false; + final int count = subMenu.size(); + for (int i = 0; i < count; i++) { + MenuItem childItem = subMenu.getItem(i); + if (childItem.isVisible() && childItem.getIcon() != null) { + preserveIconSpacing = true; + break; + } + } + setForceShowIcon(preserveIconSpacing); + } + + @Override + public void onDismiss() { + super.onDismiss(); + mActionButtonPopup = null; + mOpenSubMenuId = 0; + } + } + + private class PopupPresenterCallback implements MenuPresenter.Callback { + + @Override + public boolean onOpenSubMenu(MenuBuilder subMenu) { + if (subMenu == null) return false; + + mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId(); + return false; + } + + @Override + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + if (menu instanceof SubMenuBuilder) { + ((SubMenuBuilder) menu).getRootMenu().close(false); + } + } + } + + private class OpenOverflowRunnable implements Runnable { + private OverflowPopup mPopup; + + public OpenOverflowRunnable(OverflowPopup popup) { + mPopup = popup; + } + + public void run() { + mMenu.changeMenuMode(); + final View menuView = (View) mMenuView; + if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) { + mOverflowPopup = mPopup; + } + mPostedOpenRunnable = null; + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java new file mode 100644 index 00000000..0e3b1ae0 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java @@ -0,0 +1,575 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.actionbarsherlock.internal.view.menu; + +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Canvas; +import android.os.Build; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; +import android.widget.LinearLayout; +import com.actionbarsherlock.internal.widget.IcsLinearLayout; + +/** + * @hide + */ +public class ActionMenuView extends IcsLinearLayout implements MenuBuilder.ItemInvoker, MenuView { + //UNUSED private static final String TAG = "ActionMenuView"; + private static final boolean IS_FROYO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO; + + static final int MIN_CELL_SIZE = 56; // dips + static final int GENERATED_ITEM_PADDING = 4; // dips + + private MenuBuilder mMenu; + + private boolean mReserveOverflow; + private ActionMenuPresenter mPresenter; + private boolean mFormatItems; + private int mFormatItemsWidth; + private int mMinCellSize; + private int mGeneratedItemPadding; + //UNUSED private int mMeasuredExtraWidth; + + private boolean mFirst = true; + + public ActionMenuView(Context context) { + this(context, null); + } + + public ActionMenuView(Context context, AttributeSet attrs) { + super(context, attrs); + setBaselineAligned(false); + final float density = context.getResources().getDisplayMetrics().density; + mMinCellSize = (int) (MIN_CELL_SIZE * density); + mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density); + } + + public void setPresenter(ActionMenuPresenter presenter) { + mPresenter = presenter; + } + + public boolean isExpandedFormat() { + return mFormatItems; + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + if (IS_FROYO) { + super.onConfigurationChanged(newConfig); + } + mPresenter.updateMenuView(false); + + if (mPresenter != null && mPresenter.isOverflowMenuShowing()) { + mPresenter.hideOverflowMenu(); + mPresenter.showOverflowMenu(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + //Need to trigger a relayout since we may have been added extremely + //late in the initial rendering (e.g., when contained in a ViewPager). + //See: https://github.com/JakeWharton/ActionBarSherlock/issues/272 + if (!IS_FROYO && mFirst) { + mFirst = false; + requestLayout(); + return; + } + super.onDraw(canvas); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // If we've been given an exact size to match, apply special formatting during layout. + final boolean wasFormatted = mFormatItems; + mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY; + + if (wasFormatted != mFormatItems) { + mFormatItemsWidth = 0; // Reset this when switching modes + } + + // Special formatting can change whether items can fit as action buttons. + // Kick the menu and update presenters when this changes. + final int widthSize = MeasureSpec.getMode(widthMeasureSpec); + if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) { + mFormatItemsWidth = widthSize; + mMenu.onItemsChanged(true); + } + + if (mFormatItems) { + onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } + + private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) { + // We already know the width mode is EXACTLY if we're here. + final int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + final int widthPadding = getPaddingLeft() + getPaddingRight(); + final int heightPadding = getPaddingTop() + getPaddingBottom(); + + widthSize -= widthPadding; + + // Divide the view into cells. + final int cellCount = widthSize / mMinCellSize; + final int cellSizeRemaining = widthSize % mMinCellSize; + + if (cellCount == 0) { + // Give up, nothing fits. + setMeasuredDimension(widthSize, 0); + return; + } + + final int cellSize = mMinCellSize + cellSizeRemaining / cellCount; + + int cellsRemaining = cellCount; + int maxChildHeight = 0; + int maxCellsUsed = 0; + int expandableItemCount = 0; + int visibleItemCount = 0; + boolean hasOverflow = false; + + // This is used as a bitfield to locate the smallest items present. Assumes childCount < 64. + long smallestItemsAt = 0; + + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (child.getVisibility() == GONE) continue; + + final boolean isGeneratedItem = child instanceof ActionMenuItemView; + visibleItemCount++; + + if (isGeneratedItem) { + // Reset padding for generated menu item views; it may change below + // and views are recycled. + child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0); + } + + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + lp.expanded = false; + lp.extraPixels = 0; + lp.cellsUsed = 0; + lp.expandable = false; + lp.leftMargin = 0; + lp.rightMargin = 0; + lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText(); + + // Overflow always gets 1 cell. No more, no less. + final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining; + + final int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable, + heightMeasureSpec, heightPadding); + + maxCellsUsed = Math.max(maxCellsUsed, cellsUsed); + if (lp.expandable) expandableItemCount++; + if (lp.isOverflowButton) hasOverflow = true; + + cellsRemaining -= cellsUsed; + maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight()); + if (cellsUsed == 1) smallestItemsAt |= (1 << i); + } + + // When we have overflow and a single expanded (text) item, we want to try centering it + // visually in the available space even though overflow consumes some of it. + final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2; + + // Divide space for remaining cells if we have items that can expand. + // Try distributing whole leftover cells to smaller items first. + + boolean needsExpansion = false; + while (expandableItemCount > 0 && cellsRemaining > 0) { + int minCells = Integer.MAX_VALUE; + long minCellsAt = 0; // Bit locations are indices of relevant child views + int minCellsItemCount = 0; + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + // Don't try to expand items that shouldn't. + if (!lp.expandable) continue; + + // Mark indices of children that can receive an extra cell. + if (lp.cellsUsed < minCells) { + minCells = lp.cellsUsed; + minCellsAt = 1 << i; + minCellsItemCount = 1; + } else if (lp.cellsUsed == minCells) { + minCellsAt |= 1 << i; + minCellsItemCount++; + } + } + + // Items that get expanded will always be in the set of smallest items when we're done. + smallestItemsAt |= minCellsAt; + + if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop. + + // We have enough cells, all minimum size items will be incremented. + minCells++; + + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if ((minCellsAt & (1 << i)) == 0) { + // If this item is already at our small item count, mark it for later. + if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i; + continue; + } + + if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) { + // Add padding to this item such that it centers. + child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0); + } + lp.cellsUsed++; + lp.expanded = true; + cellsRemaining--; + } + + needsExpansion = true; + } + + // Divide any space left that wouldn't divide along cell boundaries + // evenly among the smallest items + + final boolean singleItem = !hasOverflow && visibleItemCount == 1; + if (cellsRemaining > 0 && smallestItemsAt != 0 && + (cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) { + float expandCount = Long.bitCount(smallestItemsAt); + + if (!singleItem) { + // The items at the far edges may only expand by half in order to pin to either side. + if ((smallestItemsAt & 1) != 0) { + LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams(); + if (!lp.preventEdgeOffset) expandCount -= 0.5f; + } + if ((smallestItemsAt & (1 << (childCount - 1))) != 0) { + LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams()); + if (!lp.preventEdgeOffset) expandCount -= 0.5f; + } + } + + final int extraPixels = expandCount > 0 ? + (int) (cellsRemaining * cellSize / expandCount) : 0; + + for (int i = 0; i < childCount; i++) { + if ((smallestItemsAt & (1 << i)) == 0) continue; + + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (child instanceof ActionMenuItemView) { + // If this is one of our views, expand and measure at the larger size. + lp.extraPixels = extraPixels; + lp.expanded = true; + if (i == 0 && !lp.preventEdgeOffset) { + // First item gets part of its new padding pushed out of sight. + // The last item will get this implicitly from layout. + lp.leftMargin = -extraPixels / 2; + } + needsExpansion = true; + } else if (lp.isOverflowButton) { + lp.extraPixels = extraPixels; + lp.expanded = true; + lp.rightMargin = -extraPixels / 2; + needsExpansion = true; + } else { + // If we don't know what it is, give it some margins instead + // and let it center within its space. We still want to pin + // against the edges. + if (i != 0) { + lp.leftMargin = extraPixels / 2; + } + if (i != childCount - 1) { + lp.rightMargin = extraPixels / 2; + } + } + } + + cellsRemaining = 0; + } + + // Remeasure any items that have had extra space allocated to them. + if (needsExpansion) { + int heightSpec = MeasureSpec.makeMeasureSpec(heightSize - heightPadding, heightMode); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + if (!lp.expanded) continue; + + final int width = lp.cellsUsed * cellSize + lp.extraPixels; + child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), heightSpec); + } + } + + if (heightMode != MeasureSpec.EXACTLY) { + heightSize = maxChildHeight; + } + + setMeasuredDimension(widthSize, heightSize); + //UNUSED mMeasuredExtraWidth = cellsRemaining * cellSize; + } + + /** + * Measure a child view to fit within cell-based formatting. The child's width + * will be measured to a whole multiple of cellSize. + * + *

Sets the expandable and cellsUsed fields of LayoutParams. + * + * @param child Child to measure + * @param cellSize Size of one cell + * @param cellsRemaining Number of cells remaining that this view can expand to fill + * @param parentHeightMeasureSpec MeasureSpec used by the parent view + * @param parentHeightPadding Padding present in the parent view + * @return Number of cells this child was measured to occupy + */ + static int measureChildForCells(View child, int cellSize, int cellsRemaining, + int parentHeightMeasureSpec, int parentHeightPadding) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + final int childHeightSize = MeasureSpec.getSize(parentHeightMeasureSpec) - + parentHeightPadding; + final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec); + final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode); + + int cellsUsed = 0; + if (cellsRemaining > 0) { + final int childWidthSpec = MeasureSpec.makeMeasureSpec( + cellSize * cellsRemaining, MeasureSpec.AT_MOST); + child.measure(childWidthSpec, childHeightSpec); + + final int measuredWidth = child.getMeasuredWidth(); + cellsUsed = measuredWidth / cellSize; + if (measuredWidth % cellSize != 0) cellsUsed++; + } + + final ActionMenuItemView itemView = child instanceof ActionMenuItemView ? + (ActionMenuItemView) child : null; + final boolean expandable = !lp.isOverflowButton && itemView != null && itemView.hasText(); + lp.expandable = expandable; + + lp.cellsUsed = cellsUsed; + final int targetWidth = cellsUsed * cellSize; + child.measure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY), + childHeightSpec); + return cellsUsed; + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (!mFormatItems) { + super.onLayout(changed, left, top, right, bottom); + return; + } + + final int childCount = getChildCount(); + final int midVertical = (top + bottom) / 2; + final int dividerWidth = 0;//getDividerWidth(); + int overflowWidth = 0; + //UNUSED int nonOverflowWidth = 0; + int nonOverflowCount = 0; + int widthRemaining = right - left - getPaddingRight() - getPaddingLeft(); + boolean hasOverflow = false; + for (int i = 0; i < childCount; i++) { + final View v = getChildAt(i); + if (v.getVisibility() == GONE) { + continue; + } + + LayoutParams p = (LayoutParams) v.getLayoutParams(); + if (p.isOverflowButton) { + overflowWidth = v.getMeasuredWidth(); + if (hasDividerBeforeChildAt(i)) { + overflowWidth += dividerWidth; + } + + int height = v.getMeasuredHeight(); + int r = getWidth() - getPaddingRight() - p.rightMargin; + int l = r - overflowWidth; + int t = midVertical - (height / 2); + int b = t + height; + v.layout(l, t, r, b); + + widthRemaining -= overflowWidth; + hasOverflow = true; + } else { + final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin; + //UNUSED nonOverflowWidth += size; + widthRemaining -= size; + //if (hasDividerBeforeChildAt(i)) { + //UNUSED nonOverflowWidth += dividerWidth; + //} + nonOverflowCount++; + } + } + + if (childCount == 1 && !hasOverflow) { + // Center a single child + final View v = getChildAt(0); + final int width = v.getMeasuredWidth(); + final int height = v.getMeasuredHeight(); + final int midHorizontal = (right - left) / 2; + final int l = midHorizontal - width / 2; + final int t = midVertical - height / 2; + v.layout(l, t, l + width, t + height); + return; + } + + final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1); + final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0); + + int startLeft = getPaddingLeft(); + for (int i = 0; i < childCount; i++) { + final View v = getChildAt(i); + final LayoutParams lp = (LayoutParams) v.getLayoutParams(); + if (v.getVisibility() == GONE || lp.isOverflowButton) { + continue; + } + + startLeft += lp.leftMargin; + int width = v.getMeasuredWidth(); + int height = v.getMeasuredHeight(); + int t = midVertical - height / 2; + v.layout(startLeft, t, startLeft + width, t + height); + startLeft += width + lp.rightMargin + spacerSize; + } + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mPresenter.dismissPopupMenus(); + } + + public boolean isOverflowReserved() { + return mReserveOverflow; + } + + public void setOverflowReserved(boolean reserveOverflow) { + mReserveOverflow = reserveOverflow; + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT); + params.gravity = Gravity.CENTER_VERTICAL; + return params; + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new LayoutParams(getContext(), attrs); + } + + @Override + protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + if (p instanceof LayoutParams) { + LayoutParams result = new LayoutParams((LayoutParams) p); + if (result.gravity <= Gravity.NO_GRAVITY) { + result.gravity = Gravity.CENTER_VERTICAL; + } + return result; + } + return generateDefaultLayoutParams(); + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p != null && p instanceof LayoutParams; + } + + public LayoutParams generateOverflowButtonLayoutParams() { + LayoutParams result = generateDefaultLayoutParams(); + result.isOverflowButton = true; + return result; + } + + public boolean invokeItem(MenuItemImpl item) { + return mMenu.performItemAction(item, 0); + } + + public int getWindowAnimations() { + return 0; + } + + public void initialize(MenuBuilder menu) { + mMenu = menu; + } + + //@Override + protected boolean hasDividerBeforeChildAt(int childIndex) { + if (childIndex == 0) { + return false; + } + final View childBefore = getChildAt(childIndex - 1); + final View child = getChildAt(childIndex); + boolean result = false; + if (childIndex < getChildCount() && childBefore instanceof ActionMenuChildView) { + result |= ((ActionMenuChildView) childBefore).needsDividerAfter(); + } + if (childIndex > 0 && child instanceof ActionMenuChildView) { + result |= ((ActionMenuChildView) child).needsDividerBefore(); + } + return result; + } + + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + return false; + } + + public interface ActionMenuChildView { + public boolean needsDividerBefore(); + public boolean needsDividerAfter(); + } + + public static class LayoutParams extends LinearLayout.LayoutParams { + public boolean isOverflowButton; + public int cellsUsed; + public int extraPixels; + public boolean expandable; + public boolean preventEdgeOffset; + + public boolean expanded; + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + public LayoutParams(LayoutParams other) { + super((LinearLayout.LayoutParams) other); + isOverflowButton = other.isOverflowButton; + } + + public LayoutParams(int width, int height) { + super(width, height); + isOverflowButton = false; + } + + public LayoutParams(int width, int height, boolean isOverflowButton) { + super(width, height); + this.isOverflowButton = isOverflowButton; + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.java new file mode 100644 index 00000000..6da26f2a --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.view.menu; + +import java.util.ArrayList; +import android.content.Context; +import android.os.Build; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +/** + * Base class for MenuPresenters that have a consistent container view and item + * views. Behaves similarly to an AdapterView in that existing item views will + * be reused if possible when items change. + */ +public abstract class BaseMenuPresenter implements MenuPresenter { + private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; + + protected Context mSystemContext; + protected Context mContext; + protected MenuBuilder mMenu; + protected LayoutInflater mSystemInflater; + protected LayoutInflater mInflater; + private Callback mCallback; + + private int mMenuLayoutRes; + private int mItemLayoutRes; + + protected MenuView mMenuView; + + private int mId; + + /** + * Construct a new BaseMenuPresenter. + * + * @param context Context for generating system-supplied views + * @param menuLayoutRes Layout resource ID for the menu container view + * @param itemLayoutRes Layout resource ID for a single item view + */ + public BaseMenuPresenter(Context context, int menuLayoutRes, int itemLayoutRes) { + mSystemContext = context; + mSystemInflater = LayoutInflater.from(context); + mMenuLayoutRes = menuLayoutRes; + mItemLayoutRes = itemLayoutRes; + } + + @Override + public void initForMenu(Context context, MenuBuilder menu) { + mContext = context; + mInflater = LayoutInflater.from(mContext); + mMenu = menu; + } + + @Override + public MenuView getMenuView(ViewGroup root) { + if (mMenuView == null) { + mMenuView = (MenuView) mSystemInflater.inflate(mMenuLayoutRes, root, false); + mMenuView.initialize(mMenu); + updateMenuView(true); + } + + return mMenuView; + } + + /** + * Reuses item views when it can + */ + public void updateMenuView(boolean cleared) { + final ViewGroup parent = (ViewGroup) mMenuView; + if (parent == null) return; + + int childIndex = 0; + if (mMenu != null) { + mMenu.flagActionItems(); + ArrayList visibleItems = mMenu.getVisibleItems(); + final int itemCount = visibleItems.size(); + for (int i = 0; i < itemCount; i++) { + MenuItemImpl item = visibleItems.get(i); + if (shouldIncludeItem(childIndex, item)) { + final View convertView = parent.getChildAt(childIndex); + final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ? + ((MenuView.ItemView) convertView).getItemData() : null; + final View itemView = getItemView(item, convertView, parent); + if (item != oldItem) { + // Don't let old states linger with new data. + itemView.setPressed(false); + if (IS_HONEYCOMB) itemView.jumpDrawablesToCurrentState(); + } + if (itemView != convertView) { + addItemView(itemView, childIndex); + } + childIndex++; + } + } + } + + // Remove leftover views. + while (childIndex < parent.getChildCount()) { + if (!filterLeftoverView(parent, childIndex)) { + childIndex++; + } + } + } + + /** + * Add an item view at the given index. + * + * @param itemView View to add + * @param childIndex Index within the parent to insert at + */ + protected void addItemView(View itemView, int childIndex) { + final ViewGroup currentParent = (ViewGroup) itemView.getParent(); + if (currentParent != null) { + currentParent.removeView(itemView); + } + ((ViewGroup) mMenuView).addView(itemView, childIndex); + } + + /** + * Filter the child view at index and remove it if appropriate. + * @param parent Parent to filter from + * @param childIndex Index to filter + * @return true if the child view at index was removed + */ + protected boolean filterLeftoverView(ViewGroup parent, int childIndex) { + parent.removeViewAt(childIndex); + return true; + } + + public void setCallback(Callback cb) { + mCallback = cb; + } + + /** + * Create a new item view that can be re-bound to other item data later. + * + * @return The new item view + */ + public MenuView.ItemView createItemView(ViewGroup parent) { + return (MenuView.ItemView) mSystemInflater.inflate(mItemLayoutRes, parent, false); + } + + /** + * Prepare an item view for use. See AdapterView for the basic idea at work here. + * This may require creating a new item view, but well-behaved implementations will + * re-use the view passed as convertView if present. The returned view will be populated + * with data from the item parameter. + * + * @param item Item to present + * @param convertView Existing view to reuse + * @param parent Intended parent view - use for inflation. + * @return View that presents the requested menu item + */ + public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) { + MenuView.ItemView itemView; + if (convertView instanceof MenuView.ItemView) { + itemView = (MenuView.ItemView) convertView; + } else { + itemView = createItemView(parent); + } + bindItemView(item, itemView); + return (View) itemView; + } + + /** + * Bind item data to an existing item view. + * + * @param item Item to bind + * @param itemView View to populate with item data + */ + public abstract void bindItemView(MenuItemImpl item, MenuView.ItemView itemView); + + /** + * Filter item by child index and item data. + * + * @param childIndex Indended presentation index of this item + * @param item Item to present + * @return true if this item should be included in this menu presentation; false otherwise + */ + public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) { + return true; + } + + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + if (mCallback != null) { + mCallback.onCloseMenu(menu, allMenusAreClosing); + } + } + + public boolean onSubMenuSelected(SubMenuBuilder menu) { + if (mCallback != null) { + return mCallback.onOpenSubMenu(menu); + } + return false; + } + + public boolean flagActionItems() { + return false; + } + + public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) { + return false; + } + + public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { + return false; + } + + public int getId() { + return mId; + } + + public void setId(int id) { + mId = id; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ListMenuItemView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ListMenuItemView.java new file mode 100644 index 00000000..ac25c373 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/ListMenuItemView.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.view.menu; + +import com.actionbarsherlock.R; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RadioButton; +import android.widget.TextView; + +/** + * The item view for each item in the ListView-based MenuViews. + */ +public class ListMenuItemView extends LinearLayout implements MenuView.ItemView { + private MenuItemImpl mItemData; + + private ImageView mIconView; + private RadioButton mRadioButton; + private TextView mTitleView; + private CheckBox mCheckBox; + private TextView mShortcutView; + + private Drawable mBackground; + private int mTextAppearance; + private Context mTextAppearanceContext; + private boolean mPreserveIconSpacing; + + //UNUSED private int mMenuType; + + private LayoutInflater mInflater; + + private boolean mForceShowIcon; + + final Context mContext; + + public ListMenuItemView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs); + mContext = context; + + TypedArray a = + context.obtainStyledAttributes( + attrs, R.styleable.SherlockMenuView, defStyle, 0); + + mBackground = a.getDrawable(R.styleable.SherlockMenuView_itemBackground); + mTextAppearance = a.getResourceId(R.styleable. + SherlockMenuView_itemTextAppearance, -1); + mPreserveIconSpacing = a.getBoolean( + R.styleable.SherlockMenuView_preserveIconSpacing, false); + mTextAppearanceContext = context; + + a.recycle(); + } + + public ListMenuItemView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + setBackgroundDrawable(mBackground); + + mTitleView = (TextView) findViewById(R.id.abs__title); + if (mTextAppearance != -1) { + mTitleView.setTextAppearance(mTextAppearanceContext, + mTextAppearance); + } + + mShortcutView = (TextView) findViewById(R.id.abs__shortcut); + } + + public void initialize(MenuItemImpl itemData, int menuType) { + mItemData = itemData; + //UNUSED mMenuType = menuType; + + setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE); + + setTitle(itemData.getTitleForItemView(this)); + setCheckable(itemData.isCheckable()); + setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut()); + setIcon(itemData.getIcon()); + setEnabled(itemData.isEnabled()); + } + + public void setForceShowIcon(boolean forceShow) { + mPreserveIconSpacing = mForceShowIcon = forceShow; + } + + public void setTitle(CharSequence title) { + if (title != null) { + mTitleView.setText(title); + + if (mTitleView.getVisibility() != VISIBLE) mTitleView.setVisibility(VISIBLE); + } else { + if (mTitleView.getVisibility() != GONE) mTitleView.setVisibility(GONE); + } + } + + public MenuItemImpl getItemData() { + return mItemData; + } + + public void setCheckable(boolean checkable) { + + if (!checkable && mRadioButton == null && mCheckBox == null) { + return; + } + + if (mRadioButton == null) { + insertRadioButton(); + } + if (mCheckBox == null) { + insertCheckBox(); + } + + // Depending on whether its exclusive check or not, the checkbox or + // radio button will be the one in use (and the other will be otherCompoundButton) + final CompoundButton compoundButton; + final CompoundButton otherCompoundButton; + + if (mItemData.isExclusiveCheckable()) { + compoundButton = mRadioButton; + otherCompoundButton = mCheckBox; + } else { + compoundButton = mCheckBox; + otherCompoundButton = mRadioButton; + } + + if (checkable) { + compoundButton.setChecked(mItemData.isChecked()); + + final int newVisibility = checkable ? VISIBLE : GONE; + if (compoundButton.getVisibility() != newVisibility) { + compoundButton.setVisibility(newVisibility); + } + + // Make sure the other compound button isn't visible + if (otherCompoundButton.getVisibility() != GONE) { + otherCompoundButton.setVisibility(GONE); + } + } else { + mCheckBox.setVisibility(GONE); + mRadioButton.setVisibility(GONE); + } + } + + public void setChecked(boolean checked) { + CompoundButton compoundButton; + + if (mItemData.isExclusiveCheckable()) { + if (mRadioButton == null) { + insertRadioButton(); + } + compoundButton = mRadioButton; + } else { + if (mCheckBox == null) { + insertCheckBox(); + } + compoundButton = mCheckBox; + } + + compoundButton.setChecked(checked); + } + + public void setShortcut(boolean showShortcut, char shortcutKey) { + final int newVisibility = (showShortcut && mItemData.shouldShowShortcut()) + ? VISIBLE : GONE; + + if (newVisibility == VISIBLE) { + mShortcutView.setText(mItemData.getShortcutLabel()); + } + + if (mShortcutView.getVisibility() != newVisibility) { + mShortcutView.setVisibility(newVisibility); + } + } + + public void setIcon(Drawable icon) { + final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon; + if (!showIcon && !mPreserveIconSpacing) { + return; + } + + if (mIconView == null && icon == null && !mPreserveIconSpacing) { + return; + } + + if (mIconView == null) { + insertIconView(); + } + + if (icon != null || mPreserveIconSpacing) { + mIconView.setImageDrawable(showIcon ? icon : null); + + if (mIconView.getVisibility() != VISIBLE) { + mIconView.setVisibility(VISIBLE); + } + } else { + mIconView.setVisibility(GONE); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + if (mIconView != null && mPreserveIconSpacing) { + // Enforce minimum icon spacing + ViewGroup.LayoutParams lp = getLayoutParams(); + LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams(); + if (lp.height > 0 && iconLp.width <= 0) { + iconLp.width = lp.height; + } + } + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + private void insertIconView() { + LayoutInflater inflater = getInflater(); + mIconView = (ImageView) inflater.inflate(R.layout.abs__list_menu_item_icon, + this, false); + addView(mIconView, 0); + } + + private void insertRadioButton() { + LayoutInflater inflater = getInflater(); + mRadioButton = + (RadioButton) inflater.inflate(R.layout.abs__list_menu_item_radio, + this, false); + addView(mRadioButton); + } + + private void insertCheckBox() { + LayoutInflater inflater = getInflater(); + mCheckBox = + (CheckBox) inflater.inflate(R.layout.abs__list_menu_item_checkbox, + this, false); + addView(mCheckBox); + } + + public boolean prefersCondensedTitle() { + return false; + } + + public boolean showsIcon() { + return mForceShowIcon; + } + + private LayoutInflater getInflater() { + if (mInflater == null) { + mInflater = LayoutInflater.from(mContext); + } + return mInflater; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuBuilder.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuBuilder.java index 41661ece..179b8f03 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuBuilder.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuBuilder.java @@ -1,408 +1,1335 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * Copyright (C) 2011 Jake Wharton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.actionbarsherlock.internal.view.menu; - -import java.util.ArrayList; -import java.util.List; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuItem; -import android.view.KeyEvent; - -/** - * An implementation of the {@link android.view.Menu} interface for use in - * inflating menu XML resources to be added to a third-party action bar. - * - * @author Jake Wharton - * @see com.android.internal.view.menu.MenuBuilder - */ -public class MenuBuilder implements Menu { - private static final int DEFAULT_ITEM_ID = 0; - private static final int DEFAULT_GROUP_ID = 0; - private static final int DEFAULT_ORDER = 0; - - public static final int NUM_TYPES = 2; - public static final int TYPE_ACTION_BAR = 0; - public static final int TYPE_NATIVE = 1; - - /** - * This is the part of an order integer that the user can provide. - * @hide - */ - static final int USER_MASK = 0x0000ffff; - - /** - * Bit shift of the user portion of the order integer. - * @hide - */ - static final int USER_SHIFT = 0; - - /** - * This is the part of an order integer that supplies the category of the - * item. - * @hide - */ - - static final int CATEGORY_MASK = 0xffff0000; - - /** - * Bit shift of the category portion of the order integer. - * @hide - */ - static final int CATEGORY_SHIFT = 16; - - private static final int[] CATEGORY_TO_ORDER = new int[] { - 1, /* No category */ - 4, /* CONTAINER */ - 5, /* SYSTEM */ - 3, /* SECONDARY */ - 2, /* ALTERNATIVE */ - 0, /* SELECTED_ALTERNATIVE */ - }; - - - - public interface Callback { - public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item); - } - - - - /** Context used for resolving any resources. */ - private final Context mContext; - - /** Child {@link ActionBarMenuItem} items. */ - private final ArrayList mItems; - - /** Menu callback that will receive various events. */ - private Callback mCallback; - - private boolean mShowsActionItemText; - - - - /** - * Create a new action bar menu. - * - * @param context Context used if resource resolution is required. - */ - public MenuBuilder(Context context) { - this.mContext = context; - this.mItems = new ArrayList(); - } - - - /** - * Adds an item to the menu. The other add methods funnel to this. - * - * @param itemId Unique item ID. - * @param groupId Group ID. - * @param order Order. - * @param title Item title. - * @return MenuItem instance. - */ - private MenuItem addInternal(int itemId, int groupId, int order, CharSequence title) { - final int ordering = getOrdering(order); - final MenuItemImpl item = new MenuItemImpl(this, groupId, itemId, order, ordering, title, MenuItem.SHOW_AS_ACTION_NEVER); - - mItems.add(findInsertIndex(mItems, ordering), item); - return item; - } - - private static int findInsertIndex(ArrayList items, int ordering) { - for (int i = items.size() - 1; i >= 0; i--) { - MenuItemImpl item = items.get(i); - if (item.getOrdering() <= ordering) { - return i + 1; - } - } - - return 0; - } - - /** - * Returns the ordering across all items. This will grab the category from - * the upper bits, find out how to order the category with respect to other - * categories, and combine it with the lower bits. - * - * @param categoryOrder The category order for a particular item (if it has - * not been or/add with a category, the default category is - * assumed). - * @return An ordering integer that can be used to order this item across - * all the items (even from other categories). - */ - private static int getOrdering(int categoryOrder) { - final int index = (categoryOrder & CATEGORY_MASK) >> CATEGORY_SHIFT; - - if (index < 0 || index >= CATEGORY_TO_ORDER.length) { - throw new IllegalArgumentException("order does not contain a valid category."); - } - - return (CATEGORY_TO_ORDER[index] << CATEGORY_SHIFT) | (categoryOrder & USER_MASK); - } - - public void setCallback(Callback callback) { - mCallback = callback; - } - - public Callback getCallback() { - return mCallback; - } - - public boolean getShowsActionItemText() { - return mShowsActionItemText; - } - - public void setShowsActionItemText(boolean showsActionItemText) { - mShowsActionItemText = showsActionItemText; - } - - /** - * Gets the root menu (if this is a submenu, find its root menu). - * - * @return The root menu. - */ - public MenuBuilder getRootMenu() { - return this; - } - - /** - * Get a list of the items contained in this menu. - * - * @return List of {@link MenuItemImpl}s. - */ - public final List getItems() { - return this.mItems; - } - - final MenuItemImpl remove(int index) { - return this.mItems.remove(index); - } - - final Context getContext() { - return this.mContext; - } - - void setExclusiveItemChecked(MenuItem item) { - final int group = item.getGroupId(); - - final int N = mItems.size(); - for (int i = 0; i < N; i++) { - MenuItemImpl curItem = mItems.get(i); - if (curItem.getGroupId() == group) { - if (!curItem.isExclusiveCheckable()) continue; - if (!curItem.isCheckable()) continue; - - // Check the item meant to be checked, uncheck the others (that are in the group) - curItem.setCheckedInt(curItem == item); - } - } - } - - // ** Menu Methods ** \\ - - @Override - public MenuItem add(int titleResourceId) { - return addInternal(0, 0, 0, mContext.getResources().getString(titleResourceId)); - } - - @Override - public MenuItem add(int groupId, int itemId, int order, int titleResourceId) { - return addInternal(itemId, groupId, order, mContext.getResources().getString(titleResourceId)); - } - - @Override - public MenuItem add(int groupId, int itemId, int order, CharSequence title) { - return addInternal(itemId, groupId, order, title); - } - - @Override - public MenuItem add(CharSequence title) { - return addInternal(0, 0, 0, title); - } - - @Override - public SubMenuBuilder addSubMenu(CharSequence title) { - return this.addSubMenu(DEFAULT_GROUP_ID, DEFAULT_ITEM_ID, DEFAULT_ORDER, title); - } - - @Override - public SubMenuBuilder addSubMenu(int titleResourceId) { - return this.addSubMenu(DEFAULT_GROUP_ID, DEFAULT_ITEM_ID, DEFAULT_ORDER, titleResourceId); - } - - @Override - public SubMenuBuilder addSubMenu(int groupId, int itemId, int order, int titleResourceId) { - String title = this.mContext.getResources().getString(titleResourceId); - return this.addSubMenu(groupId, itemId, order, title); - } - - @Override - public SubMenuBuilder addSubMenu(int groupId, int itemId, int order, CharSequence title) { - MenuItemImpl item = (MenuItemImpl)this.add(groupId, itemId, order, title); - SubMenuBuilder subMenu = new SubMenuBuilder(this.mContext, this, item); - item.setSubMenu(subMenu); - return subMenu; - } - - @Override - public void clear() { - this.mItems.clear(); - } - - @Override - public void close() {} - - @Override - public MenuItemImpl findItem(int itemId) { - for (MenuItemImpl item : this.mItems) { - if (item.getItemId() == itemId) { - return item; - } - } - return null; - } - - @Override - public MenuItemImpl getItem(int index) { - return this.mItems.get(index); - } - - @Override - public boolean hasVisibleItems() { - for (MenuItem item : this.mItems) { - if (item.isVisible()) { - return true; - } - } - return false; - } - - @Override - public void removeItem(int itemId) { - final int size = this.mItems.size(); - for (int i = 0; i < size; i++) { - if (this.mItems.get(i).getItemId() == itemId) { - this.mItems.remove(i); - return; - } - } - } - - @Override - public int size() { - return this.mItems.size(); - } - - @Override - public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, android.view.MenuItem[] outSpecificItems) { - PackageManager pm = mContext.getPackageManager(); - final List lri = - pm.queryIntentActivityOptions(caller, specifics, intent, 0); - final int N = lri != null ? lri.size() : 0; - - if ((flags & FLAG_APPEND_TO_GROUP) == 0) { - removeGroup(groupId); - } - - for (int i=0; i= 0) { - outSpecificItems[ri.specificIndex] = item; - } - } - - return N; - } - - @Override - public boolean isShortcutKey(int keyCode, KeyEvent event) { - return false; - } - - @Override - public boolean performIdentifierAction(int id, int flags) { - throw new RuntimeException("Method not supported."); - } - - @Override - public boolean performShortcut(int keyCode, KeyEvent event, int flags) { - return false; - } - - @Override - public void removeGroup(int groupId) { - final int size = this.mItems.size(); - for (int i = 0; i < size; i++) { - if (this.mItems.get(i).getGroupId() == groupId) { - this.mItems.remove(i); - } - } - } - - @Override - public void setGroupCheckable(int groupId, boolean checkable, boolean exclusive) { - final int N = mItems.size(); - for (int i = 0; i < N; i++) { - MenuItemImpl item = mItems.get(i); - if (item.getGroupId() == groupId) { - item.setExclusiveCheckable(exclusive); - item.setCheckable(checkable); - } - } - } - - @Override - public void setGroupEnabled(int groupId, boolean enabled) { - final int size = this.mItems.size(); - for (int i = 0; i < size; i++) { - MenuItemImpl item = mItems.get(i); - if (item.getGroupId() == groupId) { - item.setEnabled(enabled); - } - } - } - - @Override - public void setGroupVisible(int groupId, boolean visible) { - final int size = this.mItems.size(); - for (int i = 0; i < size; i++) { - MenuItemImpl item = mItems.get(i); - if (item.getGroupId() == groupId) { - item.setVisible(visible); - } - } - } - - @Override - public void setQwertyMode(boolean isQwerty) { - throw new RuntimeException("Method not supported."); - } -} \ No newline at end of file +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.view.menu; + + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.SparseArray; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.View; + +import com.actionbarsherlock.R; +import com.actionbarsherlock.view.ActionProvider; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; + +/** + * Implementation of the {@link android.view.Menu} interface for creating a + * standard menu UI. + */ +public class MenuBuilder implements Menu { + //UNUSED private static final String TAG = "MenuBuilder"; + + private static final String PRESENTER_KEY = "android:menu:presenters"; + private static final String ACTION_VIEW_STATES_KEY = "android:menu:actionviewstates"; + private static final String EXPANDED_ACTION_VIEW_ID = "android:menu:expandedactionview"; + + private static final int[] sCategoryToOrder = new int[] { + 1, /* No category */ + 4, /* CONTAINER */ + 5, /* SYSTEM */ + 3, /* SECONDARY */ + 2, /* ALTERNATIVE */ + 0, /* SELECTED_ALTERNATIVE */ + }; + + private final Context mContext; + private final Resources mResources; + + /** + * Whether the shortcuts should be qwerty-accessible. Use isQwertyMode() + * instead of accessing this directly. + */ + private boolean mQwertyMode; + + /** + * Whether the shortcuts should be visible on menus. Use isShortcutsVisible() + * instead of accessing this directly. + */ + private boolean mShortcutsVisible; + + /** + * Callback that will receive the various menu-related events generated by + * this class. Use getCallback to get a reference to the callback. + */ + private Callback mCallback; + + /** Contains all of the items for this menu */ + private ArrayList mItems; + + /** Contains only the items that are currently visible. This will be created/refreshed from + * {@link #getVisibleItems()} */ + private ArrayList mVisibleItems; + /** + * Whether or not the items (or any one item's shown state) has changed since it was last + * fetched from {@link #getVisibleItems()} + */ + private boolean mIsVisibleItemsStale; + + /** + * Contains only the items that should appear in the Action Bar, if present. + */ + private ArrayList mActionItems; + /** + * Contains items that should NOT appear in the Action Bar, if present. + */ + private ArrayList mNonActionItems; + + /** + * Whether or not the items (or any one item's action state) has changed since it was + * last fetched. + */ + private boolean mIsActionItemsStale; + + /** + * Default value for how added items should show in the action list. + */ + private int mDefaultShowAsAction = MenuItem.SHOW_AS_ACTION_NEVER; + + /** + * Current use case is Context Menus: As Views populate the context menu, each one has + * extra information that should be passed along. This is the current menu info that + * should be set on all items added to this menu. + */ + private ContextMenuInfo mCurrentMenuInfo; + + /** Header title for menu types that have a header (context and submenus) */ + CharSequence mHeaderTitle; + /** Header icon for menu types that have a header and support icons (context) */ + Drawable mHeaderIcon; + /** Header custom view for menu types that have a header and support custom views (context) */ + View mHeaderView; + + /** + * Contains the state of the View hierarchy for all menu views when the menu + * was frozen. + */ + //UNUSED private SparseArray mFrozenViewStates; + + /** + * Prevents onItemsChanged from doing its junk, useful for batching commands + * that may individually call onItemsChanged. + */ + private boolean mPreventDispatchingItemsChanged = false; + private boolean mItemsChangedWhileDispatchPrevented = false; + + private boolean mOptionalIconsVisible = false; + + private boolean mIsClosing = false; + + private ArrayList mTempShortcutItemList = new ArrayList(); + + private CopyOnWriteArrayList> mPresenters = + new CopyOnWriteArrayList>(); + + /** + * Currently expanded menu item; must be collapsed when we clear. + */ + private MenuItemImpl mExpandedItem; + + /** + * Called by menu to notify of close and selection changes. + */ + public interface Callback { + /** + * Called when a menu item is selected. + * @param menu The menu that is the parent of the item + * @param item The menu item that is selected + * @return whether the menu item selection was handled + */ + public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item); + + /** + * Called when the mode of the menu changes (for example, from icon to expanded). + * + * @param menu the menu that has changed modes + */ + public void onMenuModeChange(MenuBuilder menu); + } + + /** + * Called by menu items to execute their associated action + */ + public interface ItemInvoker { + public boolean invokeItem(MenuItemImpl item); + } + + public MenuBuilder(Context context) { + mContext = context; + mResources = context.getResources(); + + mItems = new ArrayList(); + + mVisibleItems = new ArrayList(); + mIsVisibleItemsStale = true; + + mActionItems = new ArrayList(); + mNonActionItems = new ArrayList(); + mIsActionItemsStale = true; + + setShortcutsVisibleInner(true); + } + + public MenuBuilder setDefaultShowAsAction(int defaultShowAsAction) { + mDefaultShowAsAction = defaultShowAsAction; + return this; + } + + /** + * Add a presenter to this menu. This will only hold a WeakReference; + * you do not need to explicitly remove a presenter, but you can using + * {@link #removeMenuPresenter(MenuPresenter)}. + * + * @param presenter The presenter to add + */ + public void addMenuPresenter(MenuPresenter presenter) { + mPresenters.add(new WeakReference(presenter)); + presenter.initForMenu(mContext, this); + mIsActionItemsStale = true; + } + + /** + * Remove a presenter from this menu. That presenter will no longer + * receive notifications of updates to this menu's data. + * + * @param presenter The presenter to remove + */ + public void removeMenuPresenter(MenuPresenter presenter) { + for (WeakReference ref : mPresenters) { + final MenuPresenter item = ref.get(); + if (item == null || item == presenter) { + mPresenters.remove(ref); + } + } + } + + private void dispatchPresenterUpdate(boolean cleared) { + if (mPresenters.isEmpty()) return; + + stopDispatchingItemsChanged(); + for (WeakReference ref : mPresenters) { + final MenuPresenter presenter = ref.get(); + if (presenter == null) { + mPresenters.remove(ref); + } else { + presenter.updateMenuView(cleared); + } + } + startDispatchingItemsChanged(); + } + + private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu) { + if (mPresenters.isEmpty()) return false; + + boolean result = false; + + for (WeakReference ref : mPresenters) { + final MenuPresenter presenter = ref.get(); + if (presenter == null) { + mPresenters.remove(ref); + } else if (!result) { + result = presenter.onSubMenuSelected(subMenu); + } + } + return result; + } + + private void dispatchSaveInstanceState(Bundle outState) { + if (mPresenters.isEmpty()) return; + + SparseArray presenterStates = new SparseArray(); + + for (WeakReference ref : mPresenters) { + final MenuPresenter presenter = ref.get(); + if (presenter == null) { + mPresenters.remove(ref); + } else { + final int id = presenter.getId(); + if (id > 0) { + final Parcelable state = presenter.onSaveInstanceState(); + if (state != null) { + presenterStates.put(id, state); + } + } + } + } + + outState.putSparseParcelableArray(PRESENTER_KEY, presenterStates); + } + + private void dispatchRestoreInstanceState(Bundle state) { + SparseArray presenterStates = state.getSparseParcelableArray(PRESENTER_KEY); + + if (presenterStates == null || mPresenters.isEmpty()) return; + + for (WeakReference ref : mPresenters) { + final MenuPresenter presenter = ref.get(); + if (presenter == null) { + mPresenters.remove(ref); + } else { + final int id = presenter.getId(); + if (id > 0) { + Parcelable parcel = presenterStates.get(id); + if (parcel != null) { + presenter.onRestoreInstanceState(parcel); + } + } + } + } + } + + public void savePresenterStates(Bundle outState) { + dispatchSaveInstanceState(outState); + } + + public void restorePresenterStates(Bundle state) { + dispatchRestoreInstanceState(state); + } + + public void saveActionViewStates(Bundle outStates) { + SparseArray viewStates = null; + + final int itemCount = size(); + for (int i = 0; i < itemCount; i++) { + final MenuItem item = getItem(i); + final View v = item.getActionView(); + if (v != null && v.getId() != View.NO_ID) { + if (viewStates == null) { + viewStates = new SparseArray(); + } + v.saveHierarchyState(viewStates); + if (item.isActionViewExpanded()) { + outStates.putInt(EXPANDED_ACTION_VIEW_ID, item.getItemId()); + } + } + if (item.hasSubMenu()) { + final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu(); + subMenu.saveActionViewStates(outStates); + } + } + + if (viewStates != null) { + outStates.putSparseParcelableArray(getActionViewStatesKey(), viewStates); + } + } + + public void restoreActionViewStates(Bundle states) { + if (states == null) { + return; + } + + SparseArray viewStates = states.getSparseParcelableArray( + getActionViewStatesKey()); + + final int itemCount = size(); + for (int i = 0; i < itemCount; i++) { + final MenuItem item = getItem(i); + final View v = item.getActionView(); + if (v != null && v.getId() != View.NO_ID) { + v.restoreHierarchyState(viewStates); + } + if (item.hasSubMenu()) { + final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu(); + subMenu.restoreActionViewStates(states); + } + } + + final int expandedId = states.getInt(EXPANDED_ACTION_VIEW_ID); + if (expandedId > 0) { + MenuItem itemToExpand = findItem(expandedId); + if (itemToExpand != null) { + itemToExpand.expandActionView(); + } + } + } + + protected String getActionViewStatesKey() { + return ACTION_VIEW_STATES_KEY; + } + + public void setCallback(Callback cb) { + mCallback = cb; + } + + /** + * Adds an item to the menu. The other add methods funnel to this. + */ + private MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) { + final int ordering = getOrdering(categoryOrder); + + final MenuItemImpl item = new MenuItemImpl(this, group, id, categoryOrder, + ordering, title, mDefaultShowAsAction); + + if (mCurrentMenuInfo != null) { + // Pass along the current menu info + item.setMenuInfo(mCurrentMenuInfo); + } + + mItems.add(findInsertIndex(mItems, ordering), item); + onItemsChanged(true); + + return item; + } + + public MenuItem add(CharSequence title) { + return addInternal(0, 0, 0, title); + } + + public MenuItem add(int titleRes) { + return addInternal(0, 0, 0, mResources.getString(titleRes)); + } + + public MenuItem add(int group, int id, int categoryOrder, CharSequence title) { + return addInternal(group, id, categoryOrder, title); + } + + public MenuItem add(int group, int id, int categoryOrder, int title) { + return addInternal(group, id, categoryOrder, mResources.getString(title)); + } + + public SubMenu addSubMenu(CharSequence title) { + return addSubMenu(0, 0, 0, title); + } + + public SubMenu addSubMenu(int titleRes) { + return addSubMenu(0, 0, 0, mResources.getString(titleRes)); + } + + public SubMenu addSubMenu(int group, int id, int categoryOrder, CharSequence title) { + final MenuItemImpl item = (MenuItemImpl) addInternal(group, id, categoryOrder, title); + final SubMenuBuilder subMenu = new SubMenuBuilder(mContext, this, item); + item.setSubMenu(subMenu); + + return subMenu; + } + + public SubMenu addSubMenu(int group, int id, int categoryOrder, int title) { + return addSubMenu(group, id, categoryOrder, mResources.getString(title)); + } + + public int addIntentOptions(int group, int id, int categoryOrder, ComponentName caller, + Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) { + PackageManager pm = mContext.getPackageManager(); + final List lri = + pm.queryIntentActivityOptions(caller, specifics, intent, 0); + final int N = lri != null ? lri.size() : 0; + + if ((flags & FLAG_APPEND_TO_GROUP) == 0) { + removeGroup(group); + } + + for (int i=0; i= 0) { + outSpecificItems[ri.specificIndex] = item; + } + } + + return N; + } + + public void removeItem(int id) { + removeItemAtInt(findItemIndex(id), true); + } + + public void removeGroup(int group) { + final int i = findGroupIndex(group); + + if (i >= 0) { + final int maxRemovable = mItems.size() - i; + int numRemoved = 0; + while ((numRemoved++ < maxRemovable) && (mItems.get(i).getGroupId() == group)) { + // Don't force update for each one, this method will do it at the end + removeItemAtInt(i, false); + } + + // Notify menu views + onItemsChanged(true); + } + } + + /** + * Remove the item at the given index and optionally forces menu views to + * update. + * + * @param index The index of the item to be removed. If this index is + * invalid an exception is thrown. + * @param updateChildrenOnMenuViews Whether to force update on menu views. + * Please make sure you eventually call this after your batch of + * removals. + */ + private void removeItemAtInt(int index, boolean updateChildrenOnMenuViews) { + if ((index < 0) || (index >= mItems.size())) return; + + mItems.remove(index); + + if (updateChildrenOnMenuViews) onItemsChanged(true); + } + + public void removeItemAt(int index) { + removeItemAtInt(index, true); + } + + public void clearAll() { + mPreventDispatchingItemsChanged = true; + clear(); + clearHeader(); + mPreventDispatchingItemsChanged = false; + mItemsChangedWhileDispatchPrevented = false; + onItemsChanged(true); + } + + public void clear() { + if (mExpandedItem != null) { + collapseItemActionView(mExpandedItem); + } + mItems.clear(); + + onItemsChanged(true); + } + + void setExclusiveItemChecked(MenuItem item) { + final int group = item.getGroupId(); + + final int N = mItems.size(); + for (int i = 0; i < N; i++) { + MenuItemImpl curItem = mItems.get(i); + if (curItem.getGroupId() == group) { + if (!curItem.isExclusiveCheckable()) continue; + if (!curItem.isCheckable()) continue; + + // Check the item meant to be checked, uncheck the others (that are in the group) + curItem.setCheckedInt(curItem == item); + } + } + } + + public void setGroupCheckable(int group, boolean checkable, boolean exclusive) { + final int N = mItems.size(); + + for (int i = 0; i < N; i++) { + MenuItemImpl item = mItems.get(i); + if (item.getGroupId() == group) { + item.setExclusiveCheckable(exclusive); + item.setCheckable(checkable); + } + } + } + + public void setGroupVisible(int group, boolean visible) { + final int N = mItems.size(); + + // We handle the notification of items being changed ourselves, so we use setVisibleInt rather + // than setVisible and at the end notify of items being changed + + boolean changedAtLeastOneItem = false; + for (int i = 0; i < N; i++) { + MenuItemImpl item = mItems.get(i); + if (item.getGroupId() == group) { + if (item.setVisibleInt(visible)) changedAtLeastOneItem = true; + } + } + + if (changedAtLeastOneItem) onItemsChanged(true); + } + + public void setGroupEnabled(int group, boolean enabled) { + final int N = mItems.size(); + + for (int i = 0; i < N; i++) { + MenuItemImpl item = mItems.get(i); + if (item.getGroupId() == group) { + item.setEnabled(enabled); + } + } + } + + public boolean hasVisibleItems() { + final int size = size(); + + for (int i = 0; i < size; i++) { + MenuItemImpl item = mItems.get(i); + if (item.isVisible()) { + return true; + } + } + + return false; + } + + public MenuItem findItem(int id) { + final int size = size(); + for (int i = 0; i < size; i++) { + MenuItemImpl item = mItems.get(i); + if (item.getItemId() == id) { + return item; + } else if (item.hasSubMenu()) { + MenuItem possibleItem = item.getSubMenu().findItem(id); + + if (possibleItem != null) { + return possibleItem; + } + } + } + + return null; + } + + public int findItemIndex(int id) { + final int size = size(); + + for (int i = 0; i < size; i++) { + MenuItemImpl item = mItems.get(i); + if (item.getItemId() == id) { + return i; + } + } + + return -1; + } + + public int findGroupIndex(int group) { + return findGroupIndex(group, 0); + } + + public int findGroupIndex(int group, int start) { + final int size = size(); + + if (start < 0) { + start = 0; + } + + for (int i = start; i < size; i++) { + final MenuItemImpl item = mItems.get(i); + + if (item.getGroupId() == group) { + return i; + } + } + + return -1; + } + + public int size() { + return mItems.size(); + } + + /** {@inheritDoc} */ + public MenuItem getItem(int index) { + return mItems.get(index); + } + + public boolean isShortcutKey(int keyCode, KeyEvent event) { + return findItemWithShortcutForKey(keyCode, event) != null; + } + + public void setQwertyMode(boolean isQwerty) { + mQwertyMode = isQwerty; + + onItemsChanged(false); + } + + /** + * Returns the ordering across all items. This will grab the category from + * the upper bits, find out how to order the category with respect to other + * categories, and combine it with the lower bits. + * + * @param categoryOrder The category order for a particular item (if it has + * not been or/add with a category, the default category is + * assumed). + * @return An ordering integer that can be used to order this item across + * all the items (even from other categories). + */ + private static int getOrdering(int categoryOrder) { + final int index = (categoryOrder & CATEGORY_MASK) >> CATEGORY_SHIFT; + + if (index < 0 || index >= sCategoryToOrder.length) { + throw new IllegalArgumentException("order does not contain a valid category."); + } + + return (sCategoryToOrder[index] << CATEGORY_SHIFT) | (categoryOrder & USER_MASK); + } + + /** + * @return whether the menu shortcuts are in qwerty mode or not + */ + boolean isQwertyMode() { + return mQwertyMode; + } + + /** + * Sets whether the shortcuts should be visible on menus. Devices without hardware + * key input will never make shortcuts visible even if this method is passed 'true'. + * + * @param shortcutsVisible Whether shortcuts should be visible (if true and a + * menu item does not have a shortcut defined, that item will + * still NOT show a shortcut) + */ + public void setShortcutsVisible(boolean shortcutsVisible) { + if (mShortcutsVisible == shortcutsVisible) return; + + setShortcutsVisibleInner(shortcutsVisible); + onItemsChanged(false); + } + + private void setShortcutsVisibleInner(boolean shortcutsVisible) { + mShortcutsVisible = shortcutsVisible + && mResources.getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS + && mResources.getBoolean( + R.bool.abs__config_showMenuShortcutsWhenKeyboardPresent); + } + + /** + * @return Whether shortcuts should be visible on menus. + */ + public boolean isShortcutsVisible() { + return mShortcutsVisible; + } + + Resources getResources() { + return mResources; + } + + public Context getContext() { + return mContext; + } + + boolean dispatchMenuItemSelected(MenuBuilder menu, MenuItem item) { + return mCallback != null && mCallback.onMenuItemSelected(menu, item); + } + + /** + * Dispatch a mode change event to this menu's callback. + */ + public void changeMenuMode() { + if (mCallback != null) { + mCallback.onMenuModeChange(this); + } + } + + private static int findInsertIndex(ArrayList items, int ordering) { + for (int i = items.size() - 1; i >= 0; i--) { + MenuItemImpl item = items.get(i); + if (item.getOrdering() <= ordering) { + return i + 1; + } + } + + return 0; + } + + public boolean performShortcut(int keyCode, KeyEvent event, int flags) { + final MenuItemImpl item = findItemWithShortcutForKey(keyCode, event); + + boolean handled = false; + + if (item != null) { + handled = performItemAction(item, flags); + } + + if ((flags & FLAG_ALWAYS_PERFORM_CLOSE) != 0) { + close(true); + } + + return handled; + } + + /* + * This function will return all the menu and sub-menu items that can + * be directly (the shortcut directly corresponds) and indirectly + * (the ALT-enabled char corresponds to the shortcut) associated + * with the keyCode. + */ + @SuppressWarnings("deprecation") + void findItemsWithShortcutForKey(List items, int keyCode, KeyEvent event) { + final boolean qwerty = isQwertyMode(); + final int metaState = event.getMetaState(); + final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData(); + // Get the chars associated with the keyCode (i.e using any chording combo) + final boolean isKeyCodeMapped = event.getKeyData(possibleChars); + // The delete key is not mapped to '\b' so we treat it specially + if (!isKeyCodeMapped && (keyCode != KeyEvent.KEYCODE_DEL)) { + return; + } + + // Look for an item whose shortcut is this key. + final int N = mItems.size(); + for (int i = 0; i < N; i++) { + MenuItemImpl item = mItems.get(i); + if (item.hasSubMenu()) { + ((MenuBuilder)item.getSubMenu()).findItemsWithShortcutForKey(items, keyCode, event); + } + final char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut(); + if (((metaState & (KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) && + (shortcutChar != 0) && + (shortcutChar == possibleChars.meta[0] + || shortcutChar == possibleChars.meta[2] + || (qwerty && shortcutChar == '\b' && + keyCode == KeyEvent.KEYCODE_DEL)) && + item.isEnabled()) { + items.add(item); + } + } + } + + /* + * We want to return the menu item associated with the key, but if there is no + * ambiguity (i.e. there is only one menu item corresponding to the key) we want + * to return it even if it's not an exact match; this allow the user to + * _not_ use the ALT key for example, making the use of shortcuts slightly more + * user-friendly. An example is on the G1, '!' and '1' are on the same key, and + * in Gmail, Menu+1 will trigger Menu+! (the actual shortcut). + * + * On the other hand, if two (or more) shortcuts corresponds to the same key, + * we have to only return the exact match. + */ + @SuppressWarnings("deprecation") + MenuItemImpl findItemWithShortcutForKey(int keyCode, KeyEvent event) { + // Get all items that can be associated directly or indirectly with the keyCode + ArrayList items = mTempShortcutItemList; + items.clear(); + findItemsWithShortcutForKey(items, keyCode, event); + + if (items.isEmpty()) { + return null; + } + + final int metaState = event.getMetaState(); + final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData(); + // Get the chars associated with the keyCode (i.e using any chording combo) + event.getKeyData(possibleChars); + + // If we have only one element, we can safely returns it + final int size = items.size(); + if (size == 1) { + return items.get(0); + } + + final boolean qwerty = isQwertyMode(); + // If we found more than one item associated with the key, + // we have to return the exact match + for (int i = 0; i < size; i++) { + final MenuItemImpl item = items.get(i); + final char shortcutChar = qwerty ? item.getAlphabeticShortcut() : + item.getNumericShortcut(); + if ((shortcutChar == possibleChars.meta[0] && + (metaState & KeyEvent.META_ALT_ON) == 0) + || (shortcutChar == possibleChars.meta[2] && + (metaState & KeyEvent.META_ALT_ON) != 0) + || (qwerty && shortcutChar == '\b' && + keyCode == KeyEvent.KEYCODE_DEL)) { + return item; + } + } + return null; + } + + public boolean performIdentifierAction(int id, int flags) { + // Look for an item whose identifier is the id. + return performItemAction(findItem(id), flags); + } + + public boolean performItemAction(MenuItem item, int flags) { + MenuItemImpl itemImpl = (MenuItemImpl) item; + + if (itemImpl == null || !itemImpl.isEnabled()) { + return false; + } + + boolean invoked = itemImpl.invoke(); + + if (itemImpl.hasCollapsibleActionView()) { + invoked |= itemImpl.expandActionView(); + if (invoked) close(true); + } else if (item.hasSubMenu()) { + close(false); + + final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu(); + final ActionProvider provider = item.getActionProvider(); + if (provider != null && provider.hasSubMenu()) { + provider.onPrepareSubMenu(subMenu); + } + invoked |= dispatchSubMenuSelected(subMenu); + if (!invoked) close(true); + } else { + if ((flags & FLAG_PERFORM_NO_CLOSE) == 0) { + close(true); + } + } + + return invoked; + } + + /** + * Closes the visible menu. + * + * @param allMenusAreClosing Whether the menus are completely closing (true), + * or whether there is another menu coming in this menu's place + * (false). For example, if the menu is closing because a + * sub menu is about to be shown, allMenusAreClosing + * is false. + */ + final void close(boolean allMenusAreClosing) { + if (mIsClosing) return; + + mIsClosing = true; + for (WeakReference ref : mPresenters) { + final MenuPresenter presenter = ref.get(); + if (presenter == null) { + mPresenters.remove(ref); + } else { + presenter.onCloseMenu(this, allMenusAreClosing); + } + } + mIsClosing = false; + } + + /** {@inheritDoc} */ + public void close() { + close(true); + } + + /** + * Called when an item is added or removed. + * + * @param structureChanged true if the menu structure changed, + * false if only item properties changed. + * (Visibility is a structural property since it affects layout.) + */ + void onItemsChanged(boolean structureChanged) { + if (!mPreventDispatchingItemsChanged) { + if (structureChanged) { + mIsVisibleItemsStale = true; + mIsActionItemsStale = true; + } + + dispatchPresenterUpdate(structureChanged); + } else { + mItemsChangedWhileDispatchPrevented = true; + } + } + + /** + * Stop dispatching item changed events to presenters until + * {@link #startDispatchingItemsChanged()} is called. Useful when + * many menu operations are going to be performed as a batch. + */ + public void stopDispatchingItemsChanged() { + if (!mPreventDispatchingItemsChanged) { + mPreventDispatchingItemsChanged = true; + mItemsChangedWhileDispatchPrevented = false; + } + } + + public void startDispatchingItemsChanged() { + mPreventDispatchingItemsChanged = false; + + if (mItemsChangedWhileDispatchPrevented) { + mItemsChangedWhileDispatchPrevented = false; + onItemsChanged(true); + } + } + + /** + * Called by {@link MenuItemImpl} when its visible flag is changed. + * @param item The item that has gone through a visibility change. + */ + void onItemVisibleChanged(MenuItemImpl item) { + // Notify of items being changed + mIsVisibleItemsStale = true; + onItemsChanged(true); + } + + /** + * Called by {@link MenuItemImpl} when its action request status is changed. + * @param item The item that has gone through a change in action request status. + */ + void onItemActionRequestChanged(MenuItemImpl item) { + // Notify of items being changed + mIsActionItemsStale = true; + onItemsChanged(true); + } + + ArrayList getVisibleItems() { + if (!mIsVisibleItemsStale) return mVisibleItems; + + // Refresh the visible items + mVisibleItems.clear(); + + final int itemsSize = mItems.size(); + MenuItemImpl item; + for (int i = 0; i < itemsSize; i++) { + item = mItems.get(i); + if (item.isVisible()) mVisibleItems.add(item); + } + + mIsVisibleItemsStale = false; + mIsActionItemsStale = true; + + return mVisibleItems; + } + + /** + * This method determines which menu items get to be 'action items' that will appear + * in an action bar and which items should be 'overflow items' in a secondary menu. + * The rules are as follows: + * + *

Items are considered for inclusion in the order specified within the menu. + * There is a limit of mMaxActionItems as a total count, optionally including the overflow + * menu button itself. This is a soft limit; if an item shares a group ID with an item + * previously included as an action item, the new item will stay with its group and become + * an action item itself even if it breaks the max item count limit. This is done to + * limit the conceptual complexity of the items presented within an action bar. Only a few + * unrelated concepts should be presented to the user in this space, and groups are treated + * as a single concept. + * + *

There is also a hard limit of consumed measurable space: mActionWidthLimit. This + * limit may be broken by a single item that exceeds the remaining space, but no further + * items may be added. If an item that is part of a group cannot fit within the remaining + * measured width, the entire group will be demoted to overflow. This is done to ensure room + * for navigation and other affordances in the action bar as well as reduce general UI clutter. + * + *

The space freed by demoting a full group cannot be consumed by future menu items. + * Once items begin to overflow, all future items become overflow items as well. This is + * to avoid inadvertent reordering that may break the app's intended design. + */ + public void flagActionItems() { + if (!mIsActionItemsStale) { + return; + } + + // Presenters flag action items as needed. + boolean flagged = false; + for (WeakReference ref : mPresenters) { + final MenuPresenter presenter = ref.get(); + if (presenter == null) { + mPresenters.remove(ref); + } else { + flagged |= presenter.flagActionItems(); + } + } + + if (flagged) { + mActionItems.clear(); + mNonActionItems.clear(); + ArrayList visibleItems = getVisibleItems(); + final int itemsSize = visibleItems.size(); + for (int i = 0; i < itemsSize; i++) { + MenuItemImpl item = visibleItems.get(i); + if (item.isActionButton()) { + mActionItems.add(item); + } else { + mNonActionItems.add(item); + } + } + } else { + // Nobody flagged anything, everything is a non-action item. + // (This happens during a first pass with no action-item presenters.) + mActionItems.clear(); + mNonActionItems.clear(); + mNonActionItems.addAll(getVisibleItems()); + } + mIsActionItemsStale = false; + } + + ArrayList getActionItems() { + flagActionItems(); + return mActionItems; + } + + ArrayList getNonActionItems() { + flagActionItems(); + return mNonActionItems; + } + + public void clearHeader() { + mHeaderIcon = null; + mHeaderTitle = null; + mHeaderView = null; + + onItemsChanged(false); + } + + private void setHeaderInternal(final int titleRes, final CharSequence title, final int iconRes, + final Drawable icon, final View view) { + final Resources r = getResources(); + + if (view != null) { + mHeaderView = view; + + // If using a custom view, then the title and icon aren't used + mHeaderTitle = null; + mHeaderIcon = null; + } else { + if (titleRes > 0) { + mHeaderTitle = r.getText(titleRes); + } else if (title != null) { + mHeaderTitle = title; + } + + if (iconRes > 0) { + mHeaderIcon = r.getDrawable(iconRes); + } else if (icon != null) { + mHeaderIcon = icon; + } + + // If using the title or icon, then a custom view isn't used + mHeaderView = null; + } + + // Notify of change + onItemsChanged(false); + } + + /** + * Sets the header's title. This replaces the header view. Called by the + * builder-style methods of subclasses. + * + * @param title The new title. + * @return This MenuBuilder so additional setters can be called. + */ + protected MenuBuilder setHeaderTitleInt(CharSequence title) { + setHeaderInternal(0, title, 0, null, null); + return this; + } + + /** + * Sets the header's title. This replaces the header view. Called by the + * builder-style methods of subclasses. + * + * @param titleRes The new title (as a resource ID). + * @return This MenuBuilder so additional setters can be called. + */ + protected MenuBuilder setHeaderTitleInt(int titleRes) { + setHeaderInternal(titleRes, null, 0, null, null); + return this; + } + + /** + * Sets the header's icon. This replaces the header view. Called by the + * builder-style methods of subclasses. + * + * @param icon The new icon. + * @return This MenuBuilder so additional setters can be called. + */ + protected MenuBuilder setHeaderIconInt(Drawable icon) { + setHeaderInternal(0, null, 0, icon, null); + return this; + } + + /** + * Sets the header's icon. This replaces the header view. Called by the + * builder-style methods of subclasses. + * + * @param iconRes The new icon (as a resource ID). + * @return This MenuBuilder so additional setters can be called. + */ + protected MenuBuilder setHeaderIconInt(int iconRes) { + setHeaderInternal(0, null, iconRes, null, null); + return this; + } + + /** + * Sets the header's view. This replaces the title and icon. Called by the + * builder-style methods of subclasses. + * + * @param view The new view. + * @return This MenuBuilder so additional setters can be called. + */ + protected MenuBuilder setHeaderViewInt(View view) { + setHeaderInternal(0, null, 0, null, view); + return this; + } + + public CharSequence getHeaderTitle() { + return mHeaderTitle; + } + + public Drawable getHeaderIcon() { + return mHeaderIcon; + } + + public View getHeaderView() { + return mHeaderView; + } + + /** + * Gets the root menu (if this is a submenu, find its root menu). + * @return The root menu. + */ + public MenuBuilder getRootMenu() { + return this; + } + + /** + * Sets the current menu info that is set on all items added to this menu + * (until this is called again with different menu info, in which case that + * one will be added to all subsequent item additions). + * + * @param menuInfo The extra menu information to add. + */ + public void setCurrentMenuInfo(ContextMenuInfo menuInfo) { + mCurrentMenuInfo = menuInfo; + } + + void setOptionalIconsVisible(boolean visible) { + mOptionalIconsVisible = visible; + } + + boolean getOptionalIconsVisible() { + return mOptionalIconsVisible; + } + + public boolean expandItemActionView(MenuItemImpl item) { + if (mPresenters.isEmpty()) return false; + + boolean expanded = false; + + stopDispatchingItemsChanged(); + for (WeakReference ref : mPresenters) { + final MenuPresenter presenter = ref.get(); + if (presenter == null) { + mPresenters.remove(ref); + } else if ((expanded = presenter.expandItemActionView(this, item))) { + break; + } + } + startDispatchingItemsChanged(); + + if (expanded) { + mExpandedItem = item; + } + return expanded; + } + + public boolean collapseItemActionView(MenuItemImpl item) { + if (mPresenters.isEmpty() || mExpandedItem != item) return false; + + boolean collapsed = false; + + stopDispatchingItemsChanged(); + for (WeakReference ref : mPresenters) { + final MenuPresenter presenter = ref.get(); + if (presenter == null) { + mPresenters.remove(ref); + } else if ((collapsed = presenter.collapseItemActionView(this, item))) { + break; + } + } + startDispatchingItemsChanged(); + + if (collapsed) { + mExpandedItem = null; + } + return collapsed; + } + + public MenuItemImpl getExpandedItem() { + return mExpandedItem; + } + + public boolean bindNativeOverflow(android.view.Menu menu, android.view.MenuItem.OnMenuItemClickListener listener, HashMap map) { + final List nonActionItems = getNonActionItems(); + if (nonActionItems == null || nonActionItems.size() == 0) { + return false; + } + + boolean visible = false; + menu.clear(); + for (MenuItemImpl nonActionItem : nonActionItems) { + if (!nonActionItem.isVisible()) { + continue; + } + visible = true; + + android.view.MenuItem nativeItem; + if (nonActionItem.hasSubMenu()) { + android.view.SubMenu nativeSub = menu.addSubMenu(nonActionItem.getGroupId(), nonActionItem.getItemId(), + nonActionItem.getOrder(), nonActionItem.getTitle()); + + SubMenuBuilder subMenu = (SubMenuBuilder)nonActionItem.getSubMenu(); + for (MenuItemImpl subItem : subMenu.getVisibleItems()) { + android.view.MenuItem nativeSubItem = nativeSub.add(subItem.getGroupId(), subItem.getItemId(), + subItem.getOrder(), subItem.getTitle()); + + nativeSubItem.setIcon(subItem.getIcon()); + nativeSubItem.setOnMenuItemClickListener(listener); + nativeSubItem.setEnabled(subItem.isEnabled()); + nativeSubItem.setIntent(subItem.getIntent()); + nativeSubItem.setNumericShortcut(subItem.getNumericShortcut()); + nativeSubItem.setAlphabeticShortcut(subItem.getAlphabeticShortcut()); + nativeSubItem.setTitleCondensed(subItem.getTitleCondensed()); + nativeSubItem.setCheckable(subItem.isCheckable()); + nativeSubItem.setChecked(subItem.isChecked()); + + if (subItem.isExclusiveCheckable()) { + nativeSub.setGroupCheckable(subItem.getGroupId(), true, true); + } + + map.put(nativeSubItem, subItem); + } + + nativeItem = nativeSub.getItem(); + } else { + nativeItem = menu.add(nonActionItem.getGroupId(), nonActionItem.getItemId(), + nonActionItem.getOrder(), nonActionItem.getTitle()); + } + nativeItem.setIcon(nonActionItem.getIcon()); + nativeItem.setOnMenuItemClickListener(listener); + nativeItem.setEnabled(nonActionItem.isEnabled()); + nativeItem.setIntent(nonActionItem.getIntent()); + nativeItem.setNumericShortcut(nonActionItem.getNumericShortcut()); + nativeItem.setAlphabeticShortcut(nonActionItem.getAlphabeticShortcut()); + nativeItem.setTitleCondensed(nonActionItem.getTitleCondensed()); + nativeItem.setCheckable(nonActionItem.isCheckable()); + nativeItem.setChecked(nonActionItem.isChecked()); + + if (nonActionItem.isExclusiveCheckable()) { + menu.setGroupCheckable(nonActionItem.getGroupId(), true, true); + } + + map.put(nativeItem, nonActionItem); + } + return visible; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuInflaterWrapper.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuInflaterWrapper.java deleted file mode 100644 index 29040bab..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuInflaterWrapper.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.actionbarsherlock.internal.view.menu; - -import android.content.Context; - -public final class MenuInflaterWrapper extends android.view.MenuInflater { - private final android.view.MenuInflater mMenuInflater; - - public MenuInflaterWrapper(Context context, android.view.MenuInflater menuInflater) { - super(context); - mMenuInflater = menuInflater; - } - - @Override - public void inflate(int menuRes, android.view.Menu menu) { - if (menu instanceof MenuWrapper) { - mMenuInflater.inflate(menuRes, ((MenuWrapper)menu).unwrap()); - } else { - mMenuInflater.inflate(menuRes, menu); - } - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuItemImpl.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuItemImpl.java index 0970d7ed..f5359fb4 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuItemImpl.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuItemImpl.java @@ -1,663 +1,647 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * 2011 Jake Wharton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.actionbarsherlock.internal.view.menu; - -import java.lang.ref.WeakReference; -import android.app.AlertDialog; -import android.content.ActivityNotFoundException; -import android.content.DialogInterface; -import android.content.Intent; -import android.graphics.drawable.Drawable; -import android.support.v4.view.MenuItem; -import android.util.Log; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.LayoutInflater; -import android.view.View; - -/** - * An implementation of the {@link android.view.MenuItem} interface for use in - * inflating menu XML resources to be added to a third-party action bar. - * - * @author Jake Wharton - * @see com.android.internal.view.menu.MenuItemImpl - */ -public final class MenuItemImpl implements MenuItem { - private static final String TAG = "MenuItemImpl"; - - private final MenuBuilder mMenu; - - private final int mItemId; - private final int mGroupId; - private final int mCategoryOrder; - private final int mOrdering; - - private Intent mIntent; - private CharSequence mTitle; - private CharSequence mTitleCondensed; - private char mNumericalShortcut; - private char mAlphabeticalShortcut; - private int mShowAsAction; - private SubMenuBuilder mSubMenu; - private Runnable mItemCallback; - private OnMenuItemClickListener mClickListener; - private Drawable mIcon; - private int mIconRes = View.NO_ID; - private View mActionView; - private int mActionViewRes = View.NO_ID; - - int mFlags = ENABLED; - static final int CHECKABLE = 0x01; - static final int CHECKED = 0x02; - static final int EXCLUSIVE = 0x04; - static final int HIDDEN = 0x08; - static final int ENABLED = 0x10; - static final int IS_ACTION = 0x20; - - private final WeakReference[] mItemViews; - - private final DialogInterface.OnClickListener subMenuClick = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int index) { - dialog.dismiss(); - mSubMenu.getItem(index).invoke(); - } - }; - private final DialogInterface.OnMultiChoiceClickListener subMenuMultiClick = new DialogInterface.OnMultiChoiceClickListener() { - @Override - public void onClick(DialogInterface dialog, int index, boolean isChecked) { - dialog.dismiss(); - mSubMenu.getItem(index).setChecked(isChecked); - } - }; - - - /** - * Create a new action bar menu item. - * - * @param context Context used if resource resolution is required. - * @param itemId A unique ID. Used in the activity callback. - * @param groupId Group ID. Currently unused. - * @param order Item order. Currently unused. - * @param title Title of the item. - */ - @SuppressWarnings("unchecked") - public MenuItemImpl(MenuBuilder menu, int groupId, int itemId, int order, int ordering, CharSequence title, int showAsAction) { - mMenu = menu; - - mItemId = itemId; - mGroupId = groupId; - mCategoryOrder = order; - mOrdering = ordering; - mTitle = title; - mShowAsAction = showAsAction; - - mItemViews = new WeakReference[MenuBuilder.NUM_TYPES]; - } - - - - public boolean invoke() { - if (hasSubMenu()) { - AlertDialog.Builder builder = new AlertDialog.Builder(mMenu.getContext()); - builder.setTitle(getTitle()); - - final boolean isExclusive = mSubMenu.getItem(0).isExclusiveCheckable(); - final boolean isCheckable = mSubMenu.getItem(0).isCheckable(); - final CharSequence[] titles = getSubMenuTitles(); - if (isExclusive) { - builder.setSingleChoiceItems(titles, getSubMenuSelected(), subMenuClick); - } else if (isCheckable) { - builder.setMultiChoiceItems(titles, getSubMenuChecked(), subMenuMultiClick); - } else { - builder.setItems(titles, subMenuClick); - } - - builder.show(); - return true; - } - - if (mClickListener != null && - mClickListener.onMenuItemClick(this)) { - return true; - } - - MenuBuilder.Callback callback = mMenu.getRootMenu().getCallback(); - if (callback != null && - callback.onMenuItemSelected(mMenu.getRootMenu(), this)) { - return true; - } - - if (mItemCallback != null) { - mItemCallback.run(); - return true; - } - - if (mIntent != null) { - try { - mMenu.getContext().startActivity(mIntent); - return true; - } catch (ActivityNotFoundException e) { - Log.e(TAG, "Can't find activity to handle intent; ignoring", e); - } - } - - return false; - } - - private CharSequence[] getSubMenuTitles() { - final int count = mSubMenu.size(); - CharSequence[] list = new CharSequence[count]; - for (int i = 0; i < count; i++) { - list[i] = mSubMenu.getItem(i).getTitle(); - } - return list; - } - - private int getSubMenuSelected() { - final int count = mSubMenu.size(); - for (int i = 0; i < count; i++) { - if (mSubMenu.getItem(i).isChecked()) { - return i; - } - } - return -1; - } - - private boolean[] getSubMenuChecked() { - final int count = mSubMenu.size(); - boolean[] checked = new boolean[count]; - for (int i = 0; i < count; i++) { - checked[i] = mSubMenu.getItem(i).isChecked(); - } - return checked; - } - - private boolean hasItemView(int menuType) { - return mItemViews[menuType] != null && mItemViews[menuType].get() != null; - } - - public void setItemView(int type, MenuView.ItemView itemView) { - mItemViews[type] = new WeakReference(itemView); - } - - - public void addTo(android.view.Menu menu) { - if (hasSubMenu()) { - android.view.SubMenu subMenu = menu.addSubMenu(mGroupId, mItemId, mCategoryOrder, mTitle); - if (mIconRes != View.NO_ID) { - subMenu.setIcon(mIconRes); - } else { - subMenu.setIcon(mIcon); - } - for (MenuItemImpl item : mSubMenu.getItems()) { - item.addTo(subMenu); - } - - if (mSubMenu.getItem(0).isExclusiveCheckable()) { - int checked = getSubMenuSelected(); - if (checked != -1) { - subMenu.getItem(checked).setChecked(true); - } - } - } else { - android.view.MenuItem item = menu.add(mGroupId, mItemId, mCategoryOrder, mTitle) - .setAlphabeticShortcut(mAlphabeticalShortcut) - .setNumericShortcut(mNumericalShortcut) - .setVisible(isVisible()) - .setIntent(mIntent) - .setCheckable(isCheckable()) - .setChecked(isChecked()) - .setOnMenuItemClickListener(mClickListener); - - if (isExclusiveCheckable()) { - menu.setGroupCheckable(mGroupId, true, true); - } - - //Create and initialize a native itemview wrapper - NativeMenuItemView nativeWrapper = new NativeMenuItemView(item); - nativeWrapper.initialize(this, MenuBuilder.TYPE_NATIVE); - - //Associate the itemview to this so changes will be reflected - setItemView(MenuBuilder.TYPE_NATIVE, nativeWrapper); - } - } - - /** - * Get whether or not this item is being shown on the action bar. - * - * @return {@code true} if shown, {@code false} otherwise. - */ - public boolean isShownOnActionBar() { - return (mFlags & IS_ACTION) == IS_ACTION; - } - - /** - * Denote whether or not this menu item is being shown on the action bar. - * - * @param isShownOnActionBar {@code true} if shown or {@code false}. - */ - public void setIsShownOnActionBar(boolean isShownOnActionBar) { - mFlags = (mFlags & ~IS_ACTION) | (isShownOnActionBar ? IS_ACTION : 0); - } - - @Override - public Intent getIntent() { - return this.mIntent; - } - - @Override - public int getItemId() { - return this.mItemId; - } - - @Override - public CharSequence getTitle() { - return this.mTitle; - } - - @Override - public boolean isEnabled() { - return (mFlags & ENABLED) != 0; - } - - @Override - public boolean isVisible() { - return (mFlags & HIDDEN) == 0; - } - - @Override - public MenuItem setEnabled(boolean enabled) { - final boolean oldValue = isEnabled(); - mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0); - - if (oldValue != enabled) { - for (int i = MenuBuilder.NUM_TYPES - 1; i >= 0; i--) { - if (hasItemView(i)) { - mItemViews[i].get().setEnabled(enabled); - } - } - } - - return this; - } - - @Override - public MenuItem setIcon(int iconResourceId) { - mIcon = null; - mIconRes = iconResourceId; - - if (mIconRes != View.NO_ID) { - setIconOnViews(mMenu.getContext().getResources().getDrawable(mIconRes)); - } - - return this; - } - - @Override - public MenuItem setIntent(Intent intent) { - mIntent = intent; - return this; - } - - @Override - public MenuItem setTitle(CharSequence title) { - mTitle = title; - return this; - } - - @Override - public MenuItem setTitle(int titleResourceId) { - mTitle = mMenu.getContext().getResources().getString(titleResourceId); - return this; - } - - @Override - public MenuItem setVisible(boolean visible) { - final boolean oldValue = isVisible(); - mFlags = (mFlags & ~HIDDEN) | (visible ? 0 : HIDDEN); - if (oldValue != visible) { - for (int i = MenuBuilder.NUM_TYPES - 1; i >= 0; i--) { - if (hasItemView(i)) { - mItemViews[i].get().setVisible(visible); - } - } - } - return this; - } - - @Override - public boolean isChecked() { - return (mFlags & CHECKED) == CHECKED; - } - - @Override - public MenuItem setChecked(boolean checked) { - if ((mFlags & EXCLUSIVE) == EXCLUSIVE) { - // Call the method on the Menu since it knows about the others in this - // exclusive checkable group - mMenu.setExclusiveItemChecked(this); - } else { - setCheckedInt(checked); - } - - return this; - } - - void setCheckedInt(boolean checked) { - final boolean oldValue = isChecked(); - mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0); - if (oldValue != checked) { - for (int i = MenuBuilder.NUM_TYPES - 1; i >= 0; i--) { - if (hasItemView(i)) { - mItemViews[i].get().setChecked(checked); - } - } - } - } - - @Override - public boolean isCheckable() { - return (mFlags & CHECKABLE) == CHECKABLE; - } - - @Override - public MenuItem setCheckable(boolean checkable) { - final boolean oldValue = isCheckable(); - mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0); - if (oldValue != checkable) { - for (int i = MenuBuilder.NUM_TYPES - 1; i >= 0; i--) { - if (hasItemView(i)) { - mItemViews[i].get().setCheckable(checkable); - } - } - } - - return this; - } - - public void setExclusiveCheckable(boolean exclusive) { - mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0); - } - - public boolean isExclusiveCheckable() { - return (mFlags & EXCLUSIVE) == EXCLUSIVE; - } - - @Override - public CharSequence getTitleCondensed() { - return mTitleCondensed; - } - - @Override - public MenuItem setTitleCondensed(CharSequence title) { - mTitleCondensed = title; - return this; - } - - @Override - public int getGroupId() { - return mGroupId; - } - - @Override - public int getOrder() { - return mCategoryOrder; - } - - public int getOrdering() { - return mOrdering; - } - - @Override - public SubMenuBuilder getSubMenu() { - return mSubMenu; - } - - /** - * Set the sub-menu of this item. - * - * @param subMenu Sub-menu instance. - * @return This Item so additional setters can be called. - */ - MenuItem setSubMenu(SubMenuBuilder subMenu) { - mSubMenu = subMenu; - return this; - } - - @Override - public boolean hasSubMenu() { - return (mSubMenu != null) && (mSubMenu.size() > 0); - } - - @Override - public char getAlphabeticShortcut() { - return mAlphabeticalShortcut; - } - - @Override - public char getNumericShortcut() { - return mNumericalShortcut; - } - - @Override - public MenuItem setAlphabeticShortcut(char alphaChar) { - mAlphabeticalShortcut = Character.toLowerCase(alphaChar); - return this; - } - - @Override - public MenuItem setNumericShortcut(char numericChar) { - mNumericalShortcut = numericChar; - return this; - } - - @Override - public MenuItem setShortcut(char numericChar, char alphaChar) { - setNumericShortcut(numericChar); - setAlphabeticShortcut(alphaChar); - return this; - } - - @Override - public void setShowAsAction(int actionEnum) { - mShowAsAction = actionEnum; - } - - public int getShowAsAction() { - return mShowAsAction; - } - - public boolean showsActionItemText() { - return mMenu.getShowsActionItemText(); - } - - @Override - public View getActionView() { - if (mActionView != null) { - return mActionView; - } - if (mActionViewRes != View.NO_ID) { - return LayoutInflater.from(mMenu.getContext()).inflate(mActionViewRes, null, false); - } - return null; - } - - @Override - public Drawable getIcon() { - if (mIcon != null) { - return mIcon; - } - if (mIconRes != View.NO_ID) { - return mMenu.getContext().getResources().getDrawable(mIconRes); - } - return null; - } - - @Override - public ContextMenuInfo getMenuInfo() { - return null; - } - - @Override - public MenuItem setActionView(View view) { - mActionView = view; - mActionViewRes = View.NO_ID; - setActionViewOnViews(mActionView); - return this; - } - - @Override - public MenuItem setActionView(int resId) { - mActionView = null; - mActionViewRes = resId; - - if (mActionViewRes != View.NO_ID) { - setActionViewOnViews(LayoutInflater.from(mMenu.getContext()).inflate(mActionViewRes, null, false)); - } - - return this; - } - - void setActionViewOnViews(View view) { - for (int i = MenuBuilder.NUM_TYPES - 1; i >= 0; i--) { - if (hasItemView(i)) { - mItemViews[i].get().setActionView(view); - } - } - } - - @Override - public MenuItem setIcon(Drawable icon) { - mIcon = icon; - mIconRes = View.NO_ID; - setIconOnViews(icon); - return this; - } - - void setIconOnViews(Drawable icon) { - for (int i = MenuBuilder.NUM_TYPES - 1; i >= 0; i--) { - if (hasItemView(i)) { - mItemViews[i].get().setIcon(icon); - } - } - } - - @Override - public android.view.MenuItem setOnMenuItemClickListener(final android.view.MenuItem.OnMenuItemClickListener menuItemClickListener) { - return this.setOnMenuItemClickListener(new OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - return menuItemClickListener.onMenuItemClick(new MenuItemWrapper(item)); - } - }); - } - - @Override - public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) { - mClickListener = menuItemClickListener; - return this; - } - - /** - * Returns the currently set menu click listener for this item. - * - * @return Click listener or {@code null}. - */ - public OnMenuItemClickListener getOnMenuItemClickListener() { - return mClickListener; - } - - - - - public static final class NativeMenuItemView implements MenuView.ItemView { - private final android.view.MenuItem mItem; - - - public NativeMenuItemView(android.view.MenuItem item) { - mItem = item; - } - - - @Override - public MenuItemImpl getItemData() { - return null; - } - - @Override - public void initialize(MenuItemImpl itemData, int menuType) { - setIcon(itemData.getIcon()); - setTitle(itemData.getTitle()); - setEnabled(itemData.isEnabled()); - setCheckable(itemData.isCheckable()); - setChecked(itemData.isChecked()); - setActionView(itemData.getActionView()); - setVisible(itemData.isVisible()); - } - - @Override - public boolean prefersCondensedTitle() { - return true; - } - - @Override - public void setCheckable(boolean checkable) { - mItem.setCheckable(checkable); - } - - @Override - public void setChecked(boolean checked) { - mItem.setChecked(checked); - } - - @Override - public void setEnabled(boolean enabled) { - mItem.setEnabled(enabled); - } - - @Override - public void setIcon(Drawable icon) { - mItem.setIcon(icon); - } - - @Override - public void setShortcut(boolean showShortcut, char shortcutKey) { - //Not supported - } - - @Override - public void setTitle(CharSequence title) { - mItem.setTitle(title); - } - - @Override - public boolean showsIcon() { - return true; - } - - @Override - public void setActionView(View actionView) { - //Not supported - } - - @Override - public void setVisible(boolean visible) { - mItem.setVisible(visible); - } - } -} \ No newline at end of file +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.view.menu; + +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewDebug; +import android.widget.LinearLayout; + +import com.actionbarsherlock.view.ActionProvider; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; + +/** + * @hide + */ +public final class MenuItemImpl implements MenuItem { + private static final String TAG = "MenuItemImpl"; + + private static final int SHOW_AS_ACTION_MASK = SHOW_AS_ACTION_NEVER | + SHOW_AS_ACTION_IF_ROOM | + SHOW_AS_ACTION_ALWAYS; + + private final int mId; + private final int mGroup; + private final int mCategoryOrder; + private final int mOrdering; + private CharSequence mTitle; + private CharSequence mTitleCondensed; + private Intent mIntent; + private char mShortcutNumericChar; + private char mShortcutAlphabeticChar; + + /** The icon's drawable which is only created as needed */ + private Drawable mIconDrawable; + /** + * The icon's resource ID which is used to get the Drawable when it is + * needed (if the Drawable isn't already obtained--only one of the two is + * needed). + */ + private int mIconResId = NO_ICON; + + /** The menu to which this item belongs */ + private MenuBuilder mMenu; + /** If this item should launch a sub menu, this is the sub menu to launch */ + private SubMenuBuilder mSubMenu; + + private Runnable mItemCallback; + private MenuItem.OnMenuItemClickListener mClickListener; + + private int mFlags = ENABLED; + private static final int CHECKABLE = 0x00000001; + private static final int CHECKED = 0x00000002; + private static final int EXCLUSIVE = 0x00000004; + private static final int HIDDEN = 0x00000008; + private static final int ENABLED = 0x00000010; + private static final int IS_ACTION = 0x00000020; + + private int mShowAsAction = SHOW_AS_ACTION_NEVER; + + private View mActionView; + private ActionProvider mActionProvider; + private OnActionExpandListener mOnActionExpandListener; + private boolean mIsActionViewExpanded = false; + + /** Used for the icon resource ID if this item does not have an icon */ + static final int NO_ICON = 0; + + /** + * Current use case is for context menu: Extra information linked to the + * View that added this item to the context menu. + */ + private ContextMenuInfo mMenuInfo; + + private static String sPrependShortcutLabel; + private static String sEnterShortcutLabel; + private static String sDeleteShortcutLabel; + private static String sSpaceShortcutLabel; + + + /** + * Instantiates this menu item. + * + * @param menu + * @param group Item ordering grouping control. The item will be added after + * all other items whose order is <= this number, and before any + * that are larger than it. This can also be used to define + * groups of items for batch state changes. Normally use 0. + * @param id Unique item ID. Use 0 if you do not need a unique ID. + * @param categoryOrder The ordering for this item. + * @param title The text to display for the item. + */ + MenuItemImpl(MenuBuilder menu, int group, int id, int categoryOrder, int ordering, + CharSequence title, int showAsAction) { + + /* TODO if (sPrependShortcutLabel == null) { + // This is instantiated from the UI thread, so no chance of sync issues + sPrependShortcutLabel = menu.getContext().getResources().getString( + com.android.internal.R.string.prepend_shortcut_label); + sEnterShortcutLabel = menu.getContext().getResources().getString( + com.android.internal.R.string.menu_enter_shortcut_label); + sDeleteShortcutLabel = menu.getContext().getResources().getString( + com.android.internal.R.string.menu_delete_shortcut_label); + sSpaceShortcutLabel = menu.getContext().getResources().getString( + com.android.internal.R.string.menu_space_shortcut_label); + }*/ + + mMenu = menu; + mId = id; + mGroup = group; + mCategoryOrder = categoryOrder; + mOrdering = ordering; + mTitle = title; + mShowAsAction = showAsAction; + } + + /** + * Invokes the item by calling various listeners or callbacks. + * + * @return true if the invocation was handled, false otherwise + */ + public boolean invoke() { + if (mClickListener != null && + mClickListener.onMenuItemClick(this)) { + return true; + } + + if (mMenu.dispatchMenuItemSelected(mMenu.getRootMenu(), this)) { + return true; + } + + if (mItemCallback != null) { + mItemCallback.run(); + return true; + } + + if (mIntent != null) { + try { + mMenu.getContext().startActivity(mIntent); + return true; + } catch (ActivityNotFoundException e) { + Log.e(TAG, "Can't find activity to handle intent; ignoring", e); + } + } + + if (mActionProvider != null && mActionProvider.onPerformDefaultAction()) { + return true; + } + + return false; + } + + public boolean isEnabled() { + return (mFlags & ENABLED) != 0; + } + + public MenuItem setEnabled(boolean enabled) { + if (enabled) { + mFlags |= ENABLED; + } else { + mFlags &= ~ENABLED; + } + + mMenu.onItemsChanged(false); + + return this; + } + + public int getGroupId() { + return mGroup; + } + + @ViewDebug.CapturedViewProperty + public int getItemId() { + return mId; + } + + public int getOrder() { + return mCategoryOrder; + } + + public int getOrdering() { + return mOrdering; + } + + public Intent getIntent() { + return mIntent; + } + + public MenuItem setIntent(Intent intent) { + mIntent = intent; + return this; + } + + Runnable getCallback() { + return mItemCallback; + } + + public MenuItem setCallback(Runnable callback) { + mItemCallback = callback; + return this; + } + + public char getAlphabeticShortcut() { + return mShortcutAlphabeticChar; + } + + public MenuItem setAlphabeticShortcut(char alphaChar) { + if (mShortcutAlphabeticChar == alphaChar) return this; + + mShortcutAlphabeticChar = Character.toLowerCase(alphaChar); + + mMenu.onItemsChanged(false); + + return this; + } + + public char getNumericShortcut() { + return mShortcutNumericChar; + } + + public MenuItem setNumericShortcut(char numericChar) { + if (mShortcutNumericChar == numericChar) return this; + + mShortcutNumericChar = numericChar; + + mMenu.onItemsChanged(false); + + return this; + } + + public MenuItem setShortcut(char numericChar, char alphaChar) { + mShortcutNumericChar = numericChar; + mShortcutAlphabeticChar = Character.toLowerCase(alphaChar); + + mMenu.onItemsChanged(false); + + return this; + } + + /** + * @return The active shortcut (based on QWERTY-mode of the menu). + */ + char getShortcut() { + return (mMenu.isQwertyMode() ? mShortcutAlphabeticChar : mShortcutNumericChar); + } + + /** + * @return The label to show for the shortcut. This includes the chording + * key (for example 'Menu+a'). Also, any non-human readable + * characters should be human readable (for example 'Menu+enter'). + */ + String getShortcutLabel() { + + char shortcut = getShortcut(); + if (shortcut == 0) { + return ""; + } + + StringBuilder sb = new StringBuilder(sPrependShortcutLabel); + switch (shortcut) { + + case '\n': + sb.append(sEnterShortcutLabel); + break; + + case '\b': + sb.append(sDeleteShortcutLabel); + break; + + case ' ': + sb.append(sSpaceShortcutLabel); + break; + + default: + sb.append(shortcut); + break; + } + + return sb.toString(); + } + + /** + * @return Whether this menu item should be showing shortcuts (depends on + * whether the menu should show shortcuts and whether this item has + * a shortcut defined) + */ + boolean shouldShowShortcut() { + // Show shortcuts if the menu is supposed to show shortcuts AND this item has a shortcut + return mMenu.isShortcutsVisible() && (getShortcut() != 0); + } + + public SubMenu getSubMenu() { + return mSubMenu; + } + + public boolean hasSubMenu() { + return mSubMenu != null; + } + + void setSubMenu(SubMenuBuilder subMenu) { + mSubMenu = subMenu; + + subMenu.setHeaderTitle(getTitle()); + } + + @ViewDebug.CapturedViewProperty + public CharSequence getTitle() { + return mTitle; + } + + /** + * Gets the title for a particular {@link ItemView} + * + * @param itemView The ItemView that is receiving the title + * @return Either the title or condensed title based on what the ItemView + * prefers + */ + CharSequence getTitleForItemView(MenuView.ItemView itemView) { + return ((itemView != null) && itemView.prefersCondensedTitle()) + ? getTitleCondensed() + : getTitle(); + } + + public MenuItem setTitle(CharSequence title) { + mTitle = title; + + mMenu.onItemsChanged(false); + + if (mSubMenu != null) { + mSubMenu.setHeaderTitle(title); + } + + return this; + } + + public MenuItem setTitle(int title) { + return setTitle(mMenu.getContext().getString(title)); + } + + public CharSequence getTitleCondensed() { + return mTitleCondensed != null ? mTitleCondensed : mTitle; + } + + public MenuItem setTitleCondensed(CharSequence title) { + mTitleCondensed = title; + + // Could use getTitle() in the loop below, but just cache what it would do here + if (title == null) { + title = mTitle; + } + + mMenu.onItemsChanged(false); + + return this; + } + + public Drawable getIcon() { + if (mIconDrawable != null) { + return mIconDrawable; + } + + if (mIconResId != NO_ICON) { + return mMenu.getResources().getDrawable(mIconResId); + } + + return null; + } + + public MenuItem setIcon(Drawable icon) { + mIconResId = NO_ICON; + mIconDrawable = icon; + mMenu.onItemsChanged(false); + + return this; + } + + public MenuItem setIcon(int iconResId) { + mIconDrawable = null; + mIconResId = iconResId; + + // If we have a view, we need to push the Drawable to them + mMenu.onItemsChanged(false); + + return this; + } + + public boolean isCheckable() { + return (mFlags & CHECKABLE) == CHECKABLE; + } + + public MenuItem setCheckable(boolean checkable) { + final int oldFlags = mFlags; + mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0); + if (oldFlags != mFlags) { + mMenu.onItemsChanged(false); + } + + return this; + } + + public void setExclusiveCheckable(boolean exclusive) { + mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0); + } + + public boolean isExclusiveCheckable() { + return (mFlags & EXCLUSIVE) != 0; + } + + public boolean isChecked() { + return (mFlags & CHECKED) == CHECKED; + } + + public MenuItem setChecked(boolean checked) { + if ((mFlags & EXCLUSIVE) != 0) { + // Call the method on the Menu since it knows about the others in this + // exclusive checkable group + mMenu.setExclusiveItemChecked(this); + } else { + setCheckedInt(checked); + } + + return this; + } + + void setCheckedInt(boolean checked) { + final int oldFlags = mFlags; + mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0); + if (oldFlags != mFlags) { + mMenu.onItemsChanged(false); + } + } + + public boolean isVisible() { + return (mFlags & HIDDEN) == 0; + } + + /** + * Changes the visibility of the item. This method DOES NOT notify the + * parent menu of a change in this item, so this should only be called from + * methods that will eventually trigger this change. If unsure, use {@link #setVisible(boolean)} + * instead. + * + * @param shown Whether to show (true) or hide (false). + * @return Whether the item's shown state was changed + */ + boolean setVisibleInt(boolean shown) { + final int oldFlags = mFlags; + mFlags = (mFlags & ~HIDDEN) | (shown ? 0 : HIDDEN); + return oldFlags != mFlags; + } + + public MenuItem setVisible(boolean shown) { + // Try to set the shown state to the given state. If the shown state was changed + // (i.e. the previous state isn't the same as given state), notify the parent menu that + // the shown state has changed for this item + if (setVisibleInt(shown)) mMenu.onItemVisibleChanged(this); + + return this; + } + + public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener clickListener) { + mClickListener = clickListener; + return this; + } + + @Override + public String toString() { + return mTitle.toString(); + } + + void setMenuInfo(ContextMenuInfo menuInfo) { + mMenuInfo = menuInfo; + } + + public ContextMenuInfo getMenuInfo() { + return mMenuInfo; + } + + public void actionFormatChanged() { + mMenu.onItemActionRequestChanged(this); + } + + /** + * @return Whether the menu should show icons for menu items. + */ + public boolean shouldShowIcon() { + return mMenu.getOptionalIconsVisible(); + } + + public boolean isActionButton() { + return (mFlags & IS_ACTION) == IS_ACTION; + } + + public boolean requestsActionButton() { + return (mShowAsAction & SHOW_AS_ACTION_IF_ROOM) == SHOW_AS_ACTION_IF_ROOM; + } + + public boolean requiresActionButton() { + return (mShowAsAction & SHOW_AS_ACTION_ALWAYS) == SHOW_AS_ACTION_ALWAYS; + } + + public void setIsActionButton(boolean isActionButton) { + if (isActionButton) { + mFlags |= IS_ACTION; + } else { + mFlags &= ~IS_ACTION; + } + } + + public boolean showsTextAsAction() { + return (mShowAsAction & SHOW_AS_ACTION_WITH_TEXT) == SHOW_AS_ACTION_WITH_TEXT; + } + + public void setShowAsAction(int actionEnum) { + switch (actionEnum & SHOW_AS_ACTION_MASK) { + case SHOW_AS_ACTION_ALWAYS: + case SHOW_AS_ACTION_IF_ROOM: + case SHOW_AS_ACTION_NEVER: + // Looks good! + break; + + default: + // Mutually exclusive options selected! + throw new IllegalArgumentException("SHOW_AS_ACTION_ALWAYS, SHOW_AS_ACTION_IF_ROOM," + + " and SHOW_AS_ACTION_NEVER are mutually exclusive."); + } + mShowAsAction = actionEnum; + mMenu.onItemActionRequestChanged(this); + } + + public MenuItem setActionView(View view) { + mActionView = view; + mActionProvider = null; + if (view != null && view.getId() == View.NO_ID && mId > 0) { + view.setId(mId); + } + mMenu.onItemActionRequestChanged(this); + return this; + } + + public MenuItem setActionView(int resId) { + final Context context = mMenu.getContext(); + final LayoutInflater inflater = LayoutInflater.from(context); + setActionView(inflater.inflate(resId, new LinearLayout(context), false)); + return this; + } + + public View getActionView() { + if (mActionView != null) { + return mActionView; + } else if (mActionProvider != null) { + mActionView = mActionProvider.onCreateActionView(); + return mActionView; + } else { + return null; + } + } + + public ActionProvider getActionProvider() { + return mActionProvider; + } + + public MenuItem setActionProvider(ActionProvider actionProvider) { + mActionView = null; + mActionProvider = actionProvider; + mMenu.onItemsChanged(true); // Measurement can be changed + return this; + } + + @Override + public MenuItem setShowAsActionFlags(int actionEnum) { + setShowAsAction(actionEnum); + return this; + } + + @Override + public boolean expandActionView() { + if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) == 0 || mActionView == null) { + return false; + } + + if (mOnActionExpandListener == null || + mOnActionExpandListener.onMenuItemActionExpand(this)) { + return mMenu.expandItemActionView(this); + } + + return false; + } + + @Override + public boolean collapseActionView() { + if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) == 0) { + return false; + } + if (mActionView == null) { + // We're already collapsed if we have no action view. + return true; + } + + if (mOnActionExpandListener == null || + mOnActionExpandListener.onMenuItemActionCollapse(this)) { + return mMenu.collapseItemActionView(this); + } + + return false; + } + + @Override + public MenuItem setOnActionExpandListener(OnActionExpandListener listener) { + mOnActionExpandListener = listener; + return this; + } + + public boolean hasCollapsibleActionView() { + return (mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) != 0 && mActionView != null; + } + + public void setActionViewExpanded(boolean isExpanded) { + mIsActionViewExpanded = isExpanded; + mMenu.onItemsChanged(false); + } + + public boolean isActionViewExpanded() { + return mIsActionViewExpanded; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java index 2ed1e548..aaf2997b 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java @@ -1,315 +1,310 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * Copyright (C) 2011 Jake Wharton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package com.actionbarsherlock.internal.view.menu; import android.content.Intent; import android.graphics.drawable.Drawable; -import android.support.v4.view.MenuItem; -import android.support.v4.view.SubMenu; -import android.view.View; import android.view.ContextMenu.ContextMenuInfo; - -/** - *

Interface for direct access to a previously created menu item.

- * - *

An Item is returned by calling one of the {@link Menu#add(int)} - * methods.

- * - *

For a feature set of specific menu types, see {@link Menu}.

- */ -public final class MenuItemWrapper implements MenuItem { - private static final class HoneycombMenuItem { - static View getActionView(android.view.MenuItem item) { - return item.getActionView(); - } - - static void setActionView(android.view.MenuItem item, int resId) { - item.setActionView(resId); - } - - static void setActionView(android.view.MenuItem item, View view) { - item.setActionView(view); - } - - static void setShowAsAction(android.view.MenuItem item, int actionEnum) { - item.setShowAsAction(actionEnum); +import android.view.View; +import com.actionbarsherlock.internal.view.ActionProviderWrapper; +import com.actionbarsherlock.internal.widget.CollapsibleActionViewWrapper; +import com.actionbarsherlock.view.ActionProvider; +import com.actionbarsherlock.view.CollapsibleActionView; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; + +public class MenuItemWrapper implements MenuItem, android.view.MenuItem.OnMenuItemClickListener { + private final android.view.MenuItem mNativeItem; + private SubMenu mSubMenu = null; + private OnMenuItemClickListener mMenuItemClickListener = null; + private OnActionExpandListener mActionExpandListener = null; + private android.view.MenuItem.OnActionExpandListener mNativeActionExpandListener = null; + + + public MenuItemWrapper(android.view.MenuItem nativeItem) { + if (nativeItem == null) { + throw new IllegalStateException("Wrapped menu item cannot be null."); } + mNativeItem = nativeItem; } - /** Native {@link android.view.MenuItem} whose methods are wrapped. */ - private final android.view.MenuItem mMenuItem; - /** - * Constructor used to create a wrapper to a native - * {@link android.view.MenuItem} so we can return the same type for native - * and {@link MenuItemImpl} instances, the latter of which will override - * all the methods defined in this base class. - * - * @param menuItem Native instance. - */ - public MenuItemWrapper(android.view.MenuItem menuItem) { - mMenuItem = menuItem; + @Override + public int getItemId() { + return mNativeItem.getItemId(); } + @Override + public int getGroupId() { + return mNativeItem.getGroupId(); + } - /** - * Returns the currently set action view for this menu item. - * - * @return The item's action view - * @see #setActionView(int) - * @see #setActionView(View) - * @see #setShowAsAction(int) - */ - public View getActionView() { - if (mMenuItem != null) { - return HoneycombMenuItem.getActionView(mMenuItem); - } - return null; + @Override + public int getOrder() { + return mNativeItem.getOrder(); } - /** - * Set an action view for this menu item. An action view will be displayed - * in place of an automatically generated menu item element in the UI when - * this item is shown as an action within a parent. - * - * @param resId Layout resource to use for presenting this item to the user. - * @return This Item so additional setters can be called. - * @see #setActionView(View) - */ - public MenuItem setActionView(int resId) { - if (mMenuItem != null) { - HoneycombMenuItem.setActionView(mMenuItem, resId); - } + @Override + public MenuItem setTitle(CharSequence title) { + mNativeItem.setTitle(title); return this; } - /** - * Set an action view for this menu item. An action view will be displayed - * in place of an automatically generated menu item element in the UI when - * this item is shown as an action within a parent. - * - * @param view View to use for presenting this item to the user. - * @return This Item so additional setters can be called. - * @see #setActionView(int) - */ - public MenuItem setActionView(View view) { - if (mMenuItem != null) { - HoneycombMenuItem.setActionView(mMenuItem, view); - } + @Override + public MenuItem setTitle(int title) { + mNativeItem.setTitle(title); return this; } - /** - * Sets how this item should display in the presence of an Action Bar. The - * parameter actionEnum is a flag set. One of - * {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or - * {@link #SHOW_AS_ACTION_NEVER} should be used, and you may optionally OR - * the value with {@link #SHOW_AS_ACTION_WITH_TEXT}. - * {@link #SHOW_AS_ACTION_WITH_TEXT} requests that when the item is shown as - * an action, it should be shown with a text label. - * - * @param actionEnum How the item should display. One of - * {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or - * {@link #SHOW_AS_ACTION_NEVER}. {@link #SHOW_AS_ACTION_NEVER} is the - * default. - */ - public void setShowAsAction(int actionEnum) { - if (mMenuItem != null) { - HoneycombMenuItem.setShowAsAction(mMenuItem, actionEnum); - } + @Override + public CharSequence getTitle() { + return mNativeItem.getTitle(); } - // --------------------------------------------------------------------- - // MENU ITEM SUPPORT - // --------------------------------------------------------------------- + @Override + public MenuItem setTitleCondensed(CharSequence title) { + mNativeItem.setTitleCondensed(title); + return this; + } @Override - public char getAlphabeticShortcut() { - return mMenuItem.getAlphabeticShortcut(); + public CharSequence getTitleCondensed() { + return mNativeItem.getTitleCondensed(); } @Override - public int getGroupId() { - return mMenuItem.getGroupId(); + public MenuItem setIcon(Drawable icon) { + mNativeItem.setIcon(icon); + return this; } @Override - public Drawable getIcon() { - return mMenuItem.getIcon(); + public MenuItem setIcon(int iconRes) { + mNativeItem.setIcon(iconRes); + return this; } @Override - public Intent getIntent() { - return mMenuItem.getIntent(); + public Drawable getIcon() { + return mNativeItem.getIcon(); } @Override - public int getItemId() { - return mMenuItem.getItemId(); + public MenuItem setIntent(Intent intent) { + mNativeItem.setIntent(intent); + return this; } @Override - public ContextMenuInfo getMenuInfo() { - return mMenuItem.getMenuInfo(); + public Intent getIntent() { + return mNativeItem.getIntent(); } @Override - public char getNumericShortcut() { - return mMenuItem.getNumericShortcut(); + public MenuItem setShortcut(char numericChar, char alphaChar) { + mNativeItem.setShortcut(numericChar, alphaChar); + return this; } @Override - public int getOrder() { - return mMenuItem.getOrder(); + public MenuItem setNumericShortcut(char numericChar) { + mNativeItem.setNumericShortcut(numericChar); + return this; } @Override - public SubMenu getSubMenu() { - return new SubMenuWrapper(mMenuItem.getSubMenu()); + public char getNumericShortcut() { + return mNativeItem.getNumericShortcut(); } @Override - public CharSequence getTitle() { - return mMenuItem.getTitle(); + public MenuItem setAlphabeticShortcut(char alphaChar) { + mNativeItem.setAlphabeticShortcut(alphaChar); + return this; } @Override - public CharSequence getTitleCondensed() { - return mMenuItem.getTitleCondensed(); + public char getAlphabeticShortcut() { + return mNativeItem.getAlphabeticShortcut(); } @Override - public boolean hasSubMenu() { - return mMenuItem.hasSubMenu(); + public MenuItem setCheckable(boolean checkable) { + mNativeItem.setCheckable(checkable); + return this; } @Override public boolean isCheckable() { - return mMenuItem.isCheckable(); + return mNativeItem.isCheckable(); + } + + @Override + public MenuItem setChecked(boolean checked) { + mNativeItem.setChecked(checked); + return this; } @Override public boolean isChecked() { - return mMenuItem.isChecked(); + return mNativeItem.isChecked(); } @Override - public boolean isEnabled() { - return mMenuItem.isEnabled(); + public MenuItem setVisible(boolean visible) { + mNativeItem.setVisible(visible); + return this; } @Override public boolean isVisible() { - return mMenuItem.isVisible(); + return mNativeItem.isVisible(); } @Override - public MenuItem setAlphabeticShortcut(char alphaChar) { - mMenuItem.setAlphabeticShortcut(alphaChar); + public MenuItem setEnabled(boolean enabled) { + mNativeItem.setEnabled(enabled); return this; } @Override - public MenuItem setCheckable(boolean checkable) { - mMenuItem.setCheckable(checkable); - return this; + public boolean isEnabled() { + return mNativeItem.isEnabled(); } @Override - public MenuItem setChecked(boolean checked) { - mMenuItem.setChecked(checked); - return this; + public boolean hasSubMenu() { + return mNativeItem.hasSubMenu(); } @Override - public MenuItem setEnabled(boolean enabled) { - mMenuItem.setEnabled(enabled); - return this; + public SubMenu getSubMenu() { + if (hasSubMenu() && (mSubMenu == null)) { + mSubMenu = new SubMenuWrapper(mNativeItem.getSubMenu()); + } + return mSubMenu; } @Override - public MenuItem setIcon(Drawable icon) { - mMenuItem.setIcon(icon); + public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) { + mMenuItemClickListener = menuItemClickListener; + //Register ourselves as the listener to proxy + mNativeItem.setOnMenuItemClickListener(this); return this; } @Override - public MenuItem setIcon(int iconRes) { - mMenuItem.setIcon(iconRes); - return this; + public boolean onMenuItemClick(android.view.MenuItem item) { + if (mMenuItemClickListener != null) { + return mMenuItemClickListener.onMenuItemClick(this); + } + return false; } @Override - public MenuItem setIntent(Intent intent) { - mMenuItem.setIntent(intent); - return this; + public ContextMenuInfo getMenuInfo() { + return mNativeItem.getMenuInfo(); } @Override - public MenuItem setNumericShortcut(char numericChar) { - mMenuItem.setNumericShortcut(numericChar); - return this; + public void setShowAsAction(int actionEnum) { + mNativeItem.setShowAsAction(actionEnum); } @Override - public MenuItem setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener menuItemClickListener) { - mMenuItem.setOnMenuItemClickListener(menuItemClickListener); + public MenuItem setShowAsActionFlags(int actionEnum) { + mNativeItem.setShowAsActionFlags(actionEnum); return this; } - /** - * Set a custom listener for invocation of this menu item. - * - * @param menuItemClickListener The object to receive invokations. - * @return This Item so additional setters can be called. - */ - public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) { - mMenuItem.setOnMenuItemClickListener(menuItemClickListener); + @Override + public MenuItem setActionView(View view) { + if (view != null && view instanceof CollapsibleActionView) { + view = new CollapsibleActionViewWrapper(view); + } + mNativeItem.setActionView(view); return this; } @Override - public MenuItem setShortcut(char numericChar, char alphaChar) { - mMenuItem.setShortcut(numericChar, alphaChar); + public MenuItem setActionView(int resId) { + //Allow the native menu to inflate the resource + mNativeItem.setActionView(resId); + if (resId != 0) { + //Get newly created view + View view = mNativeItem.getActionView(); + if (view instanceof CollapsibleActionView) { + //Wrap it and re-set it + mNativeItem.setActionView(new CollapsibleActionViewWrapper(view)); + } + } return this; } @Override - public MenuItem setTitle(CharSequence title) { - mMenuItem.setTitle(title); - return this; + public View getActionView() { + View actionView = mNativeItem.getActionView(); + if (actionView instanceof CollapsibleActionViewWrapper) { + return ((CollapsibleActionViewWrapper)actionView).unwrap(); + } + return actionView; } @Override - public MenuItem setTitle(int title) { - mMenuItem.setTitle(title); + public MenuItem setActionProvider(ActionProvider actionProvider) { + mNativeItem.setActionProvider(new ActionProviderWrapper(actionProvider)); return this; } @Override - public MenuItem setTitleCondensed(CharSequence title) { - mMenuItem.setTitleCondensed(title); - return this; + public ActionProvider getActionProvider() { + android.view.ActionProvider nativeProvider = mNativeItem.getActionProvider(); + if (nativeProvider != null && nativeProvider instanceof ActionProviderWrapper) { + return ((ActionProviderWrapper)nativeProvider).unwrap(); + } + return null; } @Override - public MenuItem setVisible(boolean visible) { - mMenuItem.setVisible(visible); + public boolean expandActionView() { + return mNativeItem.expandActionView(); + } + + @Override + public boolean collapseActionView() { + return mNativeItem.collapseActionView(); + } + + @Override + public boolean isActionViewExpanded() { + return mNativeItem.isActionViewExpanded(); + } + + @Override + public MenuItem setOnActionExpandListener(OnActionExpandListener listener) { + mActionExpandListener = listener; + + if (mNativeActionExpandListener == null) { + mNativeActionExpandListener = new android.view.MenuItem.OnActionExpandListener() { + @Override + public boolean onMenuItemActionExpand(android.view.MenuItem menuItem) { + if (mActionExpandListener != null) { + return mActionExpandListener.onMenuItemActionExpand(MenuItemWrapper.this); + } + return false; + } + + @Override + public boolean onMenuItemActionCollapse(android.view.MenuItem menuItem) { + if (mActionExpandListener != null) { + return mActionExpandListener.onMenuItemActionCollapse(MenuItemWrapper.this); + } + return false; + } + }; + + //Register our inner-class as the listener to proxy method calls + mNativeItem.setOnActionExpandListener(mNativeActionExpandListener); + } + return this; } } diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuPopupHelper.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuPopupHelper.java new file mode 100644 index 00000000..f030de31 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuPopupHelper.java @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.view.menu; + +import java.util.ArrayList; +import android.content.Context; +import android.content.res.Resources; +import android.database.DataSetObserver; +import android.os.Parcelable; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.MeasureSpec; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.FrameLayout; +import android.widget.ListAdapter; +import android.widget.PopupWindow; +import com.actionbarsherlock.R; +import com.actionbarsherlock.internal.view.View_HasStateListenerSupport; +import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener; +import com.actionbarsherlock.internal.widget.IcsListPopupWindow; +import com.actionbarsherlock.view.MenuItem; + +/** + * Presents a menu as a small, simple popup anchored to another view. + * @hide + */ +public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener, + ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener, + View_OnAttachStateChangeListener, MenuPresenter { + //UNUSED private static final String TAG = "MenuPopupHelper"; + + static final int ITEM_LAYOUT = R.layout.abs__popup_menu_item_layout; + + private Context mContext; + private LayoutInflater mInflater; + private IcsListPopupWindow mPopup; + private MenuBuilder mMenu; + private int mPopupMaxWidth; + private View mAnchorView; + private boolean mOverflowOnly; + private ViewTreeObserver mTreeObserver; + + private MenuAdapter mAdapter; + + private Callback mPresenterCallback; + + boolean mForceShowIcon; + + private ViewGroup mMeasureParent; + + public MenuPopupHelper(Context context, MenuBuilder menu) { + this(context, menu, null, false); + } + + public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) { + this(context, menu, anchorView, false); + } + + public MenuPopupHelper(Context context, MenuBuilder menu, + View anchorView, boolean overflowOnly) { + mContext = context; + mInflater = LayoutInflater.from(context); + mMenu = menu; + mOverflowOnly = overflowOnly; + + final Resources res = context.getResources(); + mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2, + res.getDimensionPixelSize(R.dimen.abs__config_prefDialogWidth)); + + mAnchorView = anchorView; + + menu.addMenuPresenter(this); + } + + public void setAnchorView(View anchor) { + mAnchorView = anchor; + } + + public void setForceShowIcon(boolean forceShow) { + mForceShowIcon = forceShow; + } + + public void show() { + if (!tryShow()) { + throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor"); + } + } + + public boolean tryShow() { + mPopup = new IcsListPopupWindow(mContext, null, R.attr.popupMenuStyle); + mPopup.setOnDismissListener(this); + mPopup.setOnItemClickListener(this); + + mAdapter = new MenuAdapter(mMenu); + mPopup.setAdapter(mAdapter); + mPopup.setModal(true); + + View anchor = mAnchorView; + if (anchor != null) { + final boolean addGlobalListener = mTreeObserver == null; + mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest + if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this); + ((View_HasStateListenerSupport)anchor).addOnAttachStateChangeListener(this); + mPopup.setAnchorView(anchor); + } else { + return false; + } + + mPopup.setContentWidth(Math.min(measureContentWidth(mAdapter), mPopupMaxWidth)); + mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); + mPopup.show(); + mPopup.getListView().setOnKeyListener(this); + return true; + } + + public void dismiss() { + if (isShowing()) { + mPopup.dismiss(); + } + } + + public void onDismiss() { + mPopup = null; + mMenu.close(); + if (mTreeObserver != null) { + if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver(); + mTreeObserver.removeGlobalOnLayoutListener(this); + mTreeObserver = null; + } + ((View_HasStateListenerSupport)mAnchorView).removeOnAttachStateChangeListener(this); + } + + public boolean isShowing() { + return mPopup != null && mPopup.isShowing(); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + MenuAdapter adapter = mAdapter; + adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0); + } + + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) { + dismiss(); + return true; + } + return false; + } + + private int measureContentWidth(ListAdapter adapter) { + // Menus don't tend to be long, so this is more sane than it looks. + int width = 0; + View itemView = null; + int itemType = 0; + final int widthMeasureSpec = + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + final int heightMeasureSpec = + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + final int count = adapter.getCount(); + for (int i = 0; i < count; i++) { + final int positionType = adapter.getItemViewType(i); + if (positionType != itemType) { + itemType = positionType; + itemView = null; + } + if (mMeasureParent == null) { + mMeasureParent = new FrameLayout(mContext); + } + itemView = adapter.getView(i, itemView, mMeasureParent); + itemView.measure(widthMeasureSpec, heightMeasureSpec); + width = Math.max(width, itemView.getMeasuredWidth()); + } + return width; + } + + @Override + public void onGlobalLayout() { + if (isShowing()) { + final View anchor = mAnchorView; + if (anchor == null || !anchor.isShown()) { + dismiss(); + } else if (isShowing()) { + // Recompute window size and position + mPopup.show(); + } + } + } + + @Override + public void onViewAttachedToWindow(View v) { + } + + @Override + public void onViewDetachedFromWindow(View v) { + if (mTreeObserver != null) { + if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver(); + mTreeObserver.removeGlobalOnLayoutListener(this); + } + ((View_HasStateListenerSupport)v).removeOnAttachStateChangeListener(this); + } + + @Override + public void initForMenu(Context context, MenuBuilder menu) { + // Don't need to do anything; we added as a presenter in the constructor. + } + + @Override + public MenuView getMenuView(ViewGroup root) { + throw new UnsupportedOperationException("MenuPopupHelpers manage their own views"); + } + + @Override + public void updateMenuView(boolean cleared) { + if (mAdapter != null) mAdapter.notifyDataSetChanged(); + } + + @Override + public void setCallback(Callback cb) { + mPresenterCallback = cb; + } + + @Override + public boolean onSubMenuSelected(SubMenuBuilder subMenu) { + if (subMenu.hasVisibleItems()) { + MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false); + subPopup.setCallback(mPresenterCallback); + + boolean preserveIconSpacing = false; + final int count = subMenu.size(); + for (int i = 0; i < count; i++) { + MenuItem childItem = subMenu.getItem(i); + if (childItem.isVisible() && childItem.getIcon() != null) { + preserveIconSpacing = true; + break; + } + } + subPopup.setForceShowIcon(preserveIconSpacing); + + if (subPopup.tryShow()) { + if (mPresenterCallback != null) { + mPresenterCallback.onOpenSubMenu(subMenu); + } + return true; + } + } + return false; + } + + @Override + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { + // Only care about the (sub)menu we're presenting. + if (menu != mMenu) return; + + dismiss(); + if (mPresenterCallback != null) { + mPresenterCallback.onCloseMenu(menu, allMenusAreClosing); + } + } + + @Override + public boolean flagActionItems() { + return false; + } + + public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) { + return false; + } + + public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { + return false; + } + + @Override + public int getId() { + return 0; + } + + @Override + public Parcelable onSaveInstanceState() { + return null; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + } + + private class MenuAdapter extends BaseAdapter { + private MenuBuilder mAdapterMenu; + private int mExpandedIndex = -1; + + public MenuAdapter(MenuBuilder menu) { + mAdapterMenu = menu; + registerDataSetObserver(new ExpandedIndexObserver()); + findExpandedIndex(); + } + + public int getCount() { + ArrayList items = mOverflowOnly ? + mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems(); + if (mExpandedIndex < 0) { + return items.size(); + } + return items.size() - 1; + } + + public MenuItemImpl getItem(int position) { + ArrayList items = mOverflowOnly ? + mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems(); + if (mExpandedIndex >= 0 && position >= mExpandedIndex) { + position++; + } + return items.get(position); + } + + public long getItemId(int position) { + // Since a menu item's ID is optional, we'll use the position as an + // ID for the item in the AdapterView + return position; + } + + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = mInflater.inflate(ITEM_LAYOUT, parent, false); + } + + MenuView.ItemView itemView = (MenuView.ItemView) convertView; + if (mForceShowIcon) { + ((ListMenuItemView) convertView).setForceShowIcon(true); + } + itemView.initialize(getItem(position), 0); + return convertView; + } + + void findExpandedIndex() { + final MenuItemImpl expandedItem = mMenu.getExpandedItem(); + if (expandedItem != null) { + final ArrayList items = mMenu.getNonActionItems(); + final int count = items.size(); + for (int i = 0; i < count; i++) { + final MenuItemImpl item = items.get(i); + if (item == expandedItem) { + mExpandedIndex = i; + return; + } + } + } + mExpandedIndex = -1; + } + } + + private class ExpandedIndexObserver extends DataSetObserver { + @Override + public void onChanged() { + mAdapter.findExpandedIndex(); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuPresenter.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuPresenter.java new file mode 100644 index 00000000..c3f35472 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuPresenter.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.view.menu; + +import android.content.Context; +import android.os.Parcelable; +import android.view.ViewGroup; + +/** + * A MenuPresenter is responsible for building views for a Menu object. + * It takes over some responsibility from the old style monolithic MenuBuilder class. + */ +public interface MenuPresenter { + /** + * Called by menu implementation to notify another component of open/close events. + */ + public interface Callback { + /** + * Called when a menu is closing. + * @param menu + * @param allMenusAreClosing + */ + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing); + + /** + * Called when a submenu opens. Useful for notifying the application + * of menu state so that it does not attempt to hide the action bar + * while a submenu is open or similar. + * + * @param subMenu Submenu currently being opened + * @return true if the Callback will handle presenting the submenu, false if + * the presenter should attempt to do so. + */ + public boolean onOpenSubMenu(MenuBuilder subMenu); + } + + /** + * Initialize this presenter for the given context and menu. + * This method is called by MenuBuilder when a presenter is + * added. See {@link MenuBuilder#addMenuPresenter(MenuPresenter)} + * + * @param context Context for this presenter; used for view creation and resource management + * @param menu Menu to host + */ + public void initForMenu(Context context, MenuBuilder menu); + + /** + * Retrieve a MenuView to display the menu specified in + * {@link #initForMenu(Context, Menu)}. + * + * @param root Intended parent of the MenuView. + * @return A freshly created MenuView. + */ + public MenuView getMenuView(ViewGroup root); + + /** + * Update the menu UI in response to a change. Called by + * MenuBuilder during the normal course of operation. + * + * @param cleared true if the menu was entirely cleared + */ + public void updateMenuView(boolean cleared); + + /** + * Set a callback object that will be notified of menu events + * related to this specific presentation. + * @param cb Callback that will be notified of future events + */ + public void setCallback(Callback cb); + + /** + * Called by Menu implementations to indicate that a submenu item + * has been selected. An active Callback should be notified, and + * if applicable the presenter should present the submenu. + * + * @param subMenu SubMenu being opened + * @return true if the the event was handled, false otherwise. + */ + public boolean onSubMenuSelected(SubMenuBuilder subMenu); + + /** + * Called by Menu implementations to indicate that a menu or submenu is + * closing. Presenter implementations should close the representation + * of the menu indicated as necessary and notify a registered callback. + * + * @param menu Menu or submenu that is closing. + * @param allMenusAreClosing True if all associated menus are closing. + */ + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing); + + /** + * Called by Menu implementations to flag items that will be shown as actions. + * @return true if this presenter changed the action status of any items. + */ + public boolean flagActionItems(); + + /** + * Called when a menu item with a collapsable action view should expand its action view. + * + * @param menu Menu containing the item to be expanded + * @param item Item to be expanded + * @return true if this presenter expanded the action view, false otherwise. + */ + public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item); + + /** + * Called when a menu item with a collapsable action view should collapse its action view. + * + * @param menu Menu containing the item to be collapsed + * @param item Item to be collapsed + * @return true if this presenter collapsed the action view, false otherwise. + */ + public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item); + + /** + * Returns an ID for determining how to save/restore instance state. + * @return a valid ID value. + */ + public int getId(); + + /** + * Returns a Parcelable describing the current state of the presenter. + * It will be passed to the {@link #onRestoreInstanceState(Parcelable)} + * method of the presenter sharing the same ID later. + * @return The saved instance state + */ + public Parcelable onSaveInstanceState(); + + /** + * Supplies the previously saved instance state to be restored. + * @param state The previously saved instance state + */ + public void onRestoreInstanceState(Parcelable state); +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuView.java index daae3fe8..323ba2d8 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuView.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuView.java @@ -17,10 +17,9 @@ package com.actionbarsherlock.internal.view.menu; import android.graphics.drawable.Drawable; -import android.view.View; /** - * Minimal interface for a menu view. {@link #initialize(MenuBuilder, int)} must be called for the + * Minimal interface for a menu view. {@link #initialize(MenuBuilder)} must be called for the * menu to be functional. * * @hide @@ -31,18 +30,8 @@ public interface MenuView { * view is inflated. * * @param menu The menu that this MenuView should display. - * @param menuType The type of this menu, one of - * {@link MenuBuilder#TYPE_ICON}, {@link MenuBuilder#TYPE_EXPANDED}, - * {@link MenuBuilder#TYPE_DIALOG}). */ - public void initialize(MenuBuilder menu, int menuType); - - /** - * Forces the menu view to update its view to reflect the new state of the menu. - * - * @param cleared Whether the menu was cleared or just modified. - */ - public void updateChildren(boolean cleared); + public void initialize(MenuBuilder menu); /** * Returns the default animations to be used for this menu when entering/exiting. @@ -97,12 +86,6 @@ public interface MenuView { */ public void setChecked(boolean checked); - /** - * Sets the visibility for the item view. - * @param visible Whether the item is visible - */ - public void setVisible(boolean visible); - /** * Sets the shortcut for the item. * @param showShortcut Whether a shortcut should be shown(if false, the value of @@ -117,12 +100,6 @@ public interface MenuView { */ public void setIcon(Drawable icon); - /** - * Set the action view of this item view. - * @param actionView Action view. - */ - public void setActionView(View actionView); - /** * Whether this item view prefers displaying the condensed title rather * than the normal title. If a condensed title is not available, the @@ -140,4 +117,4 @@ public interface MenuView { */ public boolean showsIcon(); } -} \ No newline at end of file +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuWrapper.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuWrapper.java index 4e499930..3d4dd42f 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuWrapper.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/MenuWrapper.java @@ -1,156 +1,185 @@ package com.actionbarsherlock.internal.view.menu; +import java.util.WeakHashMap; import android.content.ComponentName; import android.content.Intent; -import android.support.v4.view.Menu; -import android.support.v4.view.MenuItem; -import android.support.v4.view.SubMenu; import android.view.KeyEvent; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; -/** - * Wrapper around a native Menu instance which implements our version of the - * Menu interface. - */ public class MenuWrapper implements Menu { - /** Native menu. */ - private final android.view.Menu mMenu; + private final android.view.Menu mNativeMenu; - /** - * Create a new wrapped instance. - * - * @param menu Native menu. - */ - public MenuWrapper(android.view.Menu menu) { - this.mMenu = menu; + private final WeakHashMap mNativeMap = + new WeakHashMap(); + + + public MenuWrapper(android.view.Menu nativeMenu) { + mNativeMenu = nativeMenu; } - /** - * Get the native menu instance we are wrapping. - * - * @return Native menu. - */ - android.view.Menu unwrap() { - return mMenu; + public android.view.Menu unwrap() { + return mNativeMenu; } - @Override - public MenuItem add(CharSequence title) { - return new MenuItemWrapper(mMenu.add(title)); + private MenuItem addInternal(android.view.MenuItem nativeItem) { + MenuItem item = new MenuItemWrapper(nativeItem); + mNativeMap.put(nativeItem, item); + return item; } @Override - public MenuItem add(int groupId, int itemId, int order, int titleRes) { - return new MenuItemWrapper(mMenu.add(groupId, itemId, order, titleRes)); + public MenuItem add(CharSequence title) { + return addInternal(mNativeMenu.add(title)); } @Override public MenuItem add(int titleRes) { - return new MenuItemWrapper(mMenu.add(titleRes)); + return addInternal(mNativeMenu.add(titleRes)); } @Override public MenuItem add(int groupId, int itemId, int order, CharSequence title) { - return new MenuItemWrapper(mMenu.add(groupId, itemId, order, title)); + return addInternal(mNativeMenu.add(groupId, itemId, order, title)); } @Override - public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, android.view.MenuItem[] outSpecificItems) { - return mMenu.addIntentOptions(groupId, itemId, order, caller, specifics, intent, flags, outSpecificItems); + public MenuItem add(int groupId, int itemId, int order, int titleRes) { + return addInternal(mNativeMenu.add(groupId, itemId, order, titleRes)); + } + + private SubMenu addInternal(android.view.SubMenu nativeSubMenu) { + SubMenu subMenu = new SubMenuWrapper(nativeSubMenu); + android.view.MenuItem nativeItem = nativeSubMenu.getItem(); + MenuItem item = subMenu.getItem(); + mNativeMap.put(nativeItem, item); + return subMenu; } @Override public SubMenu addSubMenu(CharSequence title) { - return new SubMenuWrapper(mMenu.addSubMenu(title)); + return addInternal(mNativeMenu.addSubMenu(title)); } @Override public SubMenu addSubMenu(int titleRes) { - return new SubMenuWrapper(mMenu.addSubMenu(titleRes)); + return addInternal(mNativeMenu.addSubMenu(titleRes)); } @Override public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) { - return new SubMenuWrapper(mMenu.addSubMenu(groupId, itemId, order, title)); + return addInternal(mNativeMenu.addSubMenu(groupId, itemId, order, title)); } @Override public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) { - return new SubMenuWrapper(mMenu.addSubMenu(groupId, itemId, order, titleRes)); + return addInternal(mNativeMenu.addSubMenu(groupId, itemId, order, titleRes)); } @Override - public void clear() { - mMenu.clear(); + public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) { + int result; + if (outSpecificItems != null) { + android.view.MenuItem[] nativeOutItems = new android.view.MenuItem[outSpecificItems.length]; + result = mNativeMenu.addIntentOptions(groupId, itemId, order, caller, specifics, intent, flags, nativeOutItems); + for (int i = 0, length = outSpecificItems.length; i < length; i++) { + outSpecificItems[i] = new MenuItemWrapper(nativeOutItems[i]); + } + } else { + result = mNativeMenu.addIntentOptions(groupId, itemId, order, caller, specifics, intent, flags, null); + } + return result; } @Override - public void close() { - mMenu.close(); + public void removeItem(int id) { + mNativeMenu.removeItem(id); } @Override - public MenuItem findItem(int id) { - android.view.MenuItem item = mMenu.findItem(id); - return (item != null) ? new MenuItemWrapper(item) : null; + public void removeGroup(int groupId) { + mNativeMenu.removeGroup(groupId); } @Override - public MenuItem getItem(int index) { - return new MenuItemWrapper(mMenu.getItem(index)); + public void clear() { + mNativeMap.clear(); + mNativeMenu.clear(); } @Override - public boolean hasVisibleItems() { - return mMenu.hasVisibleItems(); + public void setGroupCheckable(int group, boolean checkable, boolean exclusive) { + mNativeMenu.setGroupCheckable(group, checkable, exclusive); } @Override - public boolean isShortcutKey(int keyCode, KeyEvent event) { - return mMenu.isShortcutKey(keyCode, event); + public void setGroupVisible(int group, boolean visible) { + mNativeMenu.setGroupVisible(group, visible); } @Override - public boolean performIdentifierAction(int id, int flags) { - return mMenu.performIdentifierAction(id, flags); + public void setGroupEnabled(int group, boolean enabled) { + mNativeMenu.setGroupEnabled(group, enabled); } @Override - public boolean performShortcut(int keyCode, KeyEvent event, int flags) { - return mMenu.performShortcut(keyCode, event, flags); + public boolean hasVisibleItems() { + return mNativeMenu.hasVisibleItems(); } @Override - public void removeGroup(int groupId) { - mMenu.removeGroup(groupId); + public MenuItem findItem(int id) { + android.view.MenuItem nativeItem = mNativeMenu.findItem(id); + return findItem(nativeItem); + } + + public MenuItem findItem(android.view.MenuItem nativeItem) { + if (nativeItem == null) { + return null; + } + + MenuItem wrapped = mNativeMap.get(nativeItem); + if (wrapped != null) { + return wrapped; + } + + return addInternal(nativeItem); } @Override - public void removeItem(int id) { - mMenu.removeItem(id); + public int size() { + return mNativeMenu.size(); } @Override - public void setGroupCheckable(int group, boolean checkable, boolean exclusive) { - mMenu.setGroupCheckable(group, checkable, exclusive); + public MenuItem getItem(int index) { + android.view.MenuItem nativeItem = mNativeMenu.getItem(index); + return findItem(nativeItem); } @Override - public void setGroupEnabled(int group, boolean enabled) { - mMenu.setGroupEnabled(group, enabled); + public void close() { + mNativeMenu.close(); } @Override - public void setGroupVisible(int group, boolean visible) { - mMenu.setGroupVisible(group, visible); + public boolean performShortcut(int keyCode, KeyEvent event, int flags) { + return mNativeMenu.performShortcut(keyCode, event, flags); } @Override - public void setQwertyMode(boolean isQwerty) { - mMenu.setQwertyMode(isQwerty); + public boolean isShortcutKey(int keyCode, KeyEvent event) { + return mNativeMenu.isShortcutKey(keyCode, event); } @Override - public int size() { - return mMenu.size(); + public boolean performIdentifierAction(int id, int flags) { + return mNativeMenu.performIdentifierAction(id, flags); + } + + @Override + public void setQwertyMode(boolean isQwerty) { + mNativeMenu.setQwertyMode(isQwerty); } } diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/SubMenuBuilder.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/SubMenuBuilder.java index dac262d5..6679cf38 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/SubMenuBuilder.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/SubMenuBuilder.java @@ -1,119 +1,134 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * Copyright (C) 2011 Jake Wharton - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.actionbarsherlock.internal.view.menu; - -import android.content.Context; -import android.graphics.drawable.Drawable; -import android.support.v4.view.SubMenu; -import android.view.View; - -/** - * The model for a sub menu, which is an extension of the menu. Most methods - * are proxied to the parent menu. - */ -public final class SubMenuBuilder extends MenuBuilder implements SubMenu { - private MenuBuilder mParentMenu; - private MenuItemImpl mItem; - - public SubMenuBuilder(Context context, MenuBuilder parentMenu, MenuItemImpl item) { - super(context); - - mParentMenu = parentMenu; - mItem = item; - } - - @Override - public void setQwertyMode(boolean isQwerty) { - mParentMenu.setQwertyMode(isQwerty); - } - - //@Override - //public boolean isQwertyMode() { - // return mParentMenu.isQwertyMode(); - //} - - //@Override - //public void setShortcutsVisible(boolean shortcutsVisible) { - // mParentMenu.setShortcutsVisible(shortcutsVisible); - //} - - //@Override - //public boolean isShortcutsVisible() { - // return mParentMenu.isShortcutsVisible(); - //} - - MenuBuilder getParentMenu() { - return mParentMenu; - } - - @Override - public MenuItemImpl getItem() { - return mItem; - } - - //@Override - //public Callback getCallback() { - // return mParentMenu.getCallback(); - //} - - //@Override - //public void setCallback(Callback callback) { - // mParentMenu.setCallback(callback); - //} - - @Override - public MenuBuilder getRootMenu() { - return mParentMenu; - } - - public SubMenuBuilder setIcon(Drawable icon) { - mItem.setIcon(icon); - return this; - } - - public SubMenuBuilder setIcon(int iconRes) { - mItem.setIcon(iconRes); - return this; - } - - public SubMenuBuilder setHeaderIcon(Drawable icon) { - throw new RuntimeException("Method not supported."); - } - - public SubMenuBuilder setHeaderIcon(int iconRes) { - throw new RuntimeException("Method not supported."); - } - - public SubMenuBuilder setHeaderTitle(CharSequence title) { - throw new RuntimeException("Method not supported."); - } - - public SubMenuBuilder setHeaderTitle(int titleRes) { - throw new RuntimeException("Method not supported."); - } - - @Override - public SubMenuBuilder setHeaderView(View view) { - throw new RuntimeException("Method not supported."); - } - - @Override - public void clearHeader() { - throw new RuntimeException("Method not supported."); - } -} \ No newline at end of file +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.view.menu; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.view.View; + +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; + +/** + * The model for a sub menu, which is an extension of the menu. Most methods are proxied to + * the parent menu. + */ +public class SubMenuBuilder extends MenuBuilder implements SubMenu { + private MenuBuilder mParentMenu; + private MenuItemImpl mItem; + + public SubMenuBuilder(Context context, MenuBuilder parentMenu, MenuItemImpl item) { + super(context); + + mParentMenu = parentMenu; + mItem = item; + } + + @Override + public void setQwertyMode(boolean isQwerty) { + mParentMenu.setQwertyMode(isQwerty); + } + + @Override + public boolean isQwertyMode() { + return mParentMenu.isQwertyMode(); + } + + @Override + public void setShortcutsVisible(boolean shortcutsVisible) { + mParentMenu.setShortcutsVisible(shortcutsVisible); + } + + @Override + public boolean isShortcutsVisible() { + return mParentMenu.isShortcutsVisible(); + } + + public Menu getParentMenu() { + return mParentMenu; + } + + public MenuItem getItem() { + return mItem; + } + + @Override + public void setCallback(Callback callback) { + mParentMenu.setCallback(callback); + } + + @Override + public MenuBuilder getRootMenu() { + return mParentMenu; + } + + @Override + boolean dispatchMenuItemSelected(MenuBuilder menu, MenuItem item) { + return super.dispatchMenuItemSelected(menu, item) || + mParentMenu.dispatchMenuItemSelected(menu, item); + } + + public SubMenu setIcon(Drawable icon) { + mItem.setIcon(icon); + return this; + } + + public SubMenu setIcon(int iconRes) { + mItem.setIcon(iconRes); + return this; + } + + public SubMenu setHeaderIcon(Drawable icon) { + return (SubMenu) super.setHeaderIconInt(icon); + } + + public SubMenu setHeaderIcon(int iconRes) { + return (SubMenu) super.setHeaderIconInt(iconRes); + } + + public SubMenu setHeaderTitle(CharSequence title) { + return (SubMenu) super.setHeaderTitleInt(title); + } + + public SubMenu setHeaderTitle(int titleRes) { + return (SubMenu) super.setHeaderTitleInt(titleRes); + } + + public SubMenu setHeaderView(View view) { + return (SubMenu) super.setHeaderViewInt(view); + } + + @Override + public boolean expandItemActionView(MenuItemImpl item) { + return mParentMenu.expandItemActionView(item); + } + + @Override + public boolean collapseItemActionView(MenuItemImpl item) { + return mParentMenu.collapseItemActionView(item); + } + + @Override + public String getActionViewStatesKey() { + final int itemId = mItem != null ? mItem.getItemId() : 0; + if (itemId == 0) { + return null; + } + return super.getActionViewStatesKey() + ":" + itemId; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/SubMenuWrapper.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/SubMenuWrapper.java index 60e81ea7..7d307acb 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/SubMenuWrapper.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/view/menu/SubMenuWrapper.java @@ -1,82 +1,72 @@ -package com.actionbarsherlock.internal.view.menu; - -import android.graphics.drawable.Drawable; -import android.support.v4.view.MenuItem; -import android.support.v4.view.SubMenu; -import android.view.View; - -public class SubMenuWrapper extends MenuWrapper implements SubMenu { - /** Native sub-menu. */ - private final android.view.SubMenu mSubMenu; - - /** - * Create a new wrapped instance. - * - * @param subMenu Native sub-menu. - */ - public SubMenuWrapper(android.view.SubMenu subMenu) { - super(subMenu); - mSubMenu = subMenu; - } - - /** - * Get the native sub-menu instance we are wrapping. - * - * @return Native sub-menu. - */ - android.view.SubMenu unwrap() { - return mSubMenu; - } - - @Override - public void clearHeader() { - mSubMenu.clearHeader(); - } - - @Override - public MenuItem getItem() { - return new MenuItemWrapper(mSubMenu.getItem()); - } - - @Override - public SubMenu setHeaderIcon(Drawable icon) { - mSubMenu.setHeaderIcon(icon); - return this; - } - - @Override - public SubMenu setHeaderIcon(int iconRes) { - mSubMenu.setHeaderIcon(iconRes); - return this; - } - - @Override - public SubMenu setHeaderTitle(CharSequence title) { - mSubMenu.setHeaderTitle(title); - return this; - } - - @Override - public SubMenu setHeaderTitle(int titleRes) { - mSubMenu.setHeaderTitle(titleRes); - return this; - } - - @Override - public SubMenu setHeaderView(View view) { - mSubMenu.setHeaderView(view); - return this; - } - - @Override - public SubMenu setIcon(Drawable icon) { - mSubMenu.setIcon(icon); - return this; - } - - @Override - public SubMenu setIcon(int iconRes) { - mSubMenu.setIcon(iconRes); - return this; - } -} +package com.actionbarsherlock.internal.view.menu; + +import android.graphics.drawable.Drawable; +import android.view.View; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.SubMenu; + +public class SubMenuWrapper extends MenuWrapper implements SubMenu { + private final android.view.SubMenu mNativeSubMenu; + private MenuItem mItem = null; + + public SubMenuWrapper(android.view.SubMenu nativeSubMenu) { + super(nativeSubMenu); + mNativeSubMenu = nativeSubMenu; + } + + + @Override + public SubMenu setHeaderTitle(int titleRes) { + mNativeSubMenu.setHeaderTitle(titleRes); + return this; + } + + @Override + public SubMenu setHeaderTitle(CharSequence title) { + mNativeSubMenu.setHeaderTitle(title); + return this; + } + + @Override + public SubMenu setHeaderIcon(int iconRes) { + mNativeSubMenu.setHeaderIcon(iconRes); + return this; + } + + @Override + public SubMenu setHeaderIcon(Drawable icon) { + mNativeSubMenu.setHeaderIcon(icon); + return this; + } + + @Override + public SubMenu setHeaderView(View view) { + mNativeSubMenu.setHeaderView(view); + return this; + } + + @Override + public void clearHeader() { + mNativeSubMenu.clearHeader(); + } + + @Override + public SubMenu setIcon(int iconRes) { + mNativeSubMenu.setIcon(iconRes); + return this; + } + + @Override + public SubMenu setIcon(Drawable icon) { + mNativeSubMenu.setIcon(icon); + return this; + } + + @Override + public MenuItem getItem() { + if (mItem == null) { + mItem = new MenuItemWrapper(mNativeSubMenu.getItem()); + } + return mItem; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/AbsActionBarView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/AbsActionBarView.java new file mode 100644 index 00000000..3a4a4467 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/AbsActionBarView.java @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.actionbarsherlock.internal.widget; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.TypedArray; +import android.os.Build; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; + +import com.actionbarsherlock.R; +import com.actionbarsherlock.internal.nineoldandroids.animation.Animator; +import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet; +import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator; +import com.actionbarsherlock.internal.nineoldandroids.view.NineViewGroup; +import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter; +import com.actionbarsherlock.internal.view.menu.ActionMenuView; + +import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean; + +public abstract class AbsActionBarView extends NineViewGroup { + protected ActionMenuView mMenuView; + protected ActionMenuPresenter mActionMenuPresenter; + protected ActionBarContainer mSplitView; + protected boolean mSplitActionBar; + protected boolean mSplitWhenNarrow; + protected int mContentHeight; + + final Context mContext; + + protected Animator mVisibilityAnim; + protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener(); + + private static final /*Time*/Interpolator sAlphaInterpolator = new DecelerateInterpolator(); + + private static final int FADE_DURATION = 200; + + public AbsActionBarView(Context context) { + super(context); + mContext = context; + } + + public AbsActionBarView(Context context, AttributeSet attrs) { + super(context, attrs); + mContext = context; + } + + public AbsActionBarView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mContext = context; + } + + /* + * Must be public so we can dispatch pre-2.2 via ActionBarImpl. + */ + @Override + public void onConfigurationChanged(Configuration newConfig) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { + super.onConfigurationChanged(newConfig); + } else if (mMenuView != null) { + mMenuView.onConfigurationChanged(newConfig); + } + + // Action bar can change size on configuration changes. + // Reread the desired height from the theme-specified style. + TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar, + R.attr.actionBarStyle, 0); + setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0)); + a.recycle(); + if (mSplitWhenNarrow) { + setSplitActionBar(getResources_getBoolean(getContext(), + R.bool.abs__split_action_bar_is_narrow)); + } + if (mActionMenuPresenter != null) { + mActionMenuPresenter.onConfigurationChanged(newConfig); + } + } + + /** + * Sets whether the bar should be split right now, no questions asked. + * @param split true if the bar should split + */ + public void setSplitActionBar(boolean split) { + mSplitActionBar = split; + } + + /** + * Sets whether the bar should split if we enter a narrow screen configuration. + * @param splitWhenNarrow true if the bar should check to split after a config change + */ + public void setSplitWhenNarrow(boolean splitWhenNarrow) { + mSplitWhenNarrow = splitWhenNarrow; + } + + public void setContentHeight(int height) { + mContentHeight = height; + requestLayout(); + } + + public int getContentHeight() { + return mContentHeight; + } + + public void setSplitView(ActionBarContainer splitView) { + mSplitView = splitView; + } + + /** + * @return Current visibility or if animating, the visibility being animated to. + */ + public int getAnimatedVisibility() { + if (mVisibilityAnim != null) { + return mVisAnimListener.mFinalVisibility; + } + return getVisibility(); + } + + public void animateToVisibility(int visibility) { + if (mVisibilityAnim != null) { + mVisibilityAnim.cancel(); + } + if (visibility == VISIBLE) { + if (getVisibility() != VISIBLE) { + setAlpha(0); + if (mSplitView != null && mMenuView != null) { + mMenuView.setAlpha(0); + } + } + ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1); + anim.setDuration(FADE_DURATION); + anim.setInterpolator(sAlphaInterpolator); + if (mSplitView != null && mMenuView != null) { + AnimatorSet set = new AnimatorSet(); + ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1); + splitAnim.setDuration(FADE_DURATION); + set.addListener(mVisAnimListener.withFinalVisibility(visibility)); + set.play(anim).with(splitAnim); + set.start(); + } else { + anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); + anim.start(); + } + } else { + ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0); + anim.setDuration(FADE_DURATION); + anim.setInterpolator(sAlphaInterpolator); + if (mSplitView != null && mMenuView != null) { + AnimatorSet set = new AnimatorSet(); + ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0); + splitAnim.setDuration(FADE_DURATION); + set.addListener(mVisAnimListener.withFinalVisibility(visibility)); + set.play(anim).with(splitAnim); + set.start(); + } else { + anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); + anim.start(); + } + } + } + + @Override + public void setVisibility(int visibility) { + if (mVisibilityAnim != null) { + mVisibilityAnim.end(); + } + super.setVisibility(visibility); + } + + public boolean showOverflowMenu() { + if (mActionMenuPresenter != null) { + return mActionMenuPresenter.showOverflowMenu(); + } + return false; + } + + public void postShowOverflowMenu() { + post(new Runnable() { + public void run() { + showOverflowMenu(); + } + }); + } + + public boolean hideOverflowMenu() { + if (mActionMenuPresenter != null) { + return mActionMenuPresenter.hideOverflowMenu(); + } + return false; + } + + public boolean isOverflowMenuShowing() { + if (mActionMenuPresenter != null) { + return mActionMenuPresenter.isOverflowMenuShowing(); + } + return false; + } + + public boolean isOverflowReserved() { + return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved(); + } + + public void dismissPopupMenus() { + if (mActionMenuPresenter != null) { + mActionMenuPresenter.dismissPopupMenus(); + } + } + + protected int measureChildView(View child, int availableWidth, int childSpecHeight, + int spacing) { + child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), + childSpecHeight); + + availableWidth -= child.getMeasuredWidth(); + availableWidth -= spacing; + + return Math.max(0, availableWidth); + } + + protected int positionChild(View child, int x, int y, int contentHeight) { + int childWidth = child.getMeasuredWidth(); + int childHeight = child.getMeasuredHeight(); + int childTop = y + (contentHeight - childHeight) / 2; + + child.layout(x, childTop, x + childWidth, childTop + childHeight); + + return childWidth; + } + + protected int positionChildInverse(View child, int x, int y, int contentHeight) { + int childWidth = child.getMeasuredWidth(); + int childHeight = child.getMeasuredHeight(); + int childTop = y + (contentHeight - childHeight) / 2; + + child.layout(x - childWidth, childTop, x, childTop + childHeight); + + return childWidth; + } + + protected class VisibilityAnimListener implements Animator.AnimatorListener { + private boolean mCanceled = false; + int mFinalVisibility; + + public VisibilityAnimListener withFinalVisibility(int visibility) { + mFinalVisibility = visibility; + return this; + } + + @Override + public void onAnimationStart(Animator animation) { + setVisibility(VISIBLE); + mVisibilityAnim = animation; + mCanceled = false; + } + + @Override + public void onAnimationEnd(Animator animation) { + if (mCanceled) return; + + mVisibilityAnim = null; + setVisibility(mFinalVisibility); + if (mSplitView != null && mMenuView != null) { + mMenuView.setVisibility(mFinalVisibility); + } + } + + @Override + public void onAnimationCancel(Animator animation) { + mCanceled = true; + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarContainer.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarContainer.java index 6f5a5992..1d9c68b3 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarContainer.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarContainer.java @@ -1,13 +1,52 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.actionbarsherlock.internal.widget; import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; import android.util.AttributeSet; import android.view.MotionEvent; +import android.view.View; import android.view.ViewGroup; -import android.widget.FrameLayout; -public class ActionBarContainer extends FrameLayout { +import com.actionbarsherlock.R; +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout; + +/** + * This class acts as a container for the action bar view and action mode context views. + * It applies special styles as needed to help handle animated transitions between them. + * @hide + */ +public class ActionBarContainer extends NineFrameLayout { private boolean mIsTransitioning; + private View mTabContainer; + private ActionBarView mActionBarView; + + private Drawable mBackground; + private Drawable mStackedBackground; + private Drawable mSplitBackground; + private boolean mIsSplit; + private boolean mIsStacked; public ActionBarContainer(Context context) { this(context, null); @@ -15,6 +54,69 @@ public class ActionBarContainer extends FrameLayout { public ActionBarContainer(Context context, AttributeSet attrs) { super(context, attrs); + + setBackgroundDrawable(null); + + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.SherlockActionBar); + mBackground = a.getDrawable(R.styleable.SherlockActionBar_background); + mStackedBackground = a.getDrawable( + R.styleable.SherlockActionBar_backgroundStacked); + + //Fix for issue #379 + if (mStackedBackground instanceof ColorDrawable && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); + Canvas c = new Canvas(bitmap); + mStackedBackground.draw(c); + int color = bitmap.getPixel(0, 0); + bitmap.recycle(); + mStackedBackground = new IcsColorDrawable(color); + } + + if (getId() == R.id.abs__split_action_bar) { + mIsSplit = true; + mSplitBackground = a.getDrawable( + R.styleable.SherlockActionBar_backgroundSplit); + } + a.recycle(); + + setWillNotDraw(mIsSplit ? mSplitBackground == null : + mBackground == null && mStackedBackground == null); + } + + @Override + public void onFinishInflate() { + super.onFinishInflate(); + mActionBarView = (ActionBarView) findViewById(R.id.abs__action_bar); + } + + public void setPrimaryBackground(Drawable bg) { + mBackground = bg; + invalidate(); + } + + public void setStackedBackground(Drawable bg) { + mStackedBackground = bg; + invalidate(); + } + + public void setSplitBackground(Drawable bg) { + mSplitBackground = bg; + invalidate(); + } + + /** + * Set the action bar into a "transitioning" state. While transitioning + * the bar will block focus and touch from all of its descendants. This + * prevents the user from interacting with the bar while it is animating + * in or out. + * + * @param isTransitioning true if the bar is currently transitioning, false otherwise. + */ + public void setTransitioning(boolean isTransitioning) { + mIsTransitioning = isTransitioning; + setDescendantFocusability(isTransitioning ? FOCUS_BLOCK_DESCENDANTS + : FOCUS_AFTER_DESCENDANTS); } @Override @@ -23,13 +125,134 @@ public class ActionBarContainer extends FrameLayout { } @Override - public boolean onTouchEvent(MotionEvent event) { - super.onTouchEvent(event); + public boolean onTouchEvent(MotionEvent ev) { + super.onTouchEvent(ev); + + // An action bar always eats touch events. + return true; + } + + @Override + public boolean onHoverEvent(MotionEvent ev) { + super.onHoverEvent(ev); + + // An action bar always eats hover events. return true; } - public void setTransitioning(boolean transitioning) { - mIsTransitioning = transitioning; - setDescendantFocusability(transitioning ? ViewGroup.FOCUS_BLOCK_DESCENDANTS : ViewGroup.FOCUS_AFTER_DESCENDANTS); + public void setTabContainer(ScrollingTabContainerView tabView) { + if (mTabContainer != null) { + removeView(mTabContainer); + } + mTabContainer = tabView; + if (tabView != null) { + addView(tabView); + final ViewGroup.LayoutParams lp = tabView.getLayoutParams(); + lp.width = LayoutParams.MATCH_PARENT; + lp.height = LayoutParams.WRAP_CONTENT; + tabView.setAllowCollapse(false); + } + } + + public View getTabContainer() { + return mTabContainer; + } + + @Override + public void onDraw(Canvas canvas) { + if (getWidth() == 0 || getHeight() == 0) { + return; + } + + if (mIsSplit) { + if (mSplitBackground != null) mSplitBackground.draw(canvas); + } else { + if (mBackground != null) { + mBackground.draw(canvas); + } + if (mStackedBackground != null && mIsStacked) { + mStackedBackground.draw(canvas); + } + } + } + + //This causes the animation reflection to fail on pre-HC platforms + //@Override + //public android.view.ActionMode startActionModeForChild(View child, android.view.ActionMode.Callback callback) { + // // No starting an action mode for an action bar child! (Where would it go?) + // return null; + //} + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + if (mActionBarView == null) return; + + final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams(); + final int actionBarViewHeight = mActionBarView.isCollapsed() ? 0 : + mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; + + if (mTabContainer != null && mTabContainer.getVisibility() != GONE) { + final int mode = MeasureSpec.getMode(heightMeasureSpec); + if (mode == MeasureSpec.AT_MOST) { + final int maxHeight = MeasureSpec.getSize(heightMeasureSpec); + setMeasuredDimension(getMeasuredWidth(), + Math.min(actionBarViewHeight + mTabContainer.getMeasuredHeight(), + maxHeight)); + } + } + } + + @Override + public void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + + final boolean hasTabs = mTabContainer != null && mTabContainer.getVisibility() != GONE; + + if (mTabContainer != null && mTabContainer.getVisibility() != GONE) { + final int containerHeight = getMeasuredHeight(); + final int tabHeight = mTabContainer.getMeasuredHeight(); + + if ((mActionBarView.getDisplayOptions() & ActionBar.DISPLAY_SHOW_HOME) == 0) { + // Not showing home, put tabs on top. + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + + if (child == mTabContainer) continue; + + if (!mActionBarView.isCollapsed()) { + child.offsetTopAndBottom(tabHeight); + } + } + mTabContainer.layout(l, 0, r, tabHeight); + } else { + mTabContainer.layout(l, containerHeight - tabHeight, r, containerHeight); + } + } + + boolean needsInvalidate = false; + if (mIsSplit) { + if (mSplitBackground != null) { + mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + needsInvalidate = true; + } + } else { + if (mBackground != null) { + mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(), + mActionBarView.getRight(), mActionBarView.getBottom()); + needsInvalidate = true; + } + if ((mIsStacked = hasTabs && mStackedBackground != null)) { + mStackedBackground.setBounds(mTabContainer.getLeft(), mTabContainer.getTop(), + mTabContainer.getRight(), mTabContainer.getBottom()); + needsInvalidate = true; + } + } + + if (needsInvalidate) { + invalidate(); + } } } diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarContextView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarContextView.java new file mode 100644 index 00000000..9ec250f3 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarContextView.java @@ -0,0 +1,518 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.actionbarsherlock.internal.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; +import android.view.animation.DecelerateInterpolator; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.actionbarsherlock.R; +import com.actionbarsherlock.internal.nineoldandroids.animation.Animator; +import com.actionbarsherlock.internal.nineoldandroids.animation.Animator.AnimatorListener; +import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet; +import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator; +import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy; +import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout; +import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter; +import com.actionbarsherlock.internal.view.menu.ActionMenuView; +import com.actionbarsherlock.internal.view.menu.MenuBuilder; +import com.actionbarsherlock.view.ActionMode; + +/** + * @hide + */ +public class ActionBarContextView extends AbsActionBarView implements AnimatorListener { + //UNUSED private static final String TAG = "ActionBarContextView"; + + private CharSequence mTitle; + private CharSequence mSubtitle; + + private NineLinearLayout mClose; + private View mCustomView; + private LinearLayout mTitleLayout; + private TextView mTitleView; + private TextView mSubtitleView; + private int mTitleStyleRes; + private int mSubtitleStyleRes; + private Drawable mSplitBackground; + + private Animator mCurrentAnimation; + private boolean mAnimateInOnLayout; + private int mAnimationMode; + + private static final int ANIMATE_IDLE = 0; + private static final int ANIMATE_IN = 1; + private static final int ANIMATE_OUT = 2; + + public ActionBarContextView(Context context) { + this(context, null); + } + + public ActionBarContextView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.actionModeStyle); + } + + public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockActionMode, defStyle, 0); + setBackgroundDrawable(a.getDrawable( + R.styleable.SherlockActionMode_background)); + mTitleStyleRes = a.getResourceId( + R.styleable.SherlockActionMode_titleTextStyle, 0); + mSubtitleStyleRes = a.getResourceId( + R.styleable.SherlockActionMode_subtitleTextStyle, 0); + + mContentHeight = a.getLayoutDimension( + R.styleable.SherlockActionMode_height, 0); + + mSplitBackground = a.getDrawable( + R.styleable.SherlockActionMode_backgroundSplit); + + a.recycle(); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mActionMenuPresenter != null) { + mActionMenuPresenter.hideOverflowMenu(); + mActionMenuPresenter.hideSubMenus(); + } + } + + @Override + public void setSplitActionBar(boolean split) { + if (mSplitActionBar != split) { + if (mActionMenuPresenter != null) { + // Mode is already active; move everything over and adjust the menu itself. + final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.MATCH_PARENT); + if (!split) { + mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); + mMenuView.setBackgroundDrawable(null); + final ViewGroup oldParent = (ViewGroup) mMenuView.getParent(); + if (oldParent != null) oldParent.removeView(mMenuView); + addView(mMenuView, layoutParams); + } else { + // Allow full screen width in split mode. + mActionMenuPresenter.setWidthLimit( + getContext().getResources().getDisplayMetrics().widthPixels, true); + // No limit to the item count; use whatever will fit. + mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE); + // Span the whole width + layoutParams.width = LayoutParams.MATCH_PARENT; + layoutParams.height = mContentHeight; + mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); + mMenuView.setBackgroundDrawable(mSplitBackground); + final ViewGroup oldParent = (ViewGroup) mMenuView.getParent(); + if (oldParent != null) oldParent.removeView(mMenuView); + mSplitView.addView(mMenuView, layoutParams); + } + } + super.setSplitActionBar(split); + } + } + + public void setContentHeight(int height) { + mContentHeight = height; + } + + public void setCustomView(View view) { + if (mCustomView != null) { + removeView(mCustomView); + } + mCustomView = view; + if (mTitleLayout != null) { + removeView(mTitleLayout); + mTitleLayout = null; + } + if (view != null) { + addView(view); + } + requestLayout(); + } + + public void setTitle(CharSequence title) { + mTitle = title; + initTitle(); + } + + public void setSubtitle(CharSequence subtitle) { + mSubtitle = subtitle; + initTitle(); + } + + public CharSequence getTitle() { + return mTitle; + } + + public CharSequence getSubtitle() { + return mSubtitle; + } + + private void initTitle() { + if (mTitleLayout == null) { + LayoutInflater inflater = LayoutInflater.from(getContext()); + inflater.inflate(R.layout.abs__action_bar_title_item, this); + mTitleLayout = (LinearLayout) getChildAt(getChildCount() - 1); + mTitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_title); + mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_subtitle); + if (mTitleStyleRes != 0) { + mTitleView.setTextAppearance(mContext, mTitleStyleRes); + } + if (mSubtitleStyleRes != 0) { + mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes); + } + } + + mTitleView.setText(mTitle); + mSubtitleView.setText(mSubtitle); + + final boolean hasTitle = !TextUtils.isEmpty(mTitle); + final boolean hasSubtitle = !TextUtils.isEmpty(mSubtitle); + mSubtitleView.setVisibility(hasSubtitle ? VISIBLE : GONE); + mTitleLayout.setVisibility(hasTitle || hasSubtitle ? VISIBLE : GONE); + if (mTitleLayout.getParent() == null) { + addView(mTitleLayout); + } + } + + public void initForMode(final ActionMode mode) { + if (mClose == null) { + LayoutInflater inflater = LayoutInflater.from(mContext); + mClose = (NineLinearLayout)inflater.inflate(R.layout.abs__action_mode_close_item, this, false); + addView(mClose); + } else if (mClose.getParent() == null) { + addView(mClose); + } + + View closeButton = mClose.findViewById(R.id.abs__action_mode_close_button); + closeButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + mode.finish(); + } + }); + + final MenuBuilder menu = (MenuBuilder) mode.getMenu(); + if (mActionMenuPresenter != null) { + mActionMenuPresenter.dismissPopupMenus(); + } + mActionMenuPresenter = new ActionMenuPresenter(mContext); + mActionMenuPresenter.setReserveOverflow(true); + + final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.MATCH_PARENT); + if (!mSplitActionBar) { + menu.addMenuPresenter(mActionMenuPresenter); + mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); + mMenuView.setBackgroundDrawable(null); + addView(mMenuView, layoutParams); + } else { + // Allow full screen width in split mode. + mActionMenuPresenter.setWidthLimit( + getContext().getResources().getDisplayMetrics().widthPixels, true); + // No limit to the item count; use whatever will fit. + mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE); + // Span the whole width + layoutParams.width = LayoutParams.MATCH_PARENT; + layoutParams.height = mContentHeight; + menu.addMenuPresenter(mActionMenuPresenter); + mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); + mMenuView.setBackgroundDrawable(mSplitBackground); + mSplitView.addView(mMenuView, layoutParams); + } + + mAnimateInOnLayout = true; + } + + public void closeMode() { + if (mAnimationMode == ANIMATE_OUT) { + // Called again during close; just finish what we were doing. + return; + } + if (mClose == null) { + killMode(); + return; + } + + finishAnimation(); + mAnimationMode = ANIMATE_OUT; + mCurrentAnimation = makeOutAnimation(); + mCurrentAnimation.start(); + } + + private void finishAnimation() { + final Animator a = mCurrentAnimation; + if (a != null) { + mCurrentAnimation = null; + a.end(); + } + } + + public void killMode() { + finishAnimation(); + removeAllViews(); + if (mSplitView != null) { + mSplitView.removeView(mMenuView); + } + mCustomView = null; + mMenuView = null; + mAnimateInOnLayout = false; + } + + @Override + public boolean showOverflowMenu() { + if (mActionMenuPresenter != null) { + return mActionMenuPresenter.showOverflowMenu(); + } + return false; + } + + @Override + public boolean hideOverflowMenu() { + if (mActionMenuPresenter != null) { + return mActionMenuPresenter.hideOverflowMenu(); + } + return false; + } + + @Override + public boolean isOverflowMenuShowing() { + if (mActionMenuPresenter != null) { + return mActionMenuPresenter.isOverflowMenuShowing(); + } + return false; + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + // Used by custom views if they don't supply layout params. Everything else + // added to an ActionBarContextView should have them already. + return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); + } + + @Override + public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { + return new MarginLayoutParams(getContext(), attrs); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int widthMode = MeasureSpec.getMode(widthMeasureSpec); + if (widthMode != MeasureSpec.EXACTLY) { + throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + + "with android:layout_width=\"match_parent\" (or fill_parent)"); + } + + final int heightMode = MeasureSpec.getMode(heightMeasureSpec); + if (heightMode == MeasureSpec.UNSPECIFIED) { + throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + + "with android:layout_height=\"wrap_content\""); + } + + final int contentWidth = MeasureSpec.getSize(widthMeasureSpec); + + int maxHeight = mContentHeight > 0 ? + mContentHeight : MeasureSpec.getSize(heightMeasureSpec); + + final int verticalPadding = getPaddingTop() + getPaddingBottom(); + int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight(); + final int height = maxHeight - verticalPadding; + final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); + + if (mClose != null) { + availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0); + MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams(); + availableWidth -= lp.leftMargin + lp.rightMargin; + } + + if (mMenuView != null && mMenuView.getParent() == this) { + availableWidth = measureChildView(mMenuView, availableWidth, + childSpecHeight, 0); + } + + if (mTitleLayout != null && mCustomView == null) { + availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0); + } + + if (mCustomView != null) { + ViewGroup.LayoutParams lp = mCustomView.getLayoutParams(); + final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ? + MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; + final int customWidth = lp.width >= 0 ? + Math.min(lp.width, availableWidth) : availableWidth; + final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ? + MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; + final int customHeight = lp.height >= 0 ? + Math.min(lp.height, height) : height; + mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode), + MeasureSpec.makeMeasureSpec(customHeight, customHeightMode)); + } + + if (mContentHeight <= 0) { + int measuredHeight = 0; + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + View v = getChildAt(i); + int paddedViewHeight = v.getMeasuredHeight() + verticalPadding; + if (paddedViewHeight > measuredHeight) { + measuredHeight = paddedViewHeight; + } + } + setMeasuredDimension(contentWidth, measuredHeight); + } else { + setMeasuredDimension(contentWidth, maxHeight); + } + } + + private Animator makeInAnimation() { + mClose.setTranslationX(-mClose.getWidth() - + ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin); + ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX", 0); + buttonAnimator.setDuration(200); + buttonAnimator.addListener(this); + buttonAnimator.setInterpolator(new DecelerateInterpolator()); + + AnimatorSet set = new AnimatorSet(); + AnimatorSet.Builder b = set.play(buttonAnimator); + + if (mMenuView != null) { + final int count = mMenuView.getChildCount(); + if (count > 0) { + for (int i = count - 1, j = 0; i >= 0; i--, j++) { + AnimatorProxy child = AnimatorProxy.wrap(mMenuView.getChildAt(i)); + child.setScaleY(0); + ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0, 1); + a.setDuration(100); + a.setStartDelay(j * 70); + b.with(a); + } + } + } + + return set; + } + + private Animator makeOutAnimation() { + ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX", + -mClose.getWidth() - ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin); + buttonAnimator.setDuration(200); + buttonAnimator.addListener(this); + buttonAnimator.setInterpolator(new DecelerateInterpolator()); + + AnimatorSet set = new AnimatorSet(); + AnimatorSet.Builder b = set.play(buttonAnimator); + + if (mMenuView != null) { + final int count = mMenuView.getChildCount(); + if (count > 0) { + for (int i = 0; i < 0; i++) { + AnimatorProxy child = AnimatorProxy.wrap(mMenuView.getChildAt(i)); + child.setScaleY(0); + ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0); + a.setDuration(100); + a.setStartDelay(i * 70); + b.with(a); + } + } + } + + return set; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + int x = getPaddingLeft(); + final int y = getPaddingTop(); + final int contentHeight = b - t - getPaddingTop() - getPaddingBottom(); + + if (mClose != null && mClose.getVisibility() != GONE) { + MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams(); + x += lp.leftMargin; + x += positionChild(mClose, x, y, contentHeight); + x += lp.rightMargin; + + if (mAnimateInOnLayout) { + mAnimationMode = ANIMATE_IN; + mCurrentAnimation = makeInAnimation(); + mCurrentAnimation.start(); + mAnimateInOnLayout = false; + } + } + + if (mTitleLayout != null && mCustomView == null) { + x += positionChild(mTitleLayout, x, y, contentHeight); + } + + if (mCustomView != null) { + x += positionChild(mCustomView, x, y, contentHeight); + } + + x = r - l - getPaddingRight(); + + if (mMenuView != null) { + x -= positionChildInverse(mMenuView, x, y, contentHeight); + } + } + + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + if (mAnimationMode == ANIMATE_OUT) { + killMode(); + } + mAnimationMode = ANIMATE_IDLE; + } + + @Override + public void onAnimationCancel(Animator animation) { + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + + @Override + public boolean shouldDelayChildPressedState() { + return false; + } + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { + // Action mode started + //TODO event.setSource(this); + event.setClassName(getClass().getName()); + event.setPackageName(getContext().getPackageName()); + event.setContentDescription(mTitle); + } else { + //TODO super.onInitializeAccessibilityEvent(event); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarView.java index d51046eb..4636de17 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarView.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ActionBarView.java @@ -1,690 +1,1548 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.actionbarsherlock.internal.widget; +import org.xmlpull.v1.XmlPullParser; import android.app.Activity; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.AssetManager; +import android.content.res.Configuration; import android.content.res.TypedArray; +import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; -import android.support.v4.app.ActionBar; -import android.support.v4.view.Window; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; import android.util.AttributeSet; +import android.util.Log; +import android.view.Gravity; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; -import android.widget.AdapterView; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.RelativeLayout; -import android.widget.Spinner; import android.widget.SpinnerAdapter; import android.widget.TextView; + import com.actionbarsherlock.R; +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.app.ActionBar.OnNavigationListener; +import com.actionbarsherlock.internal.ActionBarSherlockCompat; import com.actionbarsherlock.internal.view.menu.ActionMenuItem; -import com.actionbarsherlock.internal.view.menu.ActionMenuItemView; +import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter; +import com.actionbarsherlock.internal.view.menu.ActionMenuView; +import com.actionbarsherlock.internal.view.menu.MenuBuilder; +import com.actionbarsherlock.internal.view.menu.MenuItemImpl; +import com.actionbarsherlock.internal.view.menu.MenuPresenter; +import com.actionbarsherlock.internal.view.menu.MenuView; +import com.actionbarsherlock.internal.view.menu.SubMenuBuilder; +import com.actionbarsherlock.view.CollapsibleActionView; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.Window; + +import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean; + +/** + * @hide + */ +public class ActionBarView extends AbsActionBarView { + private static final String TAG = "ActionBarView"; + private static final boolean DEBUG = false; -public final class ActionBarView extends RelativeLayout { - /** Default display options if none are defined in the theme. */ - private static final int DEFAULT_DISPLAY_OPTIONS = ActionBar.DISPLAY_SHOW_TITLE | ActionBar.DISPLAY_SHOW_HOME; + /** + * Display options applied by default + */ + public static final int DISPLAY_DEFAULT = 0; - /** Default navigation mode if one is not defined in the theme. */ - private static final int DEFAULT_NAVIGATION_MODE = ActionBar.NAVIGATION_MODE_STANDARD; + /** + * Display options that require re-layout as opposed to a simple invalidate + */ + private static final int DISPLAY_RELAYOUT_MASK = + ActionBar.DISPLAY_SHOW_HOME | + ActionBar.DISPLAY_USE_LOGO | + ActionBar.DISPLAY_HOME_AS_UP | + ActionBar.DISPLAY_SHOW_CUSTOM | + ActionBar.DISPLAY_SHOW_TITLE; + + private static final int DEFAULT_CUSTOM_GRAVITY = Gravity.LEFT | Gravity.CENTER_VERTICAL; + + private int mNavigationMode; + private int mDisplayOptions = -1; + private CharSequence mTitle; + private CharSequence mSubtitle; + private Drawable mIcon; + private Drawable mLogo; + private HomeView mHomeLayout; + private HomeView mExpandedHomeLayout; + private LinearLayout mTitleLayout; + private TextView mTitleView; + private TextView mSubtitleView; + private View mTitleUpView; + private IcsSpinner mSpinner; + private IcsLinearLayout mListNavLayout; + private ScrollingTabContainerView mTabScrollView; + private View mCustomNavView; + private IcsProgressBar mProgressView; + private IcsProgressBar mIndeterminateProgressView; - private final View mHomeAsUpView; - private final View mHomeLayout; - private final ActionMenuItem mLogoNavItem; + private int mProgressBarPadding; + private int mItemPadding; - private final CharSequence mTitle; - private final TextView mTitleLayout; + private int mTitleStyleRes; + private int mSubtitleStyleRes; + private int mProgressStyle; + private int mIndeterminateProgressStyle; - private final CharSequence mSubtitle; - private final TextView mSubtitleLayout; + private boolean mUserTitle; + private boolean mIncludeTabs; + private boolean mIsCollapsable; + private boolean mIsCollapsed; - /** Indeterminate progress bar. */ - private final ProgressBar mIndeterminateProgress; + private MenuBuilder mOptionsMenu; - /** List view. */ - private final Spinner mSpinner; - private SpinnerAdapter mSpinnerAdapter; - private final AdapterView.OnItemSelectedListener mNavItemSelectedListener; - private ActionBar.OnNavigationListener mCallback; + private ActionBarContextView mContextView; - /** Custom view parent. */ - private final FrameLayout mCustomView; - private View mCustomNavView; + private ActionMenuItem mLogoNavItem; - private ImageView mIconView; - private Drawable mLogo; - private Drawable mIcon; - private final Drawable mDivider; + private SpinnerAdapter mSpinnerAdapter; + private OnNavigationListener mCallback; - /** Container for all action items. */ - private final LinearLayout mActionsView; + //UNUSED private Runnable mTabSelector; - /** Container for all tab items. */ - private final LinearLayout mTabsView; + private ExpandedActionViewMenuPresenter mExpandedMenuPresenter; + View mExpandedActionView; - /** - * Display state flags. - * - * @see #getDisplayOptions() - * @see #getDisplayOptionValue(int) - * @see #setDisplayOptions(int) - * @see #setDisplayOptions(int, int) - * @see #setDisplayOption(int, boolean) - * @see #reloadDisplay() - */ - private int mDisplayOptions; + Window.Callback mWindowCallback; - /** - * Current navigation mode - * - * @see #getNavigationMode() - * @see #setNavigationMode(int) - */ - private int mNavigationMode = -1; + @SuppressWarnings("rawtypes") + private final IcsAdapterView.OnItemSelectedListener mNavItemSelectedListener = + new IcsAdapterView.OnItemSelectedListener() { + public void onItemSelected(IcsAdapterView parent, View view, int position, long id) { + if (mCallback != null) { + mCallback.onNavigationItemSelected(position, id); + } + } + public void onNothingSelected(IcsAdapterView parent) { + // Do nothing + } + }; - private boolean mIsConstructing; + private final OnClickListener mExpandedActionViewUpListener = new OnClickListener() { + @Override + public void onClick(View v) { + final MenuItemImpl item = mExpandedMenuPresenter.mCurrentExpandedItem; + if (item != null) { + item.collapseActionView(); + } + } + }; + private final OnClickListener mUpClickListener = new OnClickListener() { + public void onClick(View v) { + mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem); + } + }; + public ActionBarView(Context context, AttributeSet attrs) { + super(context, attrs); - public ActionBarView(Context context) { - this(context, null); - } + // Background is always provided by the container. + setBackgroundResource(0); - public ActionBarView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockActionBar, + R.attr.actionBarStyle, 0); - public ActionBarView(final Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - mIsConstructing = true; - LayoutInflater.from(context).inflate(R.layout.abs__action_bar, this, true); + ApplicationInfo appInfo = context.getApplicationInfo(); + PackageManager pm = context.getPackageManager(); + mNavigationMode = a.getInt(R.styleable.SherlockActionBar_navigationMode, + ActionBar.NAVIGATION_MODE_STANDARD); + mTitle = a.getText(R.styleable.SherlockActionBar_title); + mSubtitle = a.getText(R.styleable.SherlockActionBar_subtitle); - mNavItemSelectedListener = new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView arg0, View arg1, int arg2, long arg3) { - if (mCallback != null) { - mCallback.onNavigationItemSelected(arg2, arg3); + mLogo = a.getDrawable(R.styleable.SherlockActionBar_logo); + if (mLogo == null) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + if (context instanceof Activity) { + //Even though native methods existed in API 9 and 10 they don't work + //so just parse the manifest to look for the logo pre-Honeycomb + final int resId = loadLogoFromManifest((Activity) context); + if (resId != 0) { + mLogo = context.getResources().getDrawable(resId); + } + } + } else { + if (context instanceof Activity) { + try { + mLogo = pm.getActivityLogo(((Activity) context).getComponentName()); + } catch (NameNotFoundException e) { + Log.e(TAG, "Activity component name not found!", e); + } + } + if (mLogo == null) { + mLogo = appInfo.loadLogo(pm); } } + } - @Override - public void onNothingSelected(AdapterView arg0) { - //No op + mIcon = a.getDrawable(R.styleable.SherlockActionBar_icon); + if (mIcon == null) { + if (context instanceof Activity) { + try { + mIcon = pm.getActivityIcon(((Activity) context).getComponentName()); + } catch (NameNotFoundException e) { + Log.e(TAG, "Activity component name not found!", e); + } } - }; + if (mIcon == null) { + mIcon = appInfo.loadIcon(pm); + } + } - setBackgroundResource(0); + final LayoutInflater inflater = LayoutInflater.from(context); - final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockTheme, defStyle, 0); - final ApplicationInfo appInfo = context.getApplicationInfo(); - final PackageManager pm = context.getPackageManager(); + final int homeResId = a.getResourceId( + R.styleable.SherlockActionBar_homeLayout, + R.layout.abs__action_bar_home); + mHomeLayout = (HomeView) inflater.inflate(homeResId, this, false); - //// TITLE //// + mExpandedHomeLayout = (HomeView) inflater.inflate(homeResId, this, false); + mExpandedHomeLayout.setUp(true); + mExpandedHomeLayout.setOnClickListener(mExpandedActionViewUpListener); + mExpandedHomeLayout.setContentDescription(getResources().getText( + R.string.abs__action_bar_up_description)); - mTitleLayout = (TextView)findViewById(R.id.abs__action_bar_title); + mTitleStyleRes = a.getResourceId(R.styleable.SherlockActionBar_titleTextStyle, 0); + mSubtitleStyleRes = a.getResourceId(R.styleable.SherlockActionBar_subtitleTextStyle, 0); + mProgressStyle = a.getResourceId(R.styleable.SherlockActionBar_progressBarStyle, 0); + mIndeterminateProgressStyle = a.getResourceId( + R.styleable.SherlockActionBar_indeterminateProgressStyle, 0); - //Try to load title style from the theme - final int titleTextStyle = a.getResourceId(R.styleable.SherlockTheme_abTitleTextStyle, 0); - if (titleTextStyle != 0) { - mTitleLayout.setTextAppearance(context, titleTextStyle); - } + mProgressBarPadding = a.getDimensionPixelOffset(R.styleable.SherlockActionBar_progressBarPadding, 0); + mItemPadding = a.getDimensionPixelOffset(R.styleable.SherlockActionBar_itemPadding, 0); - //Try to load title from the theme - mTitle = a.getString(R.styleable.SherlockTheme_abTitle); - if (mTitle != null) { - setTitle(mTitle); + setDisplayOptions(a.getInt(R.styleable.SherlockActionBar_displayOptions, DISPLAY_DEFAULT)); + + final int customNavId = a.getResourceId(R.styleable.SherlockActionBar_customNavigationLayout, 0); + if (customNavId != 0) { + mCustomNavView = inflater.inflate(customNavId, this, false); + mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD; + setDisplayOptions(mDisplayOptions | ActionBar.DISPLAY_SHOW_CUSTOM); } + mContentHeight = a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0); - //// SUBTITLE //// + a.recycle(); - mSubtitleLayout = (TextView)findViewById(R.id.abs__action_bar_subtitle); + mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle); + mHomeLayout.setOnClickListener(mUpClickListener); + mHomeLayout.setClickable(true); + mHomeLayout.setFocusable(true); + } - //Try to load subtitle style from the theme - final int subtitleTextStyle = a.getResourceId(R.styleable.SherlockTheme_abSubtitleTextStyle, 0); - if (subtitleTextStyle != 0) { - mSubtitleLayout.setTextAppearance(context, subtitleTextStyle); + /** + * Attempt to programmatically load the logo from the manifest file of an + * activity by using an XML pull parser. This should allow us to read the + * logo attribute regardless of the platform it is being run on. + * + * @param activity Activity instance. + * @return Logo resource ID. + */ + private static int loadLogoFromManifest(Activity activity) { + int logo = 0; + try { + final String thisPackage = activity.getClass().getName(); + if (DEBUG) Log.i(TAG, "Parsing AndroidManifest.xml for " + thisPackage); + + final String packageName = activity.getApplicationInfo().packageName; + final AssetManager am = activity.createPackageContext(packageName, 0).getAssets(); + final XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml"); + + int eventType = xml.getEventType(); + while (eventType != XmlPullParser.END_DOCUMENT) { + if (eventType == XmlPullParser.START_TAG) { + String name = xml.getName(); + + if ("application".equals(name)) { + //Check if the has the attribute + if (DEBUG) Log.d(TAG, "Got "); + + for (int i = xml.getAttributeCount() - 1; i >= 0; i--) { + if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i)); + + if ("logo".equals(xml.getAttributeName(i))) { + logo = xml.getAttributeResourceValue(i, 0); + break; //out of for loop + } + } + } else if ("activity".equals(name)) { + //Check if the is us and has the attribute + if (DEBUG) Log.d(TAG, "Got "); + Integer activityLogo = null; + String activityPackage = null; + boolean isOurActivity = false; + + for (int i = xml.getAttributeCount() - 1; i >= 0; i--) { + if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i)); + + //We need both uiOptions and name attributes + String attrName = xml.getAttributeName(i); + if ("logo".equals(attrName)) { + activityLogo = xml.getAttributeResourceValue(i, 0); + } else if ("name".equals(attrName)) { + activityPackage = ActionBarSherlockCompat.cleanActivityName(packageName, xml.getAttributeValue(i)); + if (!thisPackage.equals(activityPackage)) { + break; //on to the next + } + isOurActivity = true; + } + + //Make sure we have both attributes before processing + if ((activityLogo != null) && (activityPackage != null)) { + //Our activity, logo specified, override with our value + logo = activityLogo.intValue(); + } + } + if (isOurActivity) { + //If we matched our activity but it had no logo don't + //do any more processing of the manifest + break; + } + } + } + eventType = xml.nextToken(); + } + } catch (Exception e) { + e.printStackTrace(); } + if (DEBUG) Log.i(TAG, "Returning " + Integer.toHexString(logo)); + return logo; + } - //Try to load subtitle from theme - mSubtitle = a.getString(R.styleable.SherlockTheme_abSubtitle); - if (mSubtitle != null) { - setSubtitle(mSubtitle); + /* + * Must be public so we can dispatch pre-2.2 via ActionBarImpl. + */ + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + mTitleView = null; + mSubtitleView = null; + mTitleUpView = null; + if (mTitleLayout != null && mTitleLayout.getParent() == this) { + removeView(mTitleLayout); } - - - /// HOME //// - - //TODO load optional home layout from theme - mHomeLayout = findViewById(R.id.abs__home_wrapper); - - //Try to load the logo from the theme - mLogo = a.getDrawable(R.styleable.SherlockTheme_abLogo); - /* - if ((mLogo == null) && (context instanceof Activity)) { - //LOGO LOADING DOES NOT WORK - //SEE: http://stackoverflow.com/questions/6105504/load-activity-and-or-application-logo-programmatically-from-manifest - //SEE: https://groups.google.com/forum/#!topic/android-developers/UFR4l0ZwJWc + mTitleLayout = null; + if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) { + initTitle(); } - */ - //Try to load the icon from the theme - mIcon = a.getDrawable(R.styleable.SherlockTheme_abIcon); - if ((mIcon == null) && (context instanceof Activity)) { - mIcon = appInfo.loadIcon(pm); + if (mTabScrollView != null && mIncludeTabs) { + ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams(); + if (lp != null) { + lp.width = LayoutParams.WRAP_CONTENT; + lp.height = LayoutParams.MATCH_PARENT; + } + mTabScrollView.setAllowCollapse(true); } + } - mHomeAsUpView = findViewById(R.id.abs__up); - mIconView = (ImageView)findViewById(R.id.abs__home); - - - //// NAVIGATION //// - - mSpinner = (Spinner)findViewById(R.id.abs__nav_list); - mSpinner.setOnItemSelectedListener(mNavItemSelectedListener); + /** + * Set the window callback used to invoke menu items; used for dispatching home button presses. + * @param cb Window callback to dispatch to + */ + public void setWindowCallback(Window.Callback cb) { + mWindowCallback = cb; + } - mTabsView = (LinearLayout)findViewById(R.id.abs__nav_tabs); + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + //UNUSED removeCallbacks(mTabSelector); + if (mActionMenuPresenter != null) { + mActionMenuPresenter.hideOverflowMenu(); + mActionMenuPresenter.hideSubMenus(); + } + } + @Override + public boolean shouldDelayChildPressedState() { + return false; + } - //// CUSTOM VIEW //// + public void initProgress() { + mProgressView = new IcsProgressBar(mContext, null, 0, mProgressStyle); + mProgressView.setId(R.id.abs__progress_horizontal); + mProgressView.setMax(10000); + addView(mProgressView); + } - mCustomView = (FrameLayout)findViewById(R.id.abs__custom); + public void initIndeterminateProgress() { + mIndeterminateProgressView = new IcsProgressBar(mContext, null, 0, mIndeterminateProgressStyle); + mIndeterminateProgressView.setId(R.id.abs__progress_circular); + addView(mIndeterminateProgressView); + } - //Try to load a custom view from the theme. This will NOT automatically - //trigger the visibility of the custom layout, however. - final int customViewResourceId = a.getResourceId(R.styleable.SherlockTheme_abCustomNavigationLayout, 0); - if (customViewResourceId != 0) { - mCustomNavView = LayoutInflater.from(context).inflate(customViewResourceId, mCustomView, true); - mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD; - setDisplayOptions(mDisplayOptions | ActionBar.DISPLAY_SHOW_CUSTOM); + @Override + public void setSplitActionBar(boolean splitActionBar) { + if (mSplitActionBar != splitActionBar) { + if (mMenuView != null) { + final ViewGroup oldParent = (ViewGroup) mMenuView.getParent(); + if (oldParent != null) { + oldParent.removeView(mMenuView); + } + if (splitActionBar) { + if (mSplitView != null) { + mSplitView.addView(mMenuView); + } + } else { + addView(mMenuView); + } + } + if (mSplitView != null) { + mSplitView.setVisibility(splitActionBar ? VISIBLE : GONE); + } + super.setSplitActionBar(splitActionBar); } + } + public boolean isSplitActionBar() { + return mSplitActionBar; + } + public boolean hasEmbeddedTabs() { + return mIncludeTabs; + } + public void setEmbeddedTabView(ScrollingTabContainerView tabs) { + if (mTabScrollView != null) { + removeView(mTabScrollView); + } + mTabScrollView = tabs; + mIncludeTabs = tabs != null; + if (mIncludeTabs && mNavigationMode == ActionBar.NAVIGATION_MODE_TABS) { + addView(mTabScrollView); + ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams(); + lp.width = LayoutParams.WRAP_CONTENT; + lp.height = LayoutParams.MATCH_PARENT; + tabs.setAllowCollapse(true); + } + } - mActionsView = (LinearLayout)findViewById(R.id.abs__actions); - mDivider = a.getDrawable(R.styleable.SherlockTheme_abDivider); - - mIndeterminateProgress = (ProgressBar)findViewById(R.id.abs__iprogress); - - //Try to get the display options defined in the theme, or fall back to - //displaying the title and home icon - setDisplayOptions(a.getInteger(R.styleable.SherlockTheme_abDisplayOptions, DEFAULT_DISPLAY_OPTIONS)); + public void setCallback(OnNavigationListener callback) { + mCallback = callback; + } - //Try to get the navigation defined in the theme, or, fall back to - //use standard navigation by default - setNavigationMode(a.getInteger(R.styleable.SherlockTheme_abNavigationMode, DEFAULT_NAVIGATION_MODE)); + public void setMenu(Menu menu, MenuPresenter.Callback cb) { + if (menu == mOptionsMenu) return; + if (mOptionsMenu != null) { + mOptionsMenu.removeMenuPresenter(mActionMenuPresenter); + mOptionsMenu.removeMenuPresenter(mExpandedMenuPresenter); + } - //Reduce, Reuse, Recycle! - a.recycle(); - mIsConstructing = false; + MenuBuilder builder = (MenuBuilder) menu; + mOptionsMenu = builder; + if (mMenuView != null) { + final ViewGroup oldParent = (ViewGroup) mMenuView.getParent(); + if (oldParent != null) { + oldParent.removeView(mMenuView); + } + } + if (mActionMenuPresenter == null) { + mActionMenuPresenter = new ActionMenuPresenter(mContext); + mActionMenuPresenter.setCallback(cb); + mActionMenuPresenter.setId(R.id.abs__action_menu_presenter); + mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter(); + } - mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle); - mHomeLayout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (context instanceof Activity) { - ((Activity)context).onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem); + ActionMenuView menuView; + final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.MATCH_PARENT); + if (!mSplitActionBar) { + mActionMenuPresenter.setExpandedActionViewsExclusive( + getResources_getBoolean(getContext(), + R.bool.abs__action_bar_expanded_action_views_exclusive)); + configPresenters(builder); + menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); + final ViewGroup oldParent = (ViewGroup) menuView.getParent(); + if (oldParent != null && oldParent != this) { + oldParent.removeView(menuView); + } + addView(menuView, layoutParams); + } else { + mActionMenuPresenter.setExpandedActionViewsExclusive(false); + // Allow full screen width in split mode. + mActionMenuPresenter.setWidthLimit( + getContext().getResources().getDisplayMetrics().widthPixels, true); + // No limit to the item count; use whatever will fit. + mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE); + // Span the whole width + layoutParams.width = LayoutParams.MATCH_PARENT; + configPresenters(builder); + menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this); + if (mSplitView != null) { + final ViewGroup oldParent = (ViewGroup) menuView.getParent(); + if (oldParent != null && oldParent != mSplitView) { + oldParent.removeView(menuView); } + menuView.setVisibility(getAnimatedVisibility()); + mSplitView.addView(menuView, layoutParams); + } else { + // We'll add this later if we missed it this time. + menuView.setLayoutParams(layoutParams); } - }); - mHomeLayout.setClickable(true); - mHomeLayout.setFocusable(true); + } + mMenuView = menuView; + } - reloadDisplay(); + private void configPresenters(MenuBuilder builder) { + if (builder != null) { + builder.addMenuPresenter(mActionMenuPresenter); + builder.addMenuPresenter(mExpandedMenuPresenter); + } else { + mActionMenuPresenter.initForMenu(mContext, null); + mExpandedMenuPresenter.initForMenu(mContext, null); + mActionMenuPresenter.updateMenuView(true); + mExpandedMenuPresenter.updateMenuView(true); + } } + public boolean hasExpandedActionView() { + return mExpandedMenuPresenter != null && + mExpandedMenuPresenter.mCurrentExpandedItem != null; + } + public void collapseActionView() { + final MenuItemImpl item = mExpandedMenuPresenter == null ? null : + mExpandedMenuPresenter.mCurrentExpandedItem; + if (item != null) { + item.collapseActionView(); + } + } - // ------------------------------------------------------------------------ - // HELPER METHODS - // ------------------------------------------------------------------------ + public void setCustomNavigationView(View view) { + final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0; + if (mCustomNavView != null && showCustom) { + removeView(mCustomNavView); + } + mCustomNavView = view; + if (mCustomNavView != null && showCustom) { + addView(mCustomNavView); + } + } + + public CharSequence getTitle() { + return mTitle; + } /** - * Helper to get a boolean value for a specific flag. + * Set the action bar title. This will always replace or override window titles. + * @param title Title to set * - * @param flag Target flag. - * @return Value. + * @see #setWindowTitle(CharSequence) */ - private boolean getDisplayOptionValue(int flag) { - return (mDisplayOptions & flag) == flag; + public void setTitle(CharSequence title) { + mUserTitle = true; + setTitleImpl(title); } /** - * Reload the current action bar display state. + * Set the window title. A window title will always be replaced or overridden by a user title. + * @param title Title to set + * + * @see #setTitle(CharSequence) */ - private void reloadDisplay() { - if (mIsConstructing) { - return; //Do not run if we are in the constructor + public void setWindowTitle(CharSequence title) { + if (!mUserTitle) { + setTitleImpl(title); } + } - final boolean isStandard = mNavigationMode == ActionBar.NAVIGATION_MODE_STANDARD; - final boolean isList = mNavigationMode == ActionBar.NAVIGATION_MODE_LIST; - final boolean isTab = mNavigationMode == ActionBar.NAVIGATION_MODE_TABS; - final boolean isTabUnderAb = isTab && getContext().getString(R.string.abs__tab_under_ab_tag).equals(mTabsView.getTag()); - final boolean hasSubtitle = (mSubtitleLayout.getText() != null) && !mSubtitleLayout.getText().equals(""); - final boolean displayHome = getDisplayOptionValue(ActionBar.DISPLAY_SHOW_HOME); - final boolean displayHomeAsUp = getDisplayOptionValue(ActionBar.DISPLAY_HOME_AS_UP); - final boolean displayTitle = getDisplayOptionValue(ActionBar.DISPLAY_SHOW_TITLE); - final boolean displayCustom = getDisplayOptionValue(ActionBar.DISPLAY_SHOW_CUSTOM); - final boolean displayLogo = getDisplayOptionValue(ActionBar.DISPLAY_USE_LOGO) && (mLogo != null); - - mHomeLayout.setVisibility(displayHome ? View.VISIBLE : View.GONE); - if (displayHome) { - mHomeAsUpView.setVisibility(displayHomeAsUp ? View.VISIBLE : View.GONE); - mIconView.setImageDrawable(displayLogo ? mLogo : mIcon); + private void setTitleImpl(CharSequence title) { + mTitle = title; + if (mTitleView != null) { + mTitleView.setText(title); + final boolean visible = mExpandedActionView == null && + (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0 && + (!TextUtils.isEmpty(mTitle) || !TextUtils.isEmpty(mSubtitle)); + mTitleLayout.setVisibility(visible ? VISIBLE : GONE); } + if (mLogoNavItem != null) { + mLogoNavItem.setTitle(title); + } + } - //Only show list if we are in list navigation and there are list items - mSpinner.setVisibility(isList ? View.VISIBLE : View.GONE); + public CharSequence getSubtitle() { + return mSubtitle; + } - // Show tabs if in tabs navigation mode. - mTabsView.setVisibility(isTab ? View.VISIBLE : View.GONE); + public void setSubtitle(CharSequence subtitle) { + mSubtitle = subtitle; + if (mSubtitleView != null) { + mSubtitleView.setText(subtitle); + mSubtitleView.setVisibility(subtitle != null ? VISIBLE : GONE); + final boolean visible = mExpandedActionView == null && + (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0 && + (!TextUtils.isEmpty(mTitle) || !TextUtils.isEmpty(mSubtitle)); + mTitleLayout.setVisibility(visible ? VISIBLE : GONE); + } + } - //Show title view if we are not in list navigation, not showing custom - //view, and the show title flag is true - mTitleLayout.setVisibility((isStandard || isTabUnderAb) && !displayCustom && displayTitle ? View.VISIBLE : View.GONE); - //Show subtitle view if we are not in list navigation, not showing - //custom view, show title flag is true, and a subtitle is set - mSubtitleLayout.setVisibility((isStandard || isTabUnderAb) && !displayCustom && displayTitle && hasSubtitle ? View.VISIBLE : View.GONE); - //Show custom view if we are not in list navigation and showing custom - //flag is set - mCustomView.setVisibility(isStandard && displayCustom ? View.VISIBLE : View.GONE); + public void setHomeButtonEnabled(boolean enable) { + mHomeLayout.setEnabled(enable); + mHomeLayout.setFocusable(enable); + // Make sure the home button has an accurate content description for accessibility. + if (!enable) { + mHomeLayout.setContentDescription(null); + } else if ((mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0) { + mHomeLayout.setContentDescription(mContext.getResources().getText( + R.string.abs__action_bar_up_description)); + } else { + mHomeLayout.setContentDescription(mContext.getResources().getText( + R.string.abs__action_bar_home_description)); + } } - // ------------------------------------------------------------------------ - // ACTION BAR API - // ------------------------------------------------------------------------ + public void setDisplayOptions(int options) { + final int flagsChanged = mDisplayOptions == -1 ? -1 : options ^ mDisplayOptions; + mDisplayOptions = options; - public void addTab(ActionBar.Tab tab) { - final int tabCount = getTabCount(); - addTab(tab, tabCount, tabCount == 0); + if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) { + final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0; + final int vis = showHome && mExpandedActionView == null ? VISIBLE : GONE; + mHomeLayout.setVisibility(vis); + + if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) { + final boolean setUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0; + mHomeLayout.setUp(setUp); + + // Showing home as up implicitly enables interaction with it. + // In honeycomb it was always enabled, so make this transition + // a bit easier for developers in the common case. + // (It would be silly to show it as up without responding to it.) + if (setUp) { + setHomeButtonEnabled(true); + } + } + + if ((flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) { + final boolean logoVis = mLogo != null && (options & ActionBar.DISPLAY_USE_LOGO) != 0; + mHomeLayout.setIcon(logoVis ? mLogo : mIcon); + } + + if ((flagsChanged & ActionBar.DISPLAY_SHOW_TITLE) != 0) { + if ((options & ActionBar.DISPLAY_SHOW_TITLE) != 0) { + initTitle(); + } else { + removeView(mTitleLayout); + } + } + + if (mTitleLayout != null && (flagsChanged & + (ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME)) != 0) { + final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0; + mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE); + mTitleLayout.setEnabled(!showHome && homeAsUp); + } + + if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) { + if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) { + addView(mCustomNavView); + } else { + removeView(mCustomNavView); + } + } + + requestLayout(); + } else { + invalidate(); + } + + // Make sure the home button has an accurate content description for accessibility. + if (!mHomeLayout.isEnabled()) { + mHomeLayout.setContentDescription(null); + } else if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) { + mHomeLayout.setContentDescription(mContext.getResources().getText( + R.string.abs__action_bar_up_description)); + } else { + mHomeLayout.setContentDescription(mContext.getResources().getText( + R.string.abs__action_bar_home_description)); + } } - public void addTab(ActionBar.Tab tab, boolean setSelected) { - addTab(tab, getTabCount(), setSelected); + public void setIcon(Drawable icon) { + mIcon = icon; + if (icon != null && + ((mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) == 0 || mLogo == null)) { + mHomeLayout.setIcon(icon); + } } - public void addTab(ActionBar.Tab tab, int position) { - addTab(tab, position, getTabCount() == 0); + public void setIcon(int resId) { + setIcon(mContext.getResources().getDrawable(resId)); } - public void addTab(ActionBar.Tab tab, int position, boolean setSelected) { - mTabsView.addView(((TabImpl)tab).mView, position); - if (setSelected) { - tab.select(); + public void setLogo(Drawable logo) { + mLogo = logo; + if (logo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) { + mHomeLayout.setIcon(logo); } } - public View getCustomView() { - return mCustomNavView; + public void setLogo(int resId) { + setLogo(mContext.getResources().getDrawable(resId)); } - public int getDisplayOptions() { - return mDisplayOptions; + public void setNavigationMode(int mode) { + final int oldMode = mNavigationMode; + if (mode != oldMode) { + switch (oldMode) { + case ActionBar.NAVIGATION_MODE_LIST: + if (mListNavLayout != null) { + removeView(mListNavLayout); + } + break; + case ActionBar.NAVIGATION_MODE_TABS: + if (mTabScrollView != null && mIncludeTabs) { + removeView(mTabScrollView); + } + } + + switch (mode) { + case ActionBar.NAVIGATION_MODE_LIST: + if (mSpinner == null) { + mSpinner = new IcsSpinner(mContext, null, + R.attr.actionDropDownStyle); + mListNavLayout = (IcsLinearLayout) LayoutInflater.from(mContext) + .inflate(R.layout.abs__action_bar_tab_bar_view, null); + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( + LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); + params.gravity = Gravity.CENTER; + mListNavLayout.addView(mSpinner, params); + } + if (mSpinner.getAdapter() != mSpinnerAdapter) { + mSpinner.setAdapter(mSpinnerAdapter); + } + mSpinner.setOnItemSelectedListener(mNavItemSelectedListener); + addView(mListNavLayout); + break; + case ActionBar.NAVIGATION_MODE_TABS: + if (mTabScrollView != null && mIncludeTabs) { + addView(mTabScrollView); + } + break; + } + mNavigationMode = mode; + requestLayout(); + } + } + + public void setDropdownAdapter(SpinnerAdapter adapter) { + mSpinnerAdapter = adapter; + if (mSpinner != null) { + mSpinner.setAdapter(adapter); + } } public SpinnerAdapter getDropdownAdapter() { - return this.mSpinnerAdapter; + return mSpinnerAdapter; + } + + public void setDropdownSelectedPosition(int position) { + mSpinner.setSelection(position); } public int getDropdownSelectedPosition() { - return this.mSpinner.getSelectedItemPosition(); + return mSpinner.getSelectedItemPosition(); + } + + public View getCustomNavigationView() { + return mCustomNavView; } public int getNavigationMode() { return mNavigationMode; } - public ActionBar.Tab getSelectedTab() { - final int count = mTabsView.getChildCount(); - for (int i = 0; i < count; i++) { - TabImpl tab = (TabImpl)mTabsView.getChildAt(i).getTag(); - if (tab.mView.isSelected()) { - return tab; + public int getDisplayOptions() { + return mDisplayOptions; + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + // Used by custom nav views if they don't supply layout params. Everything else + // added to an ActionBarView should have them already. + return new ActionBar.LayoutParams(DEFAULT_CUSTOM_GRAVITY); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + addView(mHomeLayout); + + if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) { + final ViewParent parent = mCustomNavView.getParent(); + if (parent != this) { + if (parent instanceof ViewGroup) { + ((ViewGroup) parent).removeView(mCustomNavView); + } + addView(mCustomNavView); } } - return null; } - public CharSequence getSubtitle() { - if ((mNavigationMode == ActionBar.NAVIGATION_MODE_STANDARD) && !mSubtitleLayout.getText().equals("")) { - return mSubtitleLayout.getText(); - } else { - return null; + private void initTitle() { + if (mTitleLayout == null) { + LayoutInflater inflater = LayoutInflater.from(getContext()); + mTitleLayout = (LinearLayout) inflater.inflate(R.layout.abs__action_bar_title_item, + this, false); + mTitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_title); + mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_subtitle); + mTitleUpView = mTitleLayout.findViewById(R.id.abs__up); + + mTitleLayout.setOnClickListener(mUpClickListener); + + if (mTitleStyleRes != 0) { + mTitleView.setTextAppearance(mContext, mTitleStyleRes); + } + if (mTitle != null) { + mTitleView.setText(mTitle); + } + + if (mSubtitleStyleRes != 0) { + mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes); + } + if (mSubtitle != null) { + mSubtitleView.setText(mSubtitle); + mSubtitleView.setVisibility(VISIBLE); + } + + final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0; + final boolean showHome = (mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0; + mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE); + mTitleLayout.setEnabled(homeAsUp && !showHome); } - } - public ActionBar.Tab getTabAt(int index) { - View view = mTabsView.getChildAt(index); - return (view != null) ? (TabImpl)view.getTag() : null; + addView(mTitleLayout); + if (mExpandedActionView != null || + (TextUtils.isEmpty(mTitle) && TextUtils.isEmpty(mSubtitle))) { + // Don't show while in expanded mode or with empty text + mTitleLayout.setVisibility(GONE); + } } - public int getTabCount() { - return mTabsView.getChildCount(); + public void setContextView(ActionBarContextView view) { + mContextView = view; } - public CharSequence getTitle() { - if ((mNavigationMode == ActionBar.NAVIGATION_MODE_STANDARD) && !mTitleLayout.getText().equals("")) { - return mTitleLayout.getText(); - } else { - return null; - } + public void setCollapsable(boolean collapsable) { + mIsCollapsable = collapsable; } - public TabImpl newTab() { - return new TabImpl(this); + public boolean isCollapsed() { + return mIsCollapsed; } - public void removeAllTabs() { - TabImpl selected = (TabImpl)getSelectedTab(); - if (selected != null) { - selected.unselect(); + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int childCount = getChildCount(); + if (mIsCollapsable) { + int visibleChildren = 0; + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + if (child.getVisibility() != GONE && + !(child == mMenuView && mMenuView.getChildCount() == 0)) { + visibleChildren++; + } + } + + if (visibleChildren == 0) { + // No size for an empty action bar when collapsable. + setMeasuredDimension(0, 0); + mIsCollapsed = true; + return; + } } - mTabsView.removeAllViews(); - } + mIsCollapsed = false; - public void removeTab(ActionBar.Tab tab) { - final int count = mTabsView.getChildCount(); - for (int i = 0; i < count; i++) { - TabImpl existingTab = (TabImpl)mTabsView.getChildAt(i).getTag(); - if (existingTab.equals(tab)) { - removeTabAt(i); - break; + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + if (widthMode != MeasureSpec.EXACTLY) { + throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + + "with android:layout_width=\"match_parent\" (or fill_parent)"); + } + + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + if (heightMode != MeasureSpec.AT_MOST) { + throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + + "with android:layout_height=\"wrap_content\""); + } + + int contentWidth = MeasureSpec.getSize(widthMeasureSpec); + + int maxHeight = mContentHeight > 0 ? + mContentHeight : MeasureSpec.getSize(heightMeasureSpec); + + final int verticalPadding = getPaddingTop() + getPaddingBottom(); + final int paddingLeft = getPaddingLeft(); + final int paddingRight = getPaddingRight(); + final int height = maxHeight - verticalPadding; + final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); + + int availableWidth = contentWidth - paddingLeft - paddingRight; + int leftOfCenter = availableWidth / 2; + int rightOfCenter = leftOfCenter; + + HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout; + + if (homeLayout.getVisibility() != GONE) { + final ViewGroup.LayoutParams lp = homeLayout.getLayoutParams(); + int homeWidthSpec; + if (lp.width < 0) { + homeWidthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST); + } else { + homeWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); } + homeLayout.measure(homeWidthSpec, + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); + final int homeWidth = homeLayout.getMeasuredWidth() + homeLayout.getLeftOffset(); + availableWidth = Math.max(0, availableWidth - homeWidth); + leftOfCenter = Math.max(0, availableWidth - homeWidth); } - } - public void removeTabAt(int position) { - TabImpl tab = (TabImpl)getTabAt(position); - if (tab != null) { - tab.unselect(); - mTabsView.removeViewAt(position); + if (mMenuView != null && mMenuView.getParent() == this) { + availableWidth = measureChildView(mMenuView, availableWidth, + childSpecHeight, 0); + rightOfCenter = Math.max(0, rightOfCenter - mMenuView.getMeasuredWidth()); + } - if (position > 0) { - //Select previous tab - ((TabImpl)mTabsView.getChildAt(position - 1).getTag()).select(); - } else if (mTabsView.getChildCount() > 0) { - //Select first tab - ((TabImpl)mTabsView.getChildAt(0).getTag()).select(); + if (mIndeterminateProgressView != null && + mIndeterminateProgressView.getVisibility() != GONE) { + availableWidth = measureChildView(mIndeterminateProgressView, availableWidth, + childSpecHeight, 0); + rightOfCenter = Math.max(0, + rightOfCenter - mIndeterminateProgressView.getMeasuredWidth()); + } + + final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE && + (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0; + + if (mExpandedActionView == null) { + switch (mNavigationMode) { + case ActionBar.NAVIGATION_MODE_LIST: + if (mListNavLayout != null) { + final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding; + availableWidth = Math.max(0, availableWidth - itemPaddingSize); + leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize); + mListNavLayout.measure( + MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); + final int listNavWidth = mListNavLayout.getMeasuredWidth(); + availableWidth = Math.max(0, availableWidth - listNavWidth); + leftOfCenter = Math.max(0, leftOfCenter - listNavWidth); + } + break; + case ActionBar.NAVIGATION_MODE_TABS: + if (mTabScrollView != null) { + final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding; + availableWidth = Math.max(0, availableWidth - itemPaddingSize); + leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize); + mTabScrollView.measure( + MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); + final int tabWidth = mTabScrollView.getMeasuredWidth(); + availableWidth = Math.max(0, availableWidth - tabWidth); + leftOfCenter = Math.max(0, leftOfCenter - tabWidth); + } + break; } } - } - public void setCallback(ActionBar.OnNavigationListener callback) { - mCallback = callback; - } + View customView = null; + if (mExpandedActionView != null) { + customView = mExpandedActionView; + } else if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && + mCustomNavView != null) { + customView = mCustomNavView; + } - public void setCustomNavigationView(View view) { - mCustomNavView = view; - mCustomView.removeAllViews(); - mCustomView.addView(view); - } + if (customView != null) { + final ViewGroup.LayoutParams lp = generateLayoutParams(customView.getLayoutParams()); + final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ? + (ActionBar.LayoutParams) lp : null; - public void setDisplayOptions(int options) { - mDisplayOptions = options; - reloadDisplay(); - } + int horizontalMargin = 0; + int verticalMargin = 0; + if (ablp != null) { + horizontalMargin = ablp.leftMargin + ablp.rightMargin; + verticalMargin = ablp.topMargin + ablp.bottomMargin; + } - public void setDropdownAdapter(SpinnerAdapter spinnerAdapter) { - mSpinnerAdapter = spinnerAdapter; - if (mSpinner != null) { - mSpinner.setAdapter(mSpinnerAdapter); + // If the action bar is wrapping to its content height, don't allow a custom + // view to MATCH_PARENT. + int customNavHeightMode; + if (mContentHeight <= 0) { + customNavHeightMode = MeasureSpec.AT_MOST; + } else { + customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ? + MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; + } + final int customNavHeight = Math.max(0, + (lp.height >= 0 ? Math.min(lp.height, height) : height) - verticalMargin); + + final int customNavWidthMode = lp.width != LayoutParams.WRAP_CONTENT ? + MeasureSpec.EXACTLY : MeasureSpec.AT_MOST; + int customNavWidth = Math.max(0, + (lp.width >= 0 ? Math.min(lp.width, availableWidth) : availableWidth) + - horizontalMargin); + final int hgrav = (ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY) & + Gravity.HORIZONTAL_GRAVITY_MASK; + + // Centering a custom view is treated specially; we try to center within the whole + // action bar rather than in the available space. + if (hgrav == Gravity.CENTER_HORIZONTAL && lp.width == LayoutParams.MATCH_PARENT) { + customNavWidth = Math.min(leftOfCenter, rightOfCenter) * 2; + } + + customView.measure( + MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode), + MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode)); + availableWidth -= horizontalMargin + customView.getMeasuredWidth(); } - } - public void setDropdownSelectedPosition(int position) { - mSpinner.setSelection(position); - } + if (mExpandedActionView == null && showTitle) { + availableWidth = measureChildView(mTitleLayout, availableWidth, + MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY), 0); + leftOfCenter = Math.max(0, leftOfCenter - mTitleLayout.getMeasuredWidth()); + } - public void setProgressBarIndeterminateVisibility(boolean visible) { - mIndeterminateProgress.setVisibility(visible ? View.VISIBLE : View.GONE); - } + if (mContentHeight <= 0) { + int measuredHeight = 0; + for (int i = 0; i < childCount; i++) { + View v = getChildAt(i); + int paddedViewHeight = v.getMeasuredHeight() + verticalPadding; + if (paddedViewHeight > measuredHeight) { + measuredHeight = paddedViewHeight; + } + } + setMeasuredDimension(contentWidth, measuredHeight); + } else { + setMeasuredDimension(contentWidth, maxHeight); + } - public void setNavigationMode(int mode) { - if ((mode != ActionBar.NAVIGATION_MODE_STANDARD) && (mode != ActionBar.NAVIGATION_MODE_LIST) - && (mode != ActionBar.NAVIGATION_MODE_TABS)) { - throw new IllegalArgumentException("Unknown navigation mode value " + Integer.toString(mode)); + if (mContextView != null) { + mContextView.setContentHeight(getMeasuredHeight()); } - if (mode != mNavigationMode) { - mNavigationMode = mode; - reloadDisplay(); + if (mProgressView != null && mProgressView.getVisibility() != GONE) { + mProgressView.measure(MeasureSpec.makeMeasureSpec( + contentWidth - mProgressBarPadding * 2, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST)); } } - public void selectTab(ActionBar.Tab tab) { - final int count = mTabsView.getChildCount(); - for (int i = 0; i < count; i++) { - TabImpl existingTab = (TabImpl)mTabsView.getChildAt(i).getTag(); - if (existingTab.equals(tab)) { - existingTab.select(); - break; + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + int x = getPaddingLeft(); + final int y = getPaddingTop(); + final int contentHeight = b - t - getPaddingTop() - getPaddingBottom(); + + if (contentHeight <= 0) { + // Nothing to do if we can't see anything. + return; + } + + HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout; + if (homeLayout.getVisibility() != GONE) { + final int leftOffset = homeLayout.getLeftOffset(); + x += positionChild(homeLayout, x + leftOffset, y, contentHeight) + leftOffset; + } + + if (mExpandedActionView == null) { + final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE && + (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0; + if (showTitle) { + x += positionChild(mTitleLayout, x, y, contentHeight); + } + + switch (mNavigationMode) { + case ActionBar.NAVIGATION_MODE_STANDARD: + break; + case ActionBar.NAVIGATION_MODE_LIST: + if (mListNavLayout != null) { + if (showTitle) x += mItemPadding; + x += positionChild(mListNavLayout, x, y, contentHeight) + mItemPadding; + } + break; + case ActionBar.NAVIGATION_MODE_TABS: + if (mTabScrollView != null) { + if (showTitle) x += mItemPadding; + x += positionChild(mTabScrollView, x, y, contentHeight) + mItemPadding; + } + break; } } - } - public void setSubtitle(CharSequence subtitle) { - mSubtitleLayout.setText((subtitle == null) ? "" : subtitle); - reloadDisplay(); - } + int menuLeft = r - l - getPaddingRight(); + if (mMenuView != null && mMenuView.getParent() == this) { + positionChildInverse(mMenuView, menuLeft, y, contentHeight); + menuLeft -= mMenuView.getMeasuredWidth(); + } + + if (mIndeterminateProgressView != null && + mIndeterminateProgressView.getVisibility() != GONE) { + positionChildInverse(mIndeterminateProgressView, menuLeft, y, contentHeight); + menuLeft -= mIndeterminateProgressView.getMeasuredWidth(); + } + + View customView = null; + if (mExpandedActionView != null) { + customView = mExpandedActionView; + } else if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && + mCustomNavView != null) { + customView = mCustomNavView; + } + if (customView != null) { + ViewGroup.LayoutParams lp = customView.getLayoutParams(); + final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ? + (ActionBar.LayoutParams) lp : null; + + final int gravity = ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY; + final int navWidth = customView.getMeasuredWidth(); + + int topMargin = 0; + int bottomMargin = 0; + if (ablp != null) { + x += ablp.leftMargin; + menuLeft -= ablp.rightMargin; + topMargin = ablp.topMargin; + bottomMargin = ablp.bottomMargin; + } + + int hgravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + // See if we actually have room to truly center; if not push against left or right. + if (hgravity == Gravity.CENTER_HORIZONTAL) { + final int centeredLeft = ((getRight() - getLeft()) - navWidth) / 2; + if (centeredLeft < x) { + hgravity = Gravity.LEFT; + } else if (centeredLeft + navWidth > menuLeft) { + hgravity = Gravity.RIGHT; + } + } else if (gravity == -1) { + hgravity = Gravity.LEFT; + } + + int xpos = 0; + switch (hgravity) { + case Gravity.CENTER_HORIZONTAL: + xpos = ((getRight() - getLeft()) - navWidth) / 2; + break; + case Gravity.LEFT: + xpos = x; + break; + case Gravity.RIGHT: + xpos = menuLeft - navWidth; + break; + } + + int vgravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; + + if (gravity == -1) { + vgravity = Gravity.CENTER_VERTICAL; + } - public void setSubtitle(int resId) { - mSubtitleLayout.setText(resId); - reloadDisplay(); + int ypos = 0; + switch (vgravity) { + case Gravity.CENTER_VERTICAL: + final int paddedTop = getPaddingTop(); + final int paddedBottom = getBottom() - getTop() - getPaddingBottom(); + ypos = ((paddedBottom - paddedTop) - customView.getMeasuredHeight()) / 2; + break; + case Gravity.TOP: + ypos = getPaddingTop() + topMargin; + break; + case Gravity.BOTTOM: + ypos = getHeight() - getPaddingBottom() - customView.getMeasuredHeight() + - bottomMargin; + break; + } + final int customWidth = customView.getMeasuredWidth(); + customView.layout(xpos, ypos, xpos + customWidth, + ypos + customView.getMeasuredHeight()); + x += customWidth; + } + + if (mProgressView != null) { + mProgressView.bringToFront(); + final int halfProgressHeight = mProgressView.getMeasuredHeight() / 2; + mProgressView.layout(mProgressBarPadding, -halfProgressHeight, + mProgressBarPadding + mProgressView.getMeasuredWidth(), halfProgressHeight); + } } - public void setTitle(CharSequence title) { - mTitleLayout.setText((title == null) ? "" : title); + @Override + public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { + return new ActionBar.LayoutParams(getContext(), attrs); } - public void setTitle(int resId) { - mTitleLayout.setText(resId); + @Override + public ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { + if (lp == null) { + lp = generateDefaultLayoutParams(); + } + return lp; } - // ------------------------------------------------------------------------ - // ACTION ITEMS SUPPORT - // ------------------------------------------------------------------------ + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + SavedState state = new SavedState(superState); - public ActionMenuItemView newItem() { - ActionMenuItemView item = (ActionMenuItemView)LayoutInflater.from(getContext()).inflate(R.layout.abs__action_bar_item_layout, mActionsView, false); - return item; + if (mExpandedMenuPresenter != null && mExpandedMenuPresenter.mCurrentExpandedItem != null) { + state.expandedMenuItemId = mExpandedMenuPresenter.mCurrentExpandedItem.getItemId(); + } + + state.isOverflowOpen = isOverflowMenuShowing(); + + return state; } - public void addItem(ActionMenuItemView item) { - if (mDivider != null) { - ImageView divider = new ImageView(getContext()); - divider.setImageDrawable(mDivider); - divider.setScaleType(ImageView.ScaleType.FIT_XY); + @Override + public void onRestoreInstanceState(Parcelable p) { + SavedState state = (SavedState) p; - LinearLayout.LayoutParams dividerParams = new LinearLayout.LayoutParams( - LinearLayout.LayoutParams.WRAP_CONTENT, - LinearLayout.LayoutParams.FILL_PARENT - ); + super.onRestoreInstanceState(state.getSuperState()); - mActionsView.addView(divider, dividerParams); - item.setDivider(divider); + if (state.expandedMenuItemId != 0 && + mExpandedMenuPresenter != null && mOptionsMenu != null) { + final MenuItem item = mOptionsMenu.findItem(state.expandedMenuItemId); + if (item != null) { + item.expandActionView(); + } } - mActionsView.addView(item); + if (state.isOverflowOpen) { + postShowOverflowMenu(); + } } - public void removeAllItems() { - mActionsView.removeAllViews(); - } + static class SavedState extends BaseSavedState { + int expandedMenuItemId; + boolean isOverflowOpen; - // ------------------------------------------------------------------------ - // HELPER INTERFACES AND HELPER CLASSES - // ------------------------------------------------------------------------ + SavedState(Parcelable superState) { + super(superState); + } - private static class TabImpl extends ActionBar.Tab { - private static final View.OnClickListener clickListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - ((TabImpl)v.getTag()).select(); - } - }; + private SavedState(Parcel in) { + super(in); + expandedMenuItemId = in.readInt(); + isOverflowOpen = in.readInt() != 0; + } - final ActionBarView mActionBar; - final View mView; - final ImageView mIconView; - final TextView mTextView; - final FrameLayout mCustomView; + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(expandedMenuItemId); + out.writeInt(isOverflowOpen ? 1 : 0); + } - ActionBar.TabListener mListener; - Object mTag; + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } - TabImpl(ActionBarView actionBar) { - mActionBar = actionBar; - mView = LayoutInflater.from(mActionBar.getContext()).inflate(R.layout.abs__action_bar_tab_layout, actionBar.mTabsView, false); - mView.setTag(this); - mView.setOnClickListener(clickListener); + public static class HomeView extends FrameLayout { + private View mUpView; + private ImageView mIconView; + private int mUpWidth; - mIconView = (ImageView)mView.findViewById(R.id.abs__tab_icon); - mTextView = (TextView)mView.findViewById(R.id.abs__tab); - mCustomView = (FrameLayout)mView.findViewById(R.id.abs__tab_custom); + public HomeView(Context context) { + this(context, null); } - /** - * Update display to reflect current property state. - */ - void reloadDisplay() { - boolean hasCustom = mCustomView.getChildCount() > 0; - mIconView.setVisibility(hasCustom ? View.GONE : View.VISIBLE); - mTextView.setVisibility(hasCustom ? View.GONE : View.VISIBLE); - mCustomView.setVisibility(hasCustom ? View.VISIBLE : View.GONE); + public HomeView(Context context, AttributeSet attrs) { + super(context, attrs); } - @Override - public View getCustomView() { - return mCustomView.getChildAt(0); + public void setUp(boolean isUp) { + mUpView.setVisibility(isUp ? VISIBLE : GONE); + } + + public void setIcon(Drawable icon) { + mIconView.setImageDrawable(icon); } @Override - public Drawable getIcon() { - return mIconView.getDrawable(); + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + onPopulateAccessibilityEvent(event); + return true; } @Override - public int getPosition() { - final int count = mActionBar.mTabsView.getChildCount(); - for (int i = 0; i < count; i++) { - if (mActionBar.mTabsView.getChildAt(i).getTag().equals(this)) { - return i; - } + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + super.onPopulateAccessibilityEvent(event); + } + final CharSequence cdesc = getContentDescription(); + if (!TextUtils.isEmpty(cdesc)) { + event.getText().add(cdesc); } - return -1; } @Override - public ActionBar.TabListener getTabListener() { - return mListener; + public boolean dispatchHoverEvent(MotionEvent event) { + // Don't allow children to hover; we want this to be treated as a single component. + return onHoverEvent(event); } @Override - public Object getTag() { - return mTag; + protected void onFinishInflate() { + mUpView = findViewById(R.id.abs__up); + mIconView = (ImageView) findViewById(R.id.abs__home); + } + + public int getLeftOffset() { + return mUpView.getVisibility() == GONE ? mUpWidth : 0; } @Override - public CharSequence getText() { - return mTextView.getText(); + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + measureChildWithMargins(mUpView, widthMeasureSpec, 0, heightMeasureSpec, 0); + final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams(); + mUpWidth = upLp.leftMargin + mUpView.getMeasuredWidth() + upLp.rightMargin; + int width = mUpView.getVisibility() == GONE ? 0 : mUpWidth; + int height = upLp.topMargin + mUpView.getMeasuredHeight() + upLp.bottomMargin; + measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0); + final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams(); + width += iconLp.leftMargin + mIconView.getMeasuredWidth() + iconLp.rightMargin; + height = Math.max(height, + iconLp.topMargin + mIconView.getMeasuredHeight() + iconLp.bottomMargin); + + final int widthMode = MeasureSpec.getMode(widthMeasureSpec); + final int heightMode = MeasureSpec.getMode(heightMeasureSpec); + final int widthSize = MeasureSpec.getSize(widthMeasureSpec); + final int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + switch (widthMode) { + case MeasureSpec.AT_MOST: + width = Math.min(width, widthSize); + break; + case MeasureSpec.EXACTLY: + width = widthSize; + break; + case MeasureSpec.UNSPECIFIED: + default: + break; + } + switch (heightMode) { + case MeasureSpec.AT_MOST: + height = Math.min(height, heightSize); + break; + case MeasureSpec.EXACTLY: + height = heightSize; + break; + case MeasureSpec.UNSPECIFIED: + default: + break; + } + setMeasuredDimension(width, height); } @Override - public TabImpl setCustomView(int layoutResId) { - mCustomView.removeAllViews(); - LayoutInflater.from(mActionBar.getContext()).inflate(layoutResId, mCustomView, true); - reloadDisplay(); - return this; + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int vCenter = (b - t) / 2; + //UNUSED int width = r - l; + int upOffset = 0; + if (mUpView.getVisibility() != GONE) { + final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams(); + final int upHeight = mUpView.getMeasuredHeight(); + final int upWidth = mUpView.getMeasuredWidth(); + final int upTop = vCenter - upHeight / 2; + mUpView.layout(0, upTop, upWidth, upTop + upHeight); + upOffset = upLp.leftMargin + upWidth + upLp.rightMargin; + //UNUSED width -= upOffset; + l += upOffset; + } + final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams(); + final int iconHeight = mIconView.getMeasuredHeight(); + final int iconWidth = mIconView.getMeasuredWidth(); + final int hCenter = (r - l) / 2; + final int iconLeft = upOffset + Math.max(iconLp.leftMargin, hCenter - iconWidth / 2); + final int iconTop = Math.max(iconLp.topMargin, vCenter - iconHeight / 2); + mIconView.layout(iconLeft, iconTop, iconLeft + iconWidth, iconTop + iconHeight); } + } + + private class ExpandedActionViewMenuPresenter implements MenuPresenter { + MenuBuilder mMenu; + MenuItemImpl mCurrentExpandedItem; @Override - public TabImpl setCustomView(View view) { - mCustomView.removeAllViews(); - if (view != null) { - mCustomView.addView(view); + public void initForMenu(Context context, MenuBuilder menu) { + // Clear the expanded action view when menus change. + if (mMenu != null && mCurrentExpandedItem != null) { + mMenu.collapseItemActionView(mCurrentExpandedItem); } - reloadDisplay(); - return this; + mMenu = menu; } @Override - public TabImpl setIcon(Drawable icon) { - mIconView.setImageDrawable(icon); - return this; + public MenuView getMenuView(ViewGroup root) { + return null; } @Override - public TabImpl setIcon(int resId) { - mIconView.setImageResource(resId); - return this; + public void updateMenuView(boolean cleared) { + // Make sure the expanded item we have is still there. + if (mCurrentExpandedItem != null) { + boolean found = false; + + if (mMenu != null) { + final int count = mMenu.size(); + for (int i = 0; i < count; i++) { + final MenuItem item = mMenu.getItem(i); + if (item == mCurrentExpandedItem) { + found = true; + break; + } + } + } + + if (!found) { + // The item we had expanded disappeared. Collapse. + collapseItemActionView(mMenu, mCurrentExpandedItem); + } + } } @Override - public TabImpl setTabListener(ActionBar.TabListener listener) { - mListener = listener; - return this; + public void setCallback(Callback cb) { } @Override - public TabImpl setTag(Object obj) { - mTag = obj; - return this; + public boolean onSubMenuSelected(SubMenuBuilder subMenu) { + return false; } @Override - public TabImpl setText(int resId) { - mTextView.setText(resId); - return this; + public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { } @Override - public TabImpl setText(CharSequence text) { - mTextView.setText(text); - return this; + public boolean flagActionItems() { + return false; } @Override - public void select() { - if (mView.isSelected()) { - if (mListener != null) { - mListener.onTabReselected(this, null); - } - return; + public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) { + mExpandedActionView = item.getActionView(); + mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(/* TODO getResources() */)); + mCurrentExpandedItem = item; + if (mExpandedActionView.getParent() != ActionBarView.this) { + addView(mExpandedActionView); } - - TabImpl current = (TabImpl)mActionBar.getSelectedTab(); - if (current != null) { - current.unselect(); + if (mExpandedHomeLayout.getParent() != ActionBarView.this) { + addView(mExpandedHomeLayout); } - - mView.setSelected(true); - if (mListener != null) { - mListener.onTabSelected(this, null); + mHomeLayout.setVisibility(GONE); + if (mTitleLayout != null) mTitleLayout.setVisibility(GONE); + if (mTabScrollView != null) mTabScrollView.setVisibility(GONE); + if (mSpinner != null) mSpinner.setVisibility(GONE); + if (mCustomNavView != null) mCustomNavView.setVisibility(GONE); + requestLayout(); + item.setActionViewExpanded(true); + + if (mExpandedActionView instanceof CollapsibleActionView) { + ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded(); } + + return true; } - /** - * Unselect this tab. Only valid if the tab has been added to the - * action bar and was previously selected. - */ - void unselect() { - if (mView.isSelected()) { - mView.setSelected(false); + @Override + public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) { + // Do this before detaching the actionview from the hierarchy, in case + // it needs to dismiss the soft keyboard, etc. + if (mExpandedActionView instanceof CollapsibleActionView) { + ((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed(); + } - if (mListener != null) { - mListener.onTabUnselected(this, null); + removeView(mExpandedActionView); + removeView(mExpandedHomeLayout); + mExpandedActionView = null; + if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0) { + mHomeLayout.setVisibility(VISIBLE); + } + if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) { + if (mTitleLayout == null) { + initTitle(); + } else { + mTitleLayout.setVisibility(VISIBLE); } } + if (mTabScrollView != null && mNavigationMode == ActionBar.NAVIGATION_MODE_TABS) { + mTabScrollView.setVisibility(VISIBLE); + } + if (mSpinner != null && mNavigationMode == ActionBar.NAVIGATION_MODE_LIST) { + mSpinner.setVisibility(VISIBLE); + } + if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) { + mCustomNavView.setVisibility(VISIBLE); + } + mExpandedHomeLayout.setIcon(null); + mCurrentExpandedItem = null; + requestLayout(); + item.setActionViewExpanded(false); + + return true; + } + + @Override + public int getId() { + return 0; + } + + @Override + public Parcelable onSaveInstanceState() { + return null; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { } } } diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CapitalizingButton.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CapitalizingButton.java new file mode 100644 index 00000000..fa3698f3 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CapitalizingButton.java @@ -0,0 +1,40 @@ +package com.actionbarsherlock.internal.widget; + +import java.util.Locale; +import android.content.Context; +import android.content.res.TypedArray; +import android.os.Build; +import android.util.AttributeSet; +import android.widget.Button; + +public class CapitalizingButton extends Button { + private static final boolean SANS_ICE_CREAM = Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH; + private static final boolean IS_GINGERBREAD = Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD; + + private static final int[] R_styleable_Button = new int[] { + android.R.attr.textAllCaps + }; + private static final int R_styleable_Button_textAllCaps = 0; + + private boolean mAllCaps; + + public CapitalizingButton(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R_styleable_Button); + mAllCaps = a.getBoolean(R_styleable_Button_textAllCaps, true); + a.recycle(); + } + + public void setTextCompat(CharSequence text) { + if (SANS_ICE_CREAM && mAllCaps && text != null) { + if (IS_GINGERBREAD) { + setText(text.toString().toUpperCase(Locale.ROOT)); + } else { + setText(text.toString().toUpperCase()); + } + } else { + setText(text); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java new file mode 100644 index 00000000..cae8b8ae --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java @@ -0,0 +1,50 @@ +package com.actionbarsherlock.internal.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.os.Build; +import android.util.AttributeSet; +import android.widget.TextView; + +import java.util.Locale; + +public class CapitalizingTextView extends TextView { + private static final boolean SANS_ICE_CREAM = Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH; + private static final boolean IS_GINGERBREAD = Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD; + + private static final int[] R_styleable_TextView = new int[] { + android.R.attr.textAllCaps + }; + private static final int R_styleable_TextView_textAllCaps = 0; + + private boolean mAllCaps; + + public CapitalizingTextView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public CapitalizingTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, R_styleable_TextView, defStyle, 0); + mAllCaps = a.getBoolean(R_styleable_TextView_textAllCaps, true); + a.recycle(); + } + + public void setTextCompat(CharSequence text) { + if (SANS_ICE_CREAM && mAllCaps && text != null) { + if (IS_GINGERBREAD) { + try { + setText(text.toString().toUpperCase(Locale.ROOT)); + } catch (NoSuchFieldError e) { + //Some manufacturer broke Locale.ROOT. See #572. + setText(text.toString().toUpperCase()); + } + } else { + setText(text.toString().toUpperCase()); + } + } else { + setText(text); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CollapsibleActionViewWrapper.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CollapsibleActionViewWrapper.java new file mode 100644 index 00000000..14f092c8 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/CollapsibleActionViewWrapper.java @@ -0,0 +1,30 @@ +package com.actionbarsherlock.internal.widget; + +import android.view.View; +import android.widget.FrameLayout; +import com.actionbarsherlock.view.CollapsibleActionView; + +/** + * Wraps an ABS collapsible action view in a native container that delegates the calls. + */ +public class CollapsibleActionViewWrapper extends FrameLayout implements android.view.CollapsibleActionView { + private final CollapsibleActionView child; + + public CollapsibleActionViewWrapper(View child) { + super(child.getContext()); + this.child = (CollapsibleActionView) child; + addView(child); + } + + @Override public void onActionViewExpanded() { + child.onActionViewExpanded(); + } + + @Override public void onActionViewCollapsed() { + child.onActionViewCollapsed(); + } + + public View unwrap() { + return getChildAt(0); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/FakeDialogPhoneWindow.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/FakeDialogPhoneWindow.java new file mode 100644 index 00000000..ad1b4f0a --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/FakeDialogPhoneWindow.java @@ -0,0 +1,64 @@ +package com.actionbarsherlock.internal.widget; + +import static android.view.View.MeasureSpec.EXACTLY; +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.widget.LinearLayout; +import com.actionbarsherlock.R; + +public class FakeDialogPhoneWindow extends LinearLayout { + final TypedValue mMinWidthMajor = new TypedValue(); + final TypedValue mMinWidthMinor = new TypedValue(); + + public FakeDialogPhoneWindow(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockTheme); + + a.getValue(R.styleable.SherlockTheme_windowMinWidthMajor, mMinWidthMajor); + a.getValue(R.styleable.SherlockTheme_windowMinWidthMinor, mMinWidthMinor); + + a.recycle(); + } + + /* Stolen from PhoneWindow */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); + final boolean isPortrait = metrics.widthPixels < metrics.heightPixels; + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int width = getMeasuredWidth(); + boolean measure = false; + + widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY); + + final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor; + + if (tv.type != TypedValue.TYPE_NULL) { + final int min; + if (tv.type == TypedValue.TYPE_DIMENSION) { + min = (int)tv.getDimension(metrics); + } else if (tv.type == TypedValue.TYPE_FRACTION) { + min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels); + } else { + min = 0; + } + + if (width < min) { + widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY); + measure = true; + } + } + + // TODO: Support height? + + if (measure) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsAbsSpinner.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsAbsSpinner.java new file mode 100644 index 00000000..ce0cb3bc --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsAbsSpinner.java @@ -0,0 +1,479 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.widget; + +import android.content.Context; +import android.database.DataSetObserver; +import android.graphics.Rect; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.view.View; +import android.view.ViewGroup; +import android.widget.SpinnerAdapter; + +/** + * An abstract base class for spinner widgets. SDK users will probably not + * need to use this class. + * + * @attr ref android.R.styleable#AbsSpinner_entries + */ +public abstract class IcsAbsSpinner extends IcsAdapterView { + private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; + + SpinnerAdapter mAdapter; + + int mHeightMeasureSpec; + int mWidthMeasureSpec; + boolean mBlockLayoutRequests; + + int mSelectionLeftPadding = 0; + int mSelectionTopPadding = 0; + int mSelectionRightPadding = 0; + int mSelectionBottomPadding = 0; + final Rect mSpinnerPadding = new Rect(); + + final RecycleBin mRecycler = new RecycleBin(); + private DataSetObserver mDataSetObserver; + + /** Temporary frame to hold a child View's frame rectangle */ + private Rect mTouchFrame; + + public IcsAbsSpinner(Context context) { + super(context); + initAbsSpinner(); + } + + public IcsAbsSpinner(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public IcsAbsSpinner(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initAbsSpinner(); + + /* + TypedArray a = context.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.AbsSpinner, defStyle, 0); + + CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries); + if (entries != null) { + ArrayAdapter adapter = + new ArrayAdapter(context, + R.layout.simple_spinner_item, entries); + adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item); + setAdapter(adapter); + } + + a.recycle(); + */ + } + + /** + * Common code for different constructor flavors + */ + private void initAbsSpinner() { + setFocusable(true); + setWillNotDraw(false); + } + + /** + * The Adapter is used to provide the data which backs this Spinner. + * It also provides methods to transform spinner items based on their position + * relative to the selected item. + * @param adapter The SpinnerAdapter to use for this Spinner + */ + @Override + public void setAdapter(SpinnerAdapter adapter) { + if (null != mAdapter) { + mAdapter.unregisterDataSetObserver(mDataSetObserver); + resetList(); + } + + mAdapter = adapter; + + mOldSelectedPosition = INVALID_POSITION; + mOldSelectedRowId = INVALID_ROW_ID; + + if (mAdapter != null) { + mOldItemCount = mItemCount; + mItemCount = mAdapter.getCount(); + checkFocus(); + + mDataSetObserver = new AdapterDataSetObserver(); + mAdapter.registerDataSetObserver(mDataSetObserver); + + int position = mItemCount > 0 ? 0 : INVALID_POSITION; + + setSelectedPositionInt(position); + setNextSelectedPositionInt(position); + + if (mItemCount == 0) { + // Nothing selected + checkSelectionChanged(); + } + + } else { + checkFocus(); + resetList(); + // Nothing selected + checkSelectionChanged(); + } + + requestLayout(); + } + + /** + * Clear out all children from the list + */ + void resetList() { + mDataChanged = false; + mNeedSync = false; + + removeAllViewsInLayout(); + mOldSelectedPosition = INVALID_POSITION; + mOldSelectedRowId = INVALID_ROW_ID; + + setSelectedPositionInt(INVALID_POSITION); + setNextSelectedPositionInt(INVALID_POSITION); + invalidate(); + } + + /** + * @see android.view.View#measure(int, int) + * + * Figure out the dimensions of this Spinner. The width comes from + * the widthMeasureSpec as Spinnners can't have their width set to + * UNSPECIFIED. The height is based on the height of the selected item + * plus padding. + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int widthSize; + int heightSize; + + final int mPaddingLeft = getPaddingLeft(); + final int mPaddingTop = getPaddingTop(); + final int mPaddingRight = getPaddingRight(); + final int mPaddingBottom = getPaddingBottom(); + + mSpinnerPadding.left = mPaddingLeft > mSelectionLeftPadding ? mPaddingLeft + : mSelectionLeftPadding; + mSpinnerPadding.top = mPaddingTop > mSelectionTopPadding ? mPaddingTop + : mSelectionTopPadding; + mSpinnerPadding.right = mPaddingRight > mSelectionRightPadding ? mPaddingRight + : mSelectionRightPadding; + mSpinnerPadding.bottom = mPaddingBottom > mSelectionBottomPadding ? mPaddingBottom + : mSelectionBottomPadding; + + if (mDataChanged) { + handleDataChanged(); + } + + int preferredHeight = 0; + int preferredWidth = 0; + boolean needsMeasuring = true; + + int selectedPosition = getSelectedItemPosition(); + if (selectedPosition >= 0 && mAdapter != null && selectedPosition < mAdapter.getCount()) { + // Try looking in the recycler. (Maybe we were measured once already) + View view = mRecycler.get(selectedPosition); + if (view == null) { + // Make a new one + view = mAdapter.getView(selectedPosition, null, this); + } + + if (view != null) { + // Put in recycler for re-measuring and/or layout + mRecycler.put(selectedPosition, view); + } + + if (view != null) { + if (view.getLayoutParams() == null) { + mBlockLayoutRequests = true; + view.setLayoutParams(generateDefaultLayoutParams()); + mBlockLayoutRequests = false; + } + measureChild(view, widthMeasureSpec, heightMeasureSpec); + + preferredHeight = getChildHeight(view) + mSpinnerPadding.top + mSpinnerPadding.bottom; + preferredWidth = getChildWidth(view) + mSpinnerPadding.left + mSpinnerPadding.right; + + needsMeasuring = false; + } + } + + if (needsMeasuring) { + // No views -- just use padding + preferredHeight = mSpinnerPadding.top + mSpinnerPadding.bottom; + if (widthMode == MeasureSpec.UNSPECIFIED) { + preferredWidth = mSpinnerPadding.left + mSpinnerPadding.right; + } + } + + preferredHeight = Math.max(preferredHeight, getSuggestedMinimumHeight()); + preferredWidth = Math.max(preferredWidth, getSuggestedMinimumWidth()); + + if (IS_HONEYCOMB) { + heightSize = resolveSizeAndState(preferredHeight, heightMeasureSpec, 0); + widthSize = resolveSizeAndState(preferredWidth, widthMeasureSpec, 0); + } else { + heightSize = resolveSize(preferredHeight, heightMeasureSpec); + widthSize = resolveSize(preferredWidth, widthMeasureSpec); + } + + setMeasuredDimension(widthSize, heightSize); + mHeightMeasureSpec = heightMeasureSpec; + mWidthMeasureSpec = widthMeasureSpec; + } + + int getChildHeight(View child) { + return child.getMeasuredHeight(); + } + + int getChildWidth(View child) { + return child.getMeasuredWidth(); + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + return new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + + void recycleAllViews() { + final int childCount = getChildCount(); + final IcsAbsSpinner.RecycleBin recycleBin = mRecycler; + final int position = mFirstPosition; + + // All views go in recycler + for (int i = 0; i < childCount; i++) { + View v = getChildAt(i); + int index = position + i; + recycleBin.put(index, v); + } + } + + /** + * Jump directly to a specific item in the adapter data. + */ + public void setSelection(int position, boolean animate) { + // Animate only if requested position is already on screen somewhere + boolean shouldAnimate = animate && mFirstPosition <= position && + position <= mFirstPosition + getChildCount() - 1; + setSelectionInt(position, shouldAnimate); + } + + @Override + public void setSelection(int position) { + setNextSelectedPositionInt(position); + requestLayout(); + invalidate(); + } + + + /** + * Makes the item at the supplied position selected. + * + * @param position Position to select + * @param animate Should the transition be animated + * + */ + void setSelectionInt(int position, boolean animate) { + if (position != mOldSelectedPosition) { + mBlockLayoutRequests = true; + int delta = position - mSelectedPosition; + setNextSelectedPositionInt(position); + layout(delta, animate); + mBlockLayoutRequests = false; + } + } + + abstract void layout(int delta, boolean animate); + + @Override + public View getSelectedView() { + if (mItemCount > 0 && mSelectedPosition >= 0) { + return getChildAt(mSelectedPosition - mFirstPosition); + } else { + return null; + } + } + + /** + * Override to prevent spamming ourselves with layout requests + * as we place views + * + * @see android.view.View#requestLayout() + */ + @Override + public void requestLayout() { + if (!mBlockLayoutRequests) { + super.requestLayout(); + } + } + + @Override + public SpinnerAdapter getAdapter() { + return mAdapter; + } + + @Override + public int getCount() { + return mItemCount; + } + + /** + * Maps a point to a position in the list. + * + * @param x X in local coordinate + * @param y Y in local coordinate + * @return The position of the item which contains the specified point, or + * {@link #INVALID_POSITION} if the point does not intersect an item. + */ + public int pointToPosition(int x, int y) { + Rect frame = mTouchFrame; + if (frame == null) { + mTouchFrame = new Rect(); + frame = mTouchFrame; + } + + final int count = getChildCount(); + for (int i = count - 1; i >= 0; i--) { + View child = getChildAt(i); + if (child.getVisibility() == View.VISIBLE) { + child.getHitRect(frame); + if (frame.contains(x, y)) { + return mFirstPosition + i; + } + } + } + return INVALID_POSITION; + } + + static class SavedState extends BaseSavedState { + long selectedId; + int position; + + /** + * Constructor called from {@link AbsSpinner#onSaveInstanceState()} + */ + SavedState(Parcelable superState) { + super(superState); + } + + /** + * Constructor called from {@link #CREATOR} + */ + private SavedState(Parcel in) { + super(in); + selectedId = in.readLong(); + position = in.readInt(); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeLong(selectedId); + out.writeInt(position); + } + + @Override + public String toString() { + return "AbsSpinner.SavedState{" + + Integer.toHexString(System.identityHashCode(this)) + + " selectedId=" + selectedId + + " position=" + position + "}"; + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + ss.selectedId = getSelectedItemId(); + if (ss.selectedId >= 0) { + ss.position = getSelectedItemPosition(); + } else { + ss.position = INVALID_POSITION; + } + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + + super.onRestoreInstanceState(ss.getSuperState()); + + if (ss.selectedId >= 0) { + mDataChanged = true; + mNeedSync = true; + mSyncRowId = ss.selectedId; + mSyncPosition = ss.position; + mSyncMode = SYNC_SELECTED_POSITION; + requestLayout(); + } + } + + class RecycleBin { + private final SparseArray mScrapHeap = new SparseArray(); + + public void put(int position, View v) { + mScrapHeap.put(position, v); + } + + View get(int position) { + // System.out.print("Looking for " + position); + View result = mScrapHeap.get(position); + if (result != null) { + // System.out.println(" HIT"); + mScrapHeap.delete(position); + } else { + // System.out.println(" MISS"); + } + return result; + } + + void clear() { + final SparseArray scrapHeap = mScrapHeap; + final int count = scrapHeap.size(); + for (int i = 0; i < count; i++) { + final View view = scrapHeap.valueAt(i); + if (view != null) { + removeDetachedView(view, true); + } + } + scrapHeap.clear(); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java new file mode 100644 index 00000000..c786dc5c --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java @@ -0,0 +1,1160 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.widget; + +import android.content.Context; +import android.database.DataSetObserver; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.view.ContextMenu; +import android.view.SoundEffectConstants; +import android.view.View; +import android.view.ViewDebug; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.Adapter; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ListView; + + +/** + * An AdapterView is a view whose children are determined by an {@link Adapter}. + * + *

+ * See {@link ListView}, {@link GridView}, {@link Spinner} and + * {@link Gallery} for commonly used subclasses of AdapterView. + * + *

+ *

Developer Guides

+ *

For more information about using AdapterView, read the + * Binding to Data with AdapterView + * developer guide.

+ */ +public abstract class IcsAdapterView extends ViewGroup { + + /** + * The item view type returned by {@link Adapter#getItemViewType(int)} when + * the adapter does not want the item's view recycled. + */ + public static final int ITEM_VIEW_TYPE_IGNORE = -1; + + /** + * The item view type returned by {@link Adapter#getItemViewType(int)} when + * the item is a header or footer. + */ + public static final int ITEM_VIEW_TYPE_HEADER_OR_FOOTER = -2; + + /** + * The position of the first child displayed + */ + @ViewDebug.ExportedProperty(category = "scrolling") + int mFirstPosition = 0; + + /** + * The offset in pixels from the top of the AdapterView to the top + * of the view to select during the next layout. + */ + int mSpecificTop; + + /** + * Position from which to start looking for mSyncRowId + */ + int mSyncPosition; + + /** + * Row id to look for when data has changed + */ + long mSyncRowId = INVALID_ROW_ID; + + /** + * Height of the view when mSyncPosition and mSyncRowId where set + */ + long mSyncHeight; + + /** + * True if we need to sync to mSyncRowId + */ + boolean mNeedSync = false; + + /** + * Indicates whether to sync based on the selection or position. Possible + * values are {@link #SYNC_SELECTED_POSITION} or + * {@link #SYNC_FIRST_POSITION}. + */ + int mSyncMode; + + /** + * Our height after the last layout + */ + private int mLayoutHeight; + + /** + * Sync based on the selected child + */ + static final int SYNC_SELECTED_POSITION = 0; + + /** + * Sync based on the first child displayed + */ + static final int SYNC_FIRST_POSITION = 1; + + /** + * Maximum amount of time to spend in {@link #findSyncPosition()} + */ + static final int SYNC_MAX_DURATION_MILLIS = 100; + + /** + * Indicates that this view is currently being laid out. + */ + boolean mInLayout = false; + + /** + * The listener that receives notifications when an item is selected. + */ + OnItemSelectedListener mOnItemSelectedListener; + + /** + * The listener that receives notifications when an item is clicked. + */ + OnItemClickListener mOnItemClickListener; + + /** + * The listener that receives notifications when an item is long clicked. + */ + OnItemLongClickListener mOnItemLongClickListener; + + /** + * True if the data has changed since the last layout + */ + boolean mDataChanged; + + /** + * The position within the adapter's data set of the item to select + * during the next layout. + */ + @ViewDebug.ExportedProperty(category = "list") + int mNextSelectedPosition = INVALID_POSITION; + + /** + * The item id of the item to select during the next layout. + */ + long mNextSelectedRowId = INVALID_ROW_ID; + + /** + * The position within the adapter's data set of the currently selected item. + */ + @ViewDebug.ExportedProperty(category = "list") + int mSelectedPosition = INVALID_POSITION; + + /** + * The item id of the currently selected item. + */ + long mSelectedRowId = INVALID_ROW_ID; + + /** + * View to show if there are no items to show. + */ + private View mEmptyView; + + /** + * The number of items in the current adapter. + */ + @ViewDebug.ExportedProperty(category = "list") + int mItemCount; + + /** + * The number of items in the adapter before a data changed event occurred. + */ + int mOldItemCount; + + /** + * Represents an invalid position. All valid positions are in the range 0 to 1 less than the + * number of items in the current adapter. + */ + public static final int INVALID_POSITION = -1; + + /** + * Represents an empty or invalid row id + */ + public static final long INVALID_ROW_ID = Long.MIN_VALUE; + + /** + * The last selected position we used when notifying + */ + int mOldSelectedPosition = INVALID_POSITION; + + /** + * The id of the last selected position we used when notifying + */ + long mOldSelectedRowId = INVALID_ROW_ID; + + /** + * Indicates what focusable state is requested when calling setFocusable(). + * In addition to this, this view has other criteria for actually + * determining the focusable state (such as whether its empty or the text + * filter is shown). + * + * @see #setFocusable(boolean) + * @see #checkFocus() + */ + private boolean mDesiredFocusableState; + private boolean mDesiredFocusableInTouchModeState; + + private SelectionNotifier mSelectionNotifier; + /** + * When set to true, calls to requestLayout() will not propagate up the parent hierarchy. + * This is used to layout the children during a layout pass. + */ + boolean mBlockLayoutRequests = false; + + public IcsAdapterView(Context context) { + super(context); + } + + public IcsAdapterView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public IcsAdapterView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Register a callback to be invoked when an item in this AdapterView has + * been clicked. + * + * @param listener The callback that will be invoked. + */ + public void setOnItemClickListener(OnItemClickListener listener) { + mOnItemClickListener = listener; + } + + /** + * @return The callback to be invoked with an item in this AdapterView has + * been clicked, or null id no callback has been set. + */ + public final OnItemClickListener getOnItemClickListener() { + return mOnItemClickListener; + } + + /** + * Call the OnItemClickListener, if it is defined. + * + * @param view The view within the AdapterView that was clicked. + * @param position The position of the view in the adapter. + * @param id The row id of the item that was clicked. + * @return True if there was an assigned OnItemClickListener that was + * called, false otherwise is returned. + */ + public boolean performItemClick(View view, int position, long id) { + if (mOnItemClickListener != null) { + playSoundEffect(SoundEffectConstants.CLICK); + if (view != null) { + view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); + } + mOnItemClickListener.onItemClick(/*this*/null, view, position, id); + return true; + } + + return false; + } + + /** + * Interface definition for a callback to be invoked when an item in this + * view has been clicked and held. + */ + public interface OnItemLongClickListener { + /** + * Callback method to be invoked when an item in this view has been + * clicked and held. + * + * Implementers can call getItemAtPosition(position) if they need to access + * the data associated with the selected item. + * + * @param parent The AbsListView where the click happened + * @param view The view within the AbsListView that was clicked + * @param position The position of the view in the list + * @param id The row id of the item that was clicked + * + * @return true if the callback consumed the long click, false otherwise + */ + boolean onItemLongClick(IcsAdapterView parent, View view, int position, long id); + } + + + /** + * Register a callback to be invoked when an item in this AdapterView has + * been clicked and held + * + * @param listener The callback that will run + */ + public void setOnItemLongClickListener(OnItemLongClickListener listener) { + if (!isLongClickable()) { + setLongClickable(true); + } + mOnItemLongClickListener = listener; + } + + /** + * @return The callback to be invoked with an item in this AdapterView has + * been clicked and held, or null id no callback as been set. + */ + public final OnItemLongClickListener getOnItemLongClickListener() { + return mOnItemLongClickListener; + } + + /** + * Interface definition for a callback to be invoked when + * an item in this view has been selected. + */ + public interface OnItemSelectedListener { + /** + *

Callback method to be invoked when an item in this view has been + * selected. This callback is invoked only when the newly selected + * position is different from the previously selected position or if + * there was no selected item.

+ * + * Impelmenters can call getItemAtPosition(position) if they need to access the + * data associated with the selected item. + * + * @param parent The AdapterView where the selection happened + * @param view The view within the AdapterView that was clicked + * @param position The position of the view in the adapter + * @param id The row id of the item that is selected + */ + void onItemSelected(IcsAdapterView parent, View view, int position, long id); + + /** + * Callback method to be invoked when the selection disappears from this + * view. The selection can disappear for instance when touch is activated + * or when the adapter becomes empty. + * + * @param parent The AdapterView that now contains no selected item. + */ + void onNothingSelected(IcsAdapterView parent); + } + + + /** + * Register a callback to be invoked when an item in this AdapterView has + * been selected. + * + * @param listener The callback that will run + */ + public void setOnItemSelectedListener(OnItemSelectedListener listener) { + mOnItemSelectedListener = listener; + } + + public final OnItemSelectedListener getOnItemSelectedListener() { + return mOnItemSelectedListener; + } + + /** + * Extra menu information provided to the + * {@link android.view.View.OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo) } + * callback when a context menu is brought up for this AdapterView. + * + */ + public static class AdapterContextMenuInfo implements ContextMenu.ContextMenuInfo { + + public AdapterContextMenuInfo(View targetView, int position, long id) { + this.targetView = targetView; + this.position = position; + this.id = id; + } + + /** + * The child view for which the context menu is being displayed. This + * will be one of the children of this AdapterView. + */ + public View targetView; + + /** + * The position in the adapter for which the context menu is being + * displayed. + */ + public int position; + + /** + * The row id of the item for which the context menu is being displayed. + */ + public long id; + } + + /** + * Returns the adapter currently associated with this widget. + * + * @return The adapter used to provide this view's content. + */ + public abstract T getAdapter(); + + /** + * Sets the adapter that provides the data and the views to represent the data + * in this widget. + * + * @param adapter The adapter to use to create this view's content. + */ + public abstract void setAdapter(T adapter); + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param child Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void addView(View child) { + throw new UnsupportedOperationException("addView(View) is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param child Ignored. + * @param index Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void addView(View child, int index) { + throw new UnsupportedOperationException("addView(View, int) is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param child Ignored. + * @param params Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void addView(View child, LayoutParams params) { + throw new UnsupportedOperationException("addView(View, LayoutParams) " + + "is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param child Ignored. + * @param index Ignored. + * @param params Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void addView(View child, int index, LayoutParams params) { + throw new UnsupportedOperationException("addView(View, int, LayoutParams) " + + "is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param child Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void removeView(View child) { + throw new UnsupportedOperationException("removeView(View) is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @param index Ignored. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void removeViewAt(int index) { + throw new UnsupportedOperationException("removeViewAt(int) is not supported in AdapterView"); + } + + /** + * This method is not supported and throws an UnsupportedOperationException when called. + * + * @throws UnsupportedOperationException Every time this method is invoked. + */ + @Override + public void removeAllViews() { + throw new UnsupportedOperationException("removeAllViews() is not supported in AdapterView"); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + mLayoutHeight = getHeight(); + } + + /** + * Return the position of the currently selected item within the adapter's data set + * + * @return int Position (starting at 0), or {@link #INVALID_POSITION} if there is nothing selected. + */ + @ViewDebug.CapturedViewProperty + public int getSelectedItemPosition() { + return mNextSelectedPosition; + } + + /** + * @return The id corresponding to the currently selected item, or {@link #INVALID_ROW_ID} + * if nothing is selected. + */ + @ViewDebug.CapturedViewProperty + public long getSelectedItemId() { + return mNextSelectedRowId; + } + + /** + * @return The view corresponding to the currently selected item, or null + * if nothing is selected + */ + public abstract View getSelectedView(); + + /** + * @return The data corresponding to the currently selected item, or + * null if there is nothing selected. + */ + public Object getSelectedItem() { + T adapter = getAdapter(); + int selection = getSelectedItemPosition(); + if (adapter != null && adapter.getCount() > 0 && selection >= 0) { + return adapter.getItem(selection); + } else { + return null; + } + } + + /** + * @return The number of items owned by the Adapter associated with this + * AdapterView. (This is the number of data items, which may be + * larger than the number of visible views.) + */ + @ViewDebug.CapturedViewProperty + public int getCount() { + return mItemCount; + } + + /** + * Get the position within the adapter's data set for the view, where view is a an adapter item + * or a descendant of an adapter item. + * + * @param view an adapter item, or a descendant of an adapter item. This must be visible in this + * AdapterView at the time of the call. + * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION} + * if the view does not correspond to a list item (or it is not currently visible). + */ + public int getPositionForView(View view) { + View listItem = view; + try { + View v; + while (!(v = (View) listItem.getParent()).equals(this)) { + listItem = v; + } + } catch (ClassCastException e) { + // We made it up to the window without find this list view + return INVALID_POSITION; + } + + // Search the children for the list item + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + if (getChildAt(i).equals(listItem)) { + return mFirstPosition + i; + } + } + + // Child not found! + return INVALID_POSITION; + } + + /** + * Returns the position within the adapter's data set for the first item + * displayed on screen. + * + * @return The position within the adapter's data set + */ + public int getFirstVisiblePosition() { + return mFirstPosition; + } + + /** + * Returns the position within the adapter's data set for the last item + * displayed on screen. + * + * @return The position within the adapter's data set + */ + public int getLastVisiblePosition() { + return mFirstPosition + getChildCount() - 1; + } + + /** + * Sets the currently selected item. To support accessibility subclasses that + * override this method must invoke the overriden super method first. + * + * @param position Index (starting at 0) of the data item to be selected. + */ + public abstract void setSelection(int position); + + /** + * Sets the view to show if the adapter is empty + */ + public void setEmptyView(View emptyView) { + mEmptyView = emptyView; + + final T adapter = getAdapter(); + final boolean empty = ((adapter == null) || adapter.isEmpty()); + updateEmptyStatus(empty); + } + + /** + * When the current adapter is empty, the AdapterView can display a special view + * call the empty view. The empty view is used to provide feedback to the user + * that no data is available in this AdapterView. + * + * @return The view to show if the adapter is empty. + */ + public View getEmptyView() { + return mEmptyView; + } + + /** + * Indicates whether this view is in filter mode. Filter mode can for instance + * be enabled by a user when typing on the keyboard. + * + * @return True if the view is in filter mode, false otherwise. + */ + boolean isInFilterMode() { + return false; + } + + @Override + public void setFocusable(boolean focusable) { + final T adapter = getAdapter(); + final boolean empty = adapter == null || adapter.getCount() == 0; + + mDesiredFocusableState = focusable; + if (!focusable) { + mDesiredFocusableInTouchModeState = false; + } + + super.setFocusable(focusable && (!empty || isInFilterMode())); + } + + @Override + public void setFocusableInTouchMode(boolean focusable) { + final T adapter = getAdapter(); + final boolean empty = adapter == null || adapter.getCount() == 0; + + mDesiredFocusableInTouchModeState = focusable; + if (focusable) { + mDesiredFocusableState = true; + } + + super.setFocusableInTouchMode(focusable && (!empty || isInFilterMode())); + } + + void checkFocus() { + final T adapter = getAdapter(); + final boolean empty = adapter == null || adapter.getCount() == 0; + final boolean focusable = !empty || isInFilterMode(); + // The order in which we set focusable in touch mode/focusable may matter + // for the client, see View.setFocusableInTouchMode() comments for more + // details + super.setFocusableInTouchMode(focusable && mDesiredFocusableInTouchModeState); + super.setFocusable(focusable && mDesiredFocusableState); + if (mEmptyView != null) { + updateEmptyStatus((adapter == null) || adapter.isEmpty()); + } + } + + /** + * Update the status of the list based on the empty parameter. If empty is true and + * we have an empty view, display it. In all the other cases, make sure that the listview + * is VISIBLE and that the empty view is GONE (if it's not null). + */ + private void updateEmptyStatus(boolean empty) { + if (isInFilterMode()) { + empty = false; + } + + if (empty) { + if (mEmptyView != null) { + mEmptyView.setVisibility(View.VISIBLE); + setVisibility(View.GONE); + } else { + // If the caller just removed our empty view, make sure the list view is visible + setVisibility(View.VISIBLE); + } + + // We are now GONE, so pending layouts will not be dispatched. + // Force one here to make sure that the state of the list matches + // the state of the adapter. + if (mDataChanged) { + this.onLayout(false, getLeft(), getTop(), getRight(), getBottom()); + } + } else { + if (mEmptyView != null) mEmptyView.setVisibility(View.GONE); + setVisibility(View.VISIBLE); + } + } + + /** + * Gets the data associated with the specified position in the list. + * + * @param position Which data to get + * @return The data associated with the specified position in the list + */ + public Object getItemAtPosition(int position) { + T adapter = getAdapter(); + return (adapter == null || position < 0) ? null : adapter.getItem(position); + } + + public long getItemIdAtPosition(int position) { + T adapter = getAdapter(); + return (adapter == null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position); + } + + @Override + public void setOnClickListener(OnClickListener l) { + throw new RuntimeException("Don't call setOnClickListener for an AdapterView. " + + "You probably want setOnItemClickListener instead"); + } + + /** + * Override to prevent freezing of any views created by the adapter. + */ + @Override + protected void dispatchSaveInstanceState(SparseArray container) { + dispatchFreezeSelfOnly(container); + } + + /** + * Override to prevent thawing of any views created by the adapter. + */ + @Override + protected void dispatchRestoreInstanceState(SparseArray container) { + dispatchThawSelfOnly(container); + } + + class AdapterDataSetObserver extends DataSetObserver { + + private Parcelable mInstanceState = null; + + @Override + public void onChanged() { + mDataChanged = true; + mOldItemCount = mItemCount; + mItemCount = getAdapter().getCount(); + + // Detect the case where a cursor that was previously invalidated has + // been repopulated with new data. + if (IcsAdapterView.this.getAdapter().hasStableIds() && mInstanceState != null + && mOldItemCount == 0 && mItemCount > 0) { + IcsAdapterView.this.onRestoreInstanceState(mInstanceState); + mInstanceState = null; + } else { + rememberSyncState(); + } + checkFocus(); + requestLayout(); + } + + @Override + public void onInvalidated() { + mDataChanged = true; + + if (IcsAdapterView.this.getAdapter().hasStableIds()) { + // Remember the current state for the case where our hosting activity is being + // stopped and later restarted + mInstanceState = IcsAdapterView.this.onSaveInstanceState(); + } + + // Data is invalid so we should reset our state + mOldItemCount = mItemCount; + mItemCount = 0; + mSelectedPosition = INVALID_POSITION; + mSelectedRowId = INVALID_ROW_ID; + mNextSelectedPosition = INVALID_POSITION; + mNextSelectedRowId = INVALID_ROW_ID; + mNeedSync = false; + + checkFocus(); + requestLayout(); + } + + public void clearSavedState() { + mInstanceState = null; + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + removeCallbacks(mSelectionNotifier); + } + + private class SelectionNotifier implements Runnable { + public void run() { + if (mDataChanged) { + // Data has changed between when this SelectionNotifier + // was posted and now. We need to wait until the AdapterView + // has been synched to the new data. + if (getAdapter() != null) { + post(this); + } + } else { + fireOnSelected(); + } + } + } + + void selectionChanged() { + if (mOnItemSelectedListener != null) { + if (mInLayout || mBlockLayoutRequests) { + // If we are in a layout traversal, defer notification + // by posting. This ensures that the view tree is + // in a consistent state and is able to accomodate + // new layout or invalidate requests. + if (mSelectionNotifier == null) { + mSelectionNotifier = new SelectionNotifier(); + } + post(mSelectionNotifier); + } else { + fireOnSelected(); + } + } + + // we fire selection events here not in View + if (mSelectedPosition != ListView.INVALID_POSITION && isShown() && !isInTouchMode()) { + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + } + } + + private void fireOnSelected() { + if (mOnItemSelectedListener == null) + return; + + int selection = this.getSelectedItemPosition(); + if (selection >= 0) { + View v = getSelectedView(); + mOnItemSelectedListener.onItemSelected(this, v, selection, + getAdapter().getItemId(selection)); + } else { + mOnItemSelectedListener.onNothingSelected(this); + } + } + + @Override + public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { + View selectedView = getSelectedView(); + if (selectedView != null && selectedView.getVisibility() == VISIBLE + && selectedView.dispatchPopulateAccessibilityEvent(event)) { + return true; + } + return false; + } + + @Override + public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) { + if (super.onRequestSendAccessibilityEvent(child, event)) { + // Add a record for ourselves as well. + AccessibilityEvent record = AccessibilityEvent.obtain(); + onInitializeAccessibilityEvent(record); + // Populate with the text of the requesting child. + child.dispatchPopulateAccessibilityEvent(record); + event.appendRecord(record); + return true; + } + return false; + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setScrollable(isScrollableForAccessibility()); + View selectedView = getSelectedView(); + if (selectedView != null) { + info.setEnabled(selectedView.isEnabled()); + } + } + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + event.setScrollable(isScrollableForAccessibility()); + View selectedView = getSelectedView(); + if (selectedView != null) { + event.setEnabled(selectedView.isEnabled()); + } + event.setCurrentItemIndex(getSelectedItemPosition()); + event.setFromIndex(getFirstVisiblePosition()); + event.setToIndex(getLastVisiblePosition()); + event.setItemCount(getCount()); + } + + private boolean isScrollableForAccessibility() { + T adapter = getAdapter(); + if (adapter != null) { + final int itemCount = adapter.getCount(); + return itemCount > 0 + && (getFirstVisiblePosition() > 0 || getLastVisiblePosition() < itemCount - 1); + } + return false; + } + + @Override + protected boolean canAnimate() { + return super.canAnimate() && mItemCount > 0; + } + + void handleDataChanged() { + final int count = mItemCount; + boolean found = false; + + if (count > 0) { + + int newPos; + + // Find the row we are supposed to sync to + if (mNeedSync) { + // Update this first, since setNextSelectedPositionInt inspects + // it + mNeedSync = false; + + // See if we can find a position in the new data with the same + // id as the old selection + newPos = findSyncPosition(); + if (newPos >= 0) { + // Verify that new selection is selectable + int selectablePos = lookForSelectablePosition(newPos, true); + if (selectablePos == newPos) { + // Same row id is selected + setNextSelectedPositionInt(newPos); + found = true; + } + } + } + if (!found) { + // Try to use the same position if we can't find matching data + newPos = getSelectedItemPosition(); + + // Pin position to the available range + if (newPos >= count) { + newPos = count - 1; + } + if (newPos < 0) { + newPos = 0; + } + + // Make sure we select something selectable -- first look down + int selectablePos = lookForSelectablePosition(newPos, true); + if (selectablePos < 0) { + // Looking down didn't work -- try looking up + selectablePos = lookForSelectablePosition(newPos, false); + } + if (selectablePos >= 0) { + setNextSelectedPositionInt(selectablePos); + checkSelectionChanged(); + found = true; + } + } + } + if (!found) { + // Nothing is selected + mSelectedPosition = INVALID_POSITION; + mSelectedRowId = INVALID_ROW_ID; + mNextSelectedPosition = INVALID_POSITION; + mNextSelectedRowId = INVALID_ROW_ID; + mNeedSync = false; + checkSelectionChanged(); + } + } + + void checkSelectionChanged() { + if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) { + selectionChanged(); + mOldSelectedPosition = mSelectedPosition; + mOldSelectedRowId = mSelectedRowId; + } + } + + /** + * Searches the adapter for a position matching mSyncRowId. The search starts at mSyncPosition + * and then alternates between moving up and moving down until 1) we find the right position, or + * 2) we run out of time, or 3) we have looked at every position + * + * @return Position of the row that matches mSyncRowId, or {@link #INVALID_POSITION} if it can't + * be found + */ + int findSyncPosition() { + int count = mItemCount; + + if (count == 0) { + return INVALID_POSITION; + } + + long idToMatch = mSyncRowId; + int seed = mSyncPosition; + + // If there isn't a selection don't hunt for it + if (idToMatch == INVALID_ROW_ID) { + return INVALID_POSITION; + } + + // Pin seed to reasonable values + seed = Math.max(0, seed); + seed = Math.min(count - 1, seed); + + long endTime = SystemClock.uptimeMillis() + SYNC_MAX_DURATION_MILLIS; + + long rowId; + + // first position scanned so far + int first = seed; + + // last position scanned so far + int last = seed; + + // True if we should move down on the next iteration + boolean next = false; + + // True when we have looked at the first item in the data + boolean hitFirst; + + // True when we have looked at the last item in the data + boolean hitLast; + + // Get the item ID locally (instead of getItemIdAtPosition), so + // we need the adapter + T adapter = getAdapter(); + if (adapter == null) { + return INVALID_POSITION; + } + + while (SystemClock.uptimeMillis() <= endTime) { + rowId = adapter.getItemId(seed); + if (rowId == idToMatch) { + // Found it! + return seed; + } + + hitLast = last == count - 1; + hitFirst = first == 0; + + if (hitLast && hitFirst) { + // Looked at everything + break; + } + + if (hitFirst || (next && !hitLast)) { + // Either we hit the top, or we are trying to move down + last++; + seed = last; + // Try going up next time + next = false; + } else if (hitLast || (!next && !hitFirst)) { + // Either we hit the bottom, or we are trying to move up + first--; + seed = first; + // Try going down next time + next = true; + } + + } + + return INVALID_POSITION; + } + + /** + * Find a position that can be selected (i.e., is not a separator). + * + * @param position The starting position to look at. + * @param lookDown Whether to look down for other positions. + * @return The next selectable position starting at position and then searching either up or + * down. Returns {@link #INVALID_POSITION} if nothing can be found. + */ + int lookForSelectablePosition(int position, boolean lookDown) { + return position; + } + + /** + * Utility to keep mSelectedPosition and mSelectedRowId in sync + * @param position Our current position + */ + void setSelectedPositionInt(int position) { + mSelectedPosition = position; + mSelectedRowId = getItemIdAtPosition(position); + } + + /** + * Utility to keep mNextSelectedPosition and mNextSelectedRowId in sync + * @param position Intended value for mSelectedPosition the next time we go + * through layout + */ + void setNextSelectedPositionInt(int position) { + mNextSelectedPosition = position; + mNextSelectedRowId = getItemIdAtPosition(position); + // If we are trying to sync to the selection, update that too + if (mNeedSync && mSyncMode == SYNC_SELECTED_POSITION && position >= 0) { + mSyncPosition = position; + mSyncRowId = mNextSelectedRowId; + } + } + + /** + * Remember enough information to restore the screen state when the data has + * changed. + * + */ + void rememberSyncState() { + if (getChildCount() > 0) { + mNeedSync = true; + mSyncHeight = mLayoutHeight; + if (mSelectedPosition >= 0) { + // Sync the selection state + View v = getChildAt(mSelectedPosition - mFirstPosition); + mSyncRowId = mNextSelectedRowId; + mSyncPosition = mNextSelectedPosition; + if (v != null) { + mSpecificTop = v.getTop(); + } + mSyncMode = SYNC_SELECTED_POSITION; + } else { + // Sync the based on the offset of the first view + View v = getChildAt(0); + T adapter = getAdapter(); + if (mFirstPosition >= 0 && mFirstPosition < adapter.getCount()) { + mSyncRowId = adapter.getItemId(mFirstPosition); + } else { + mSyncRowId = NO_ID; + } + mSyncPosition = mFirstPosition; + if (v != null) { + mSpecificTop = v.getTop(); + } + mSyncMode = SYNC_FIRST_POSITION; + } + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsColorDrawable.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsColorDrawable.java new file mode 100644 index 00000000..a78b3f71 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsColorDrawable.java @@ -0,0 +1,41 @@ +package com.actionbarsherlock.internal.widget; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; + +/** + * A version of {@link android.graphics.drawable.ColorDrawable} that respects bounds. + */ +public class IcsColorDrawable extends Drawable { + private int color; + private final Paint paint = new Paint(); + + public IcsColorDrawable(int color) { + this.color = color; + } + + @Override public void draw(Canvas canvas) { + if ((color >>> 24) != 0) { + paint.setColor(color); + canvas.drawRect(getBounds(), paint); + } + } + + @Override + public void setAlpha(int alpha) { + if (alpha != (color >>> 24)) { + color = (color & 0x00FFFFFF) & (alpha << 24); + invalidateSelf(); + } + } + + @Override public void setColorFilter(ColorFilter colorFilter) { + //Ignored + } + + @Override public int getOpacity() { + return color >>> 24; + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java new file mode 100644 index 00000000..4947c41d --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java @@ -0,0 +1,410 @@ +package com.actionbarsherlock.internal.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; + +import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout; + +/** + * A simple extension of a regular linear layout that supports the divider API + * of Android 4.0+. The dividers are added adjacent to the children by changing + * their layout params. If you need to rely on the margins which fall in the + * same orientation as the layout you should wrap the child in a simple + * {@link android.widget.FrameLayout} so it can receive the margin. + */ +public class IcsLinearLayout extends NineLinearLayout { + private static final int[] R_styleable_LinearLayout = new int[] { + /* 0 */ android.R.attr.divider, + /* 1 */ android.R.attr.measureWithLargestChild, + /* 2 */ android.R.attr.showDividers, + /* 3 */ android.R.attr.dividerPadding, + }; + private static final int LinearLayout_divider = 0; + private static final int LinearLayout_measureWithLargestChild = 1; + private static final int LinearLayout_showDividers = 2; + private static final int LinearLayout_dividerPadding = 3; + + /** + * Don't show any dividers. + */ + public static final int SHOW_DIVIDER_NONE = 0; + /** + * Show a divider at the beginning of the group. + */ + public static final int SHOW_DIVIDER_BEGINNING = 1; + /** + * Show dividers between each item in the group. + */ + public static final int SHOW_DIVIDER_MIDDLE = 2; + /** + * Show a divider at the end of the group. + */ + public static final int SHOW_DIVIDER_END = 4; + + + private Drawable mDivider; + private int mDividerWidth; + private int mDividerHeight; + private int mShowDividers; + private int mDividerPadding; + + private boolean mUseLargestChild; + + public IcsLinearLayout(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/R_styleable_LinearLayout); + + setDividerDrawable(a.getDrawable(/*com.android.internal.R.styleable.*/LinearLayout_divider)); + mShowDividers = a.getInt(/*com.android.internal.R.styleable.*/LinearLayout_showDividers, SHOW_DIVIDER_NONE); + mDividerPadding = a.getDimensionPixelSize(/*com.android.internal.R.styleable.*/LinearLayout_dividerPadding, 0); + mUseLargestChild = a.getBoolean(/*com.android.internal.R.styleable.*/LinearLayout_measureWithLargestChild, false); + + a.recycle(); + } + + /** + * Set how dividers should be shown between items in this layout + * + * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING}, + * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END}, + * or {@link #SHOW_DIVIDER_NONE} to show no dividers. + */ + public void setShowDividers(int showDividers) { + if (showDividers != mShowDividers) { + requestLayout(); + invalidate(); //XXX This is required if you are toggling a divider off + } + mShowDividers = showDividers; + } + + /** + * @return A flag set indicating how dividers should be shown around items. + * @see #setShowDividers(int) + */ + public int getShowDividers() { + return mShowDividers; + } + + /** + * Set a drawable to be used as a divider between items. + * @param divider Drawable that will divide each item. + * @see #setShowDividers(int) + */ + public void setDividerDrawable(Drawable divider) { + if (divider == mDivider) { + return; + } + mDivider = divider; + if (divider != null) { + mDividerWidth = divider.getIntrinsicWidth(); + mDividerHeight = divider.getIntrinsicHeight(); + } else { + mDividerWidth = 0; + mDividerHeight = 0; + } + setWillNotDraw(divider == null); + requestLayout(); + } + + /** + * Set padding displayed on both ends of dividers. + * + * @param padding Padding value in pixels that will be applied to each end + * + * @see #setShowDividers(int) + * @see #setDividerDrawable(Drawable) + * @see #getDividerPadding() + */ + public void setDividerPadding(int padding) { + mDividerPadding = padding; + } + + /** + * Get the padding size used to inset dividers in pixels + * + * @see #setShowDividers(int) + * @see #setDividerDrawable(Drawable) + * @see #setDividerPadding(int) + */ + public int getDividerPadding() { + return mDividerPadding; + } + + /** + * Get the width of the current divider drawable. + * + * @hide Used internally by framework. + */ + public int getDividerWidth() { + return mDividerWidth; + } + + @Override + protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { + final int index = indexOfChild(child); + final int orientation = getOrientation(); + final LayoutParams params = (LayoutParams) child.getLayoutParams(); + if (hasDividerBeforeChildAt(index)) { + if (orientation == VERTICAL) { + //Account for the divider by pushing everything up + params.topMargin = mDividerHeight; + } else { + //Account for the divider by pushing everything left + params.leftMargin = mDividerWidth; + } + } + + final int count = getChildCount(); + if (index == count - 1) { + if (hasDividerBeforeChildAt(count)) { + if (orientation == VERTICAL) { + params.bottomMargin = mDividerHeight; + } else { + params.rightMargin = mDividerWidth; + } + } + } + super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed); + } + + @Override + protected void onDraw(Canvas canvas) { + if (mDivider != null) { + if (getOrientation() == VERTICAL) { + drawDividersVertical(canvas); + } else { + drawDividersHorizontal(canvas); + } + } + super.onDraw(canvas); + } + + void drawDividersVertical(Canvas canvas) { + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + + if (child != null && child.getVisibility() != GONE) { + if (hasDividerBeforeChildAt(i)) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/; + drawHorizontalDivider(canvas, top); + } + } + } + + if (hasDividerBeforeChildAt(count)) { + final View child = getChildAt(count - 1); + int bottom = 0; + if (child == null) { + bottom = getHeight() - getPaddingBottom() - mDividerHeight; + } else { + //final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + bottom = child.getBottom()/* + lp.bottomMargin*/; + } + drawHorizontalDivider(canvas, bottom); + } + } + + void drawDividersHorizontal(Canvas canvas) { + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + + if (child != null && child.getVisibility() != GONE) { + if (hasDividerBeforeChildAt(i)) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/; + drawVerticalDivider(canvas, left); + } + } + } + + if (hasDividerBeforeChildAt(count)) { + final View child = getChildAt(count - 1); + int right = 0; + if (child == null) { + right = getWidth() - getPaddingRight() - mDividerWidth; + } else { + //final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + right = child.getRight()/* + lp.rightMargin*/; + } + drawVerticalDivider(canvas, right); + } + } + + void drawHorizontalDivider(Canvas canvas, int top) { + mDivider.setBounds(getPaddingLeft() + mDividerPadding, top, + getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight); + mDivider.draw(canvas); + } + + void drawVerticalDivider(Canvas canvas, int left) { + mDivider.setBounds(left, getPaddingTop() + mDividerPadding, + left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding); + mDivider.draw(canvas); + } + + /** + * Determines where to position dividers between children. + * + * @param childIndex Index of child to check for preceding divider + * @return true if there should be a divider before the child at childIndex + * @hide Pending API consideration. Currently only used internally by the system. + */ + protected boolean hasDividerBeforeChildAt(int childIndex) { + if (childIndex == 0) { + return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0; + } else if (childIndex == getChildCount()) { + return (mShowDividers & SHOW_DIVIDER_END) != 0; + } else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) { + boolean hasVisibleViewBefore = false; + for (int i = childIndex - 1; i >= 0; i--) { + if (getChildAt(i).getVisibility() != GONE) { + hasVisibleViewBefore = true; + break; + } + } + return hasVisibleViewBefore; + } + return false; + } + + /** + * When true, all children with a weight will be considered having + * the minimum size of the largest child. If false, all children are + * measured normally. + * + * @return True to measure children with a weight using the minimum + * size of the largest child, false otherwise. + * + * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild + */ + public boolean isMeasureWithLargestChildEnabled() { + return mUseLargestChild; + } + + /** + * When set to true, all children with a weight will be considered having + * the minimum size of the largest child. If false, all children are + * measured normally. + * + * Disabled by default. + * + * @param enabled True to measure children with a weight using the + * minimum size of the largest child, false otherwise. + * + * @attr ref android.R.styleable#LinearLayout_measureWithLargestChild + */ + public void setMeasureWithLargestChildEnabled(boolean enabled) { + mUseLargestChild = enabled; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + if (mUseLargestChild) { + final int orientation = getOrientation(); + switch (orientation) { + case HORIZONTAL: + useLargestChildHorizontal(); + break; + + case VERTICAL: + useLargestChildVertical(); + break; + } + } + } + + private void useLargestChildHorizontal() { + final int childCount = getChildCount(); + + // Find largest child width + int largestChildWidth = 0; + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + largestChildWidth = Math.max(child.getMeasuredWidth(), largestChildWidth); + } + + int totalWidth = 0; + // Re-measure childs + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + + if (child == null || child.getVisibility() == View.GONE) { + continue; + } + + final LinearLayout.LayoutParams lp = + (LinearLayout.LayoutParams) child.getLayoutParams(); + + float childExtra = lp.weight; + if (childExtra > 0) { + child.measure( + MeasureSpec.makeMeasureSpec(largestChildWidth, + MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(), + MeasureSpec.EXACTLY)); + totalWidth += largestChildWidth; + + } else { + totalWidth += child.getMeasuredWidth(); + } + + totalWidth += lp.leftMargin + lp.rightMargin; + } + + totalWidth += getPaddingLeft() + getPaddingRight(); + setMeasuredDimension(totalWidth, getMeasuredHeight()); + } + + private void useLargestChildVertical() { + final int childCount = getChildCount(); + + // Find largest child width + int largestChildHeight = 0; + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + largestChildHeight = Math.max(child.getMeasuredHeight(), largestChildHeight); + } + + int totalHeight = 0; + // Re-measure childs + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + + if (child == null || child.getVisibility() == View.GONE) { + continue; + } + + final LinearLayout.LayoutParams lp = + (LinearLayout.LayoutParams) child.getLayoutParams(); + + float childExtra = lp.weight; + if (childExtra > 0) { + child.measure( + MeasureSpec.makeMeasureSpec(child.getMeasuredWidth(), + MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(largestChildHeight, + MeasureSpec.EXACTLY)); + totalHeight += largestChildHeight; + + } else { + totalHeight += child.getMeasuredHeight(); + } + + totalHeight += lp.leftMargin + lp.rightMargin; + } + + totalHeight += getPaddingLeft() + getPaddingRight(); + setMeasuredDimension(getMeasuredWidth(), totalHeight); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java new file mode 100644 index 00000000..d13c6cea --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java @@ -0,0 +1,644 @@ +package com.actionbarsherlock.internal.widget; + +import com.actionbarsherlock.R; + +import android.content.Context; +import android.content.res.Resources; +import android.database.DataSetObserver; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Handler; +import android.util.AttributeSet; +import android.view.ContextThemeWrapper; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.MeasureSpec; +import android.view.View.OnTouchListener; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.widget.AbsListView; +import android.widget.AdapterView; +import android.widget.LinearLayout; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.PopupWindow; + +/** + * A proxy between pre- and post-Honeycomb implementations of this class. + */ +public class IcsListPopupWindow { + /** + * This value controls the length of time that the user + * must leave a pointer down without scrolling to expand + * the autocomplete dropdown list to cover the IME. + */ + private static final int EXPAND_LIST_TIMEOUT = 250; + + private Context mContext; + private PopupWindow mPopup; + private ListAdapter mAdapter; + private DropDownListView mDropDownList; + + private int mDropDownHeight = ViewGroup.LayoutParams.WRAP_CONTENT; + private int mDropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT; + private int mDropDownHorizontalOffset; + private int mDropDownVerticalOffset; + private boolean mDropDownVerticalOffsetSet; + + private int mListItemExpandMaximum = Integer.MAX_VALUE; + + private View mPromptView; + private int mPromptPosition = POSITION_PROMPT_ABOVE; + + private DataSetObserver mObserver; + + private View mDropDownAnchorView; + + private Drawable mDropDownListHighlight; + + private AdapterView.OnItemClickListener mItemClickListener; + private AdapterView.OnItemSelectedListener mItemSelectedListener; + + private final ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable(); + private final PopupTouchInterceptor mTouchInterceptor = new PopupTouchInterceptor(); + private final PopupScrollListener mScrollListener = new PopupScrollListener(); + private final ListSelectorHider mHideSelector = new ListSelectorHider(); + + private Handler mHandler = new Handler(); + + private Rect mTempRect = new Rect(); + + private boolean mModal; + + public static final int POSITION_PROMPT_ABOVE = 0; + public static final int POSITION_PROMPT_BELOW = 1; + + public IcsListPopupWindow(Context context) { + this(context, null, R.attr.listPopupWindowStyle); + } + + public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) { + mContext = context; + mPopup = new PopupWindow(context, attrs, defStyleAttr); + mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); + } + + public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + mContext = context; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + Context wrapped = new ContextThemeWrapper(context, defStyleRes); + mPopup = new PopupWindow(wrapped, attrs, defStyleAttr); + } else { + mPopup = new PopupWindow(context, attrs, defStyleAttr, defStyleRes); + } + mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); + } + + public void setAdapter(ListAdapter adapter) { + if (mObserver == null) { + mObserver = new PopupDataSetObserver(); + } else if (mAdapter != null) { + mAdapter.unregisterDataSetObserver(mObserver); + } + mAdapter = adapter; + if (mAdapter != null) { + adapter.registerDataSetObserver(mObserver); + } + + if (mDropDownList != null) { + mDropDownList.setAdapter(mAdapter); + } + } + + public void setPromptPosition(int position) { + mPromptPosition = position; + } + + public void setModal(boolean modal) { + mModal = true; + mPopup.setFocusable(modal); + } + + public void setBackgroundDrawable(Drawable d) { + mPopup.setBackgroundDrawable(d); + } + + public void setAnchorView(View anchor) { + mDropDownAnchorView = anchor; + } + + public void setHorizontalOffset(int offset) { + mDropDownHorizontalOffset = offset; + } + + public void setVerticalOffset(int offset) { + mDropDownVerticalOffset = offset; + mDropDownVerticalOffsetSet = true; + } + + public void setContentWidth(int width) { + Drawable popupBackground = mPopup.getBackground(); + if (popupBackground != null) { + popupBackground.getPadding(mTempRect); + mDropDownWidth = mTempRect.left + mTempRect.right + width; + } else { + mDropDownWidth = width; + } + } + + public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) { + mItemClickListener = clickListener; + } + + public void show() { + int height = buildDropDown(); + + int widthSpec = 0; + int heightSpec = 0; + + boolean noInputMethod = isInputMethodNotNeeded(); + //XXX mPopup.setAllowScrollingAnchorParent(!noInputMethod); + + if (mPopup.isShowing()) { + if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) { + // The call to PopupWindow's update method below can accept -1 for any + // value you do not want to update. + widthSpec = -1; + } else if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) { + widthSpec = mDropDownAnchorView.getWidth(); + } else { + widthSpec = mDropDownWidth; + } + + if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) { + // The call to PopupWindow's update method below can accept -1 for any + // value you do not want to update. + heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT; + if (noInputMethod) { + mPopup.setWindowLayoutMode( + mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ? + ViewGroup.LayoutParams.MATCH_PARENT : 0, 0); + } else { + mPopup.setWindowLayoutMode( + mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ? + ViewGroup.LayoutParams.MATCH_PARENT : 0, + ViewGroup.LayoutParams.MATCH_PARENT); + } + } else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) { + heightSpec = height; + } else { + heightSpec = mDropDownHeight; + } + + mPopup.setOutsideTouchable(true); + + mPopup.update(mDropDownAnchorView, mDropDownHorizontalOffset, + mDropDownVerticalOffset, widthSpec, heightSpec); + } else { + if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) { + widthSpec = ViewGroup.LayoutParams.MATCH_PARENT; + } else { + if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) { + mPopup.setWidth(mDropDownAnchorView.getWidth()); + } else { + mPopup.setWidth(mDropDownWidth); + } + } + + if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) { + heightSpec = ViewGroup.LayoutParams.MATCH_PARENT; + } else { + if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) { + mPopup.setHeight(height); + } else { + mPopup.setHeight(mDropDownHeight); + } + } + + mPopup.setWindowLayoutMode(widthSpec, heightSpec); + //XXX mPopup.setClipToScreenEnabled(true); + + // use outside touchable to dismiss drop down when touching outside of it, so + // only set this if the dropdown is not always visible + mPopup.setOutsideTouchable(true); + mPopup.setTouchInterceptor(mTouchInterceptor); + mPopup.showAsDropDown(mDropDownAnchorView, + mDropDownHorizontalOffset, mDropDownVerticalOffset); + mDropDownList.setSelection(ListView.INVALID_POSITION); + + if (!mModal || mDropDownList.isInTouchMode()) { + clearListSelection(); + } + if (!mModal) { + mHandler.post(mHideSelector); + } + } + } + + public void dismiss() { + mPopup.dismiss(); + if (mPromptView != null) { + final ViewParent parent = mPromptView.getParent(); + if (parent instanceof ViewGroup) { + final ViewGroup group = (ViewGroup) parent; + group.removeView(mPromptView); + } + } + mPopup.setContentView(null); + mDropDownList = null; + mHandler.removeCallbacks(mResizePopupRunnable); + } + + public void setOnDismissListener(PopupWindow.OnDismissListener listener) { + mPopup.setOnDismissListener(listener); + } + + public void setInputMethodMode(int mode) { + mPopup.setInputMethodMode(mode); + } + + public void clearListSelection() { + final DropDownListView list = mDropDownList; + if (list != null) { + // WARNING: Please read the comment where mListSelectionHidden is declared + list.mListSelectionHidden = true; + //XXX list.hideSelector(); + list.requestLayout(); + } + } + + public boolean isShowing() { + return mPopup.isShowing(); + } + + private boolean isInputMethodNotNeeded() { + return mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED; + } + + public ListView getListView() { + return mDropDownList; + } + + private int buildDropDown() { + ViewGroup dropDownView; + int otherHeights = 0; + + if (mDropDownList == null) { + Context context = mContext; + + mDropDownList = new DropDownListView(context, !mModal); + if (mDropDownListHighlight != null) { + mDropDownList.setSelector(mDropDownListHighlight); + } + mDropDownList.setAdapter(mAdapter); + mDropDownList.setOnItemClickListener(mItemClickListener); + mDropDownList.setFocusable(true); + mDropDownList.setFocusableInTouchMode(true); + mDropDownList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + public void onItemSelected(AdapterView parent, View view, + int position, long id) { + + if (position != -1) { + DropDownListView dropDownList = mDropDownList; + + if (dropDownList != null) { + dropDownList.mListSelectionHidden = false; + } + } + } + + public void onNothingSelected(AdapterView parent) { + } + }); + mDropDownList.setOnScrollListener(mScrollListener); + + if (mItemSelectedListener != null) { + mDropDownList.setOnItemSelectedListener(mItemSelectedListener); + } + + dropDownView = mDropDownList; + + View hintView = mPromptView; + if (hintView != null) { + // if an hint has been specified, we accomodate more space for it and + // add a text view in the drop down menu, at the bottom of the list + LinearLayout hintContainer = new LinearLayout(context); + hintContainer.setOrientation(LinearLayout.VERTICAL); + + LinearLayout.LayoutParams hintParams = new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f + ); + + switch (mPromptPosition) { + case POSITION_PROMPT_BELOW: + hintContainer.addView(dropDownView, hintParams); + hintContainer.addView(hintView); + break; + + case POSITION_PROMPT_ABOVE: + hintContainer.addView(hintView); + hintContainer.addView(dropDownView, hintParams); + break; + + default: + break; + } + + // measure the hint's height to find how much more vertical space + // we need to add to the drop down's height + int widthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.AT_MOST); + int heightSpec = MeasureSpec.UNSPECIFIED; + hintView.measure(widthSpec, heightSpec); + + hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams(); + otherHeights = hintView.getMeasuredHeight() + hintParams.topMargin + + hintParams.bottomMargin; + + dropDownView = hintContainer; + } + + mPopup.setContentView(dropDownView); + } else { + dropDownView = (ViewGroup) mPopup.getContentView(); + final View view = mPromptView; + if (view != null) { + LinearLayout.LayoutParams hintParams = + (LinearLayout.LayoutParams) view.getLayoutParams(); + otherHeights = view.getMeasuredHeight() + hintParams.topMargin + + hintParams.bottomMargin; + } + } + + // getMaxAvailableHeight() subtracts the padding, so we put it back + // to get the available height for the whole window + int padding = 0; + Drawable background = mPopup.getBackground(); + if (background != null) { + background.getPadding(mTempRect); + padding = mTempRect.top + mTempRect.bottom; + + // If we don't have an explicit vertical offset, determine one from the window + // background so that content will line up. + if (!mDropDownVerticalOffsetSet) { + mDropDownVerticalOffset = -mTempRect.top; + } + } + + // Max height available on the screen for a popup. + boolean ignoreBottomDecorations = + mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED; + final int maxHeight = /*mPopup.*/getMaxAvailableHeight( + mDropDownAnchorView, mDropDownVerticalOffset, ignoreBottomDecorations); + + if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) { + return maxHeight + padding; + } + + final int listContent = /*mDropDownList.*/measureHeightOfChildren(MeasureSpec.UNSPECIFIED, + 0, -1/*ListView.NO_POSITION*/, maxHeight - otherHeights, -1); + // add padding only if the list has items in it, that way we don't show + // the popup if it is not needed + if (listContent > 0) otherHeights += padding; + + return listContent + otherHeights; + } + + private int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) { + final Rect displayFrame = new Rect(); + anchor.getWindowVisibleDisplayFrame(displayFrame); + + final int[] anchorPos = new int[2]; + anchor.getLocationOnScreen(anchorPos); + + int bottomEdge = displayFrame.bottom; + if (ignoreBottomDecorations) { + Resources res = anchor.getContext().getResources(); + bottomEdge = res.getDisplayMetrics().heightPixels; + } + final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset; + final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset; + + // anchorPos[1] is distance from anchor to top of screen + int returnedHeight = Math.max(distanceToBottom, distanceToTop); + if (mPopup.getBackground() != null) { + mPopup.getBackground().getPadding(mTempRect); + returnedHeight -= mTempRect.top + mTempRect.bottom; + } + + return returnedHeight; + } + + private int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition, + final int maxHeight, int disallowPartialChildPosition) { + + final ListAdapter adapter = mAdapter; + if (adapter == null) { + return mDropDownList.getListPaddingTop() + mDropDownList.getListPaddingBottom(); + } + + // Include the padding of the list + int returnedHeight = mDropDownList.getListPaddingTop() + mDropDownList.getListPaddingBottom(); + final int dividerHeight = ((mDropDownList.getDividerHeight() > 0) && mDropDownList.getDivider() != null) ? mDropDownList.getDividerHeight() : 0; + // The previous height value that was less than maxHeight and contained + // no partial children + int prevHeightWithoutPartialChild = 0; + int i; + View child; + + // mItemCount - 1 since endPosition parameter is inclusive + endPosition = (endPosition == -1/*NO_POSITION*/) ? adapter.getCount() - 1 : endPosition; + + for (i = startPosition; i <= endPosition; ++i) { + child = mAdapter.getView(i, null, mDropDownList); + if (mDropDownList.getCacheColorHint() != 0) { + child.setDrawingCacheBackgroundColor(mDropDownList.getCacheColorHint()); + } + + measureScrapChild(child, i, widthMeasureSpec); + + if (i > 0) { + // Count the divider for all but one child + returnedHeight += dividerHeight; + } + + returnedHeight += child.getMeasuredHeight(); + + if (returnedHeight >= maxHeight) { + // We went over, figure out which height to return. If returnedHeight > maxHeight, + // then the i'th position did not fit completely. + return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1) + && (i > disallowPartialChildPosition) // We've past the min pos + && (prevHeightWithoutPartialChild > 0) // We have a prev height + && (returnedHeight != maxHeight) // i'th child did not fit completely + ? prevHeightWithoutPartialChild + : maxHeight; + } + + if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) { + prevHeightWithoutPartialChild = returnedHeight; + } + } + + // At this point, we went through the range of children, and they each + // completely fit, so return the returnedHeight + return returnedHeight; + } + private void measureScrapChild(View child, int position, int widthMeasureSpec) { + ListView.LayoutParams p = (ListView.LayoutParams) child.getLayoutParams(); + if (p == null) { + p = new ListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT, 0); + child.setLayoutParams(p); + } + //XXX p.viewType = mAdapter.getItemViewType(position); + //XXX p.forceAdd = true; + + int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec, + mDropDownList.getPaddingLeft() + mDropDownList.getPaddingRight(), p.width); + int lpHeight = p.height; + int childHeightSpec; + if (lpHeight > 0) { + childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); + } else { + childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + } + child.measure(childWidthSpec, childHeightSpec); + } + + private static class DropDownListView extends ListView { + /* + * WARNING: This is a workaround for a touch mode issue. + * + * Touch mode is propagated lazily to windows. This causes problems in + * the following scenario: + * - Type something in the AutoCompleteTextView and get some results + * - Move down with the d-pad to select an item in the list + * - Move up with the d-pad until the selection disappears + * - Type more text in the AutoCompleteTextView *using the soft keyboard* + * and get new results; you are now in touch mode + * - The selection comes back on the first item in the list, even though + * the list is supposed to be in touch mode + * + * Using the soft keyboard triggers the touch mode change but that change + * is propagated to our window only after the first list layout, therefore + * after the list attempts to resurrect the selection. + * + * The trick to work around this issue is to pretend the list is in touch + * mode when we know that the selection should not appear, that is when + * we know the user moved the selection away from the list. + * + * This boolean is set to true whenever we explicitly hide the list's + * selection and reset to false whenever we know the user moved the + * selection back to the list. + * + * When this boolean is true, isInTouchMode() returns true, otherwise it + * returns super.isInTouchMode(). + */ + private boolean mListSelectionHidden; + + private boolean mHijackFocus; + + public DropDownListView(Context context, boolean hijackFocus) { + super(context, null, /*com.android.internal.*/R.attr.dropDownListViewStyle); + mHijackFocus = hijackFocus; + // TODO: Add an API to control this + setCacheColorHint(0); // Transparent, since the background drawable could be anything. + } + + //XXX @Override + //View obtainView(int position, boolean[] isScrap) { + // View view = super.obtainView(position, isScrap); + + // if (view instanceof TextView) { + // ((TextView) view).setHorizontallyScrolling(true); + // } + + // return view; + //} + + @Override + public boolean isInTouchMode() { + // WARNING: Please read the comment where mListSelectionHidden is declared + return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode(); + } + + @Override + public boolean hasWindowFocus() { + return mHijackFocus || super.hasWindowFocus(); + } + + @Override + public boolean isFocused() { + return mHijackFocus || super.isFocused(); + } + + @Override + public boolean hasFocus() { + return mHijackFocus || super.hasFocus(); + } + } + + private class PopupDataSetObserver extends DataSetObserver { + @Override + public void onChanged() { + if (isShowing()) { + // Resize the popup to fit new content + show(); + } + } + + @Override + public void onInvalidated() { + dismiss(); + } + } + + private class ListSelectorHider implements Runnable { + public void run() { + clearListSelection(); + } + } + + private class ResizePopupRunnable implements Runnable { + public void run() { + if (mDropDownList != null && mDropDownList.getCount() > mDropDownList.getChildCount() && + mDropDownList.getChildCount() <= mListItemExpandMaximum) { + mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); + show(); + } + } + } + + private class PopupTouchInterceptor implements OnTouchListener { + public boolean onTouch(View v, MotionEvent event) { + final int action = event.getAction(); + final int x = (int) event.getX(); + final int y = (int) event.getY(); + + if (action == MotionEvent.ACTION_DOWN && + mPopup != null && mPopup.isShowing() && + (x >= 0 && x < mPopup.getWidth() && y >= 0 && y < mPopup.getHeight())) { + mHandler.postDelayed(mResizePopupRunnable, EXPAND_LIST_TIMEOUT); + } else if (action == MotionEvent.ACTION_UP) { + mHandler.removeCallbacks(mResizePopupRunnable); + } + return false; + } + } + + private class PopupScrollListener implements ListView.OnScrollListener { + public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, + int totalItemCount) { + + } + + public void onScrollStateChanged(AbsListView view, int scrollState) { + if (scrollState == SCROLL_STATE_TOUCH_SCROLL && + !isInputMethodNotNeeded() && mPopup.getContentView() != null) { + mHandler.removeCallbacks(mResizePopupRunnable); + mResizePopupRunnable.run(); + } + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsProgressBar.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsProgressBar.java new file mode 100644 index 00000000..1c02d4ac --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsProgressBar.java @@ -0,0 +1,1193 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.Shader; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.AnimationDrawable; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ClipDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.RoundRectShape; +import android.graphics.drawable.shapes.Shape; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewDebug; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; +import android.view.animation.Transformation; +import android.widget.RemoteViews.RemoteView; + + +/** + *

+ * Visual indicator of progress in some operation. Displays a bar to the user + * representing how far the operation has progressed; the application can + * change the amount of progress (modifying the length of the bar) as it moves + * forward. There is also a secondary progress displayable on a progress bar + * which is useful for displaying intermediate progress, such as the buffer + * level during a streaming playback progress bar. + *

+ * + *

+ * A progress bar can also be made indeterminate. In indeterminate mode, the + * progress bar shows a cyclic animation without an indication of progress. This mode is used by + * applications when the length of the task is unknown. The indeterminate progress bar can be either + * a spinning wheel or a horizontal bar. + *

+ * + *

The following code example shows how a progress bar can be used from + * a worker thread to update the user interface to notify the user of progress: + *

+ * + *
+ * public class MyActivity extends Activity {
+ *     private static final int PROGRESS = 0x1;
+ *
+ *     private ProgressBar mProgress;
+ *     private int mProgressStatus = 0;
+ *
+ *     private Handler mHandler = new Handler();
+ *
+ *     protected void onCreate(Bundle icicle) {
+ *         super.onCreate(icicle);
+ *
+ *         setContentView(R.layout.progressbar_activity);
+ *
+ *         mProgress = (ProgressBar) findViewById(R.id.progress_bar);
+ *
+ *         // Start lengthy operation in a background thread
+ *         new Thread(new Runnable() {
+ *             public void run() {
+ *                 while (mProgressStatus < 100) {
+ *                     mProgressStatus = doWork();
+ *
+ *                     // Update the progress bar
+ *                     mHandler.post(new Runnable() {
+ *                         public void run() {
+ *                             mProgress.setProgress(mProgressStatus);
+ *                         }
+ *                     });
+ *                 }
+ *             }
+ *         }).start();
+ *     }
+ * }
+ * + *

To add a progress bar to a layout file, you can use the {@code <ProgressBar>} element. + * By default, the progress bar is a spinning wheel (an indeterminate indicator). To change to a + * horizontal progress bar, apply the {@link android.R.style#Widget_ProgressBar_Horizontal + * Widget.ProgressBar.Horizontal} style, like so:

+ * + *
+ * <ProgressBar
+ *     style="@android:style/Widget.ProgressBar.Horizontal"
+ *     ... />
+ * + *

If you will use the progress bar to show real progress, you must use the horizontal bar. You + * can then increment the progress with {@link #incrementProgressBy incrementProgressBy()} or + * {@link #setProgress setProgress()}. By default, the progress bar is full when it reaches 100. If + * necessary, you can adjust the maximum value (the value for a full bar) using the {@link + * android.R.styleable#ProgressBar_max android:max} attribute. Other attributes available are listed + * below.

+ * + *

Another common style to apply to the progress bar is {@link + * android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}, which shows a smaller + * version of the spinning wheel—useful when waiting for content to load. + * For example, you can insert this kind of progress bar into your default layout for + * a view that will be populated by some content fetched from the Internet—the spinning wheel + * appears immediately and when your application receives the content, it replaces the progress bar + * with the loaded content. For example:

+ * + *
+ * <LinearLayout
+ *     android:orientation="horizontal"
+ *     ... >
+ *     <ProgressBar
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         style="@android:style/Widget.ProgressBar.Small"
+ *         android:layout_marginRight="5dp" />
+ *     <TextView
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:text="@string/loading" />
+ * </LinearLayout>
+ * + *

Other progress bar styles provided by the system include:

+ *
    + *
  • {@link android.R.style#Widget_ProgressBar_Horizontal Widget.ProgressBar.Horizontal}
  • + *
  • {@link android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}
  • + *
  • {@link android.R.style#Widget_ProgressBar_Large Widget.ProgressBar.Large}
  • + *
  • {@link android.R.style#Widget_ProgressBar_Inverse Widget.ProgressBar.Inverse}
  • + *
  • {@link android.R.style#Widget_ProgressBar_Small_Inverse + * Widget.ProgressBar.Small.Inverse}
  • + *
  • {@link android.R.style#Widget_ProgressBar_Large_Inverse + * Widget.ProgressBar.Large.Inverse}
  • + *
+ *

The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary + * if your application uses a light colored theme (a white background).

+ * + *

XML attributes + *

+ * See {@link android.R.styleable#ProgressBar ProgressBar Attributes}, + * {@link android.R.styleable#View View Attributes} + *

+ * + * @attr ref android.R.styleable#ProgressBar_animationResolution + * @attr ref android.R.styleable#ProgressBar_indeterminate + * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior + * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable + * @attr ref android.R.styleable#ProgressBar_indeterminateDuration + * @attr ref android.R.styleable#ProgressBar_indeterminateOnly + * @attr ref android.R.styleable#ProgressBar_interpolator + * @attr ref android.R.styleable#ProgressBar_max + * @attr ref android.R.styleable#ProgressBar_maxHeight + * @attr ref android.R.styleable#ProgressBar_maxWidth + * @attr ref android.R.styleable#ProgressBar_minHeight + * @attr ref android.R.styleable#ProgressBar_minWidth + * @attr ref android.R.styleable#ProgressBar_progress + * @attr ref android.R.styleable#ProgressBar_progressDrawable + * @attr ref android.R.styleable#ProgressBar_secondaryProgress + */ +@RemoteView +public class IcsProgressBar extends View { + private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; + private static final int MAX_LEVEL = 10000; + private static final int ANIMATION_RESOLUTION = 200; + private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200; + + private static final int[] ProgressBar = new int[] { + android.R.attr.maxWidth, + android.R.attr.maxHeight, + android.R.attr.max, + android.R.attr.progress, + android.R.attr.secondaryProgress, + android.R.attr.indeterminate, + android.R.attr.indeterminateOnly, + android.R.attr.indeterminateDrawable, + android.R.attr.progressDrawable, + android.R.attr.indeterminateDuration, + android.R.attr.indeterminateBehavior, + android.R.attr.minWidth, + android.R.attr.minHeight, + android.R.attr.interpolator, + android.R.attr.animationResolution, + }; + private static final int ProgressBar_maxWidth = 0; + private static final int ProgressBar_maxHeight = 1; + private static final int ProgressBar_max = 2; + private static final int ProgressBar_progress = 3; + private static final int ProgressBar_secondaryProgress = 4; + private static final int ProgressBar_indeterminate = 5; + private static final int ProgressBar_indeterminateOnly = 6; + private static final int ProgressBar_indeterminateDrawable = 7; + private static final int ProgressBar_progressDrawable = 8; + private static final int ProgressBar_indeterminateDuration = 9; + private static final int ProgressBar_indeterminateBehavior = 10; + private static final int ProgressBar_minWidth = 11; + private static final int ProgressBar_minHeight = 12; + private static final int ProgressBar_interpolator = 13; + private static final int ProgressBar_animationResolution = 14; + + int mMinWidth; + int mMaxWidth; + int mMinHeight; + int mMaxHeight; + + private int mProgress; + private int mSecondaryProgress; + private int mMax; + + private int mBehavior; + private int mDuration; + private boolean mIndeterminate; + private boolean mOnlyIndeterminate; + private Transformation mTransformation; + private AlphaAnimation mAnimation; + private Drawable mIndeterminateDrawable; + private int mIndeterminateRealLeft; + private int mIndeterminateRealTop; + private Drawable mProgressDrawable; + private Drawable mCurrentDrawable; + Bitmap mSampleTile; + private boolean mNoInvalidate; + private Interpolator mInterpolator; + private RefreshProgressRunnable mRefreshProgressRunnable; + private long mUiThreadId; + private boolean mShouldStartAnimationDrawable; + private long mLastDrawTime; + + private boolean mInDrawing; + + private int mAnimationResolution; + + private AccessibilityManager mAccessibilityManager; + private AccessibilityEventSender mAccessibilityEventSender; + + /** + * Create a new progress bar with range 0...100 and initial progress of 0. + * @param context the application environment + */ + public IcsProgressBar(Context context) { + this(context, null); + } + + public IcsProgressBar(Context context, AttributeSet attrs) { + this(context, attrs, android.R.attr.progressBarStyle); + } + + public IcsProgressBar(Context context, AttributeSet attrs, int defStyle) { + this(context, attrs, defStyle, 0); + } + + /** + * @hide + */ + public IcsProgressBar(Context context, AttributeSet attrs, int defStyle, int styleRes) { + super(context, attrs, defStyle); + mUiThreadId = Thread.currentThread().getId(); + initProgressBar(); + + TypedArray a = + context.obtainStyledAttributes(attrs, /*R.styleable.*/ProgressBar, defStyle, styleRes); + + mNoInvalidate = true; + + Drawable drawable = a.getDrawable(/*R.styleable.*/ProgressBar_progressDrawable); + if (drawable != null) { + drawable = tileify(drawable, false); + // Calling this method can set mMaxHeight, make sure the corresponding + // XML attribute for mMaxHeight is read after calling this method + setProgressDrawable(drawable); + } + + + mDuration = a.getInt(/*R.styleable.*/ProgressBar_indeterminateDuration, mDuration); + + mMinWidth = a.getDimensionPixelSize(/*R.styleable.*/ProgressBar_minWidth, mMinWidth); + mMaxWidth = a.getDimensionPixelSize(/*R.styleable.*/ProgressBar_maxWidth, mMaxWidth); + mMinHeight = a.getDimensionPixelSize(/*R.styleable.*/ProgressBar_minHeight, mMinHeight); + mMaxHeight = a.getDimensionPixelSize(/*R.styleable.*/ProgressBar_maxHeight, mMaxHeight); + + mBehavior = a.getInt(/*R.styleable.*/ProgressBar_indeterminateBehavior, mBehavior); + + final int resID = a.getResourceId( + /*com.android.internal.R.styleable.*/ProgressBar_interpolator, + android.R.anim.linear_interpolator); // default to linear interpolator + if (resID > 0) { + setInterpolator(context, resID); + } + + setMax(a.getInt(/*R.styleable.*/ProgressBar_max, mMax)); + + setProgress(a.getInt(/*R.styleable.*/ProgressBar_progress, mProgress)); + + setSecondaryProgress( + a.getInt(/*R.styleable.*/ProgressBar_secondaryProgress, mSecondaryProgress)); + + drawable = a.getDrawable(/*R.styleable.*/ProgressBar_indeterminateDrawable); + if (drawable != null) { + drawable = tileifyIndeterminate(drawable); + setIndeterminateDrawable(drawable); + } + + mOnlyIndeterminate = a.getBoolean( + /*R.styleable.*/ProgressBar_indeterminateOnly, mOnlyIndeterminate); + + mNoInvalidate = false; + + setIndeterminate(mOnlyIndeterminate || a.getBoolean( + /*R.styleable.*/ProgressBar_indeterminate, mIndeterminate)); + + mAnimationResolution = a.getInteger(/*R.styleable.*/ProgressBar_animationResolution, + ANIMATION_RESOLUTION); + + a.recycle(); + + mAccessibilityManager = (AccessibilityManager)context.getSystemService(Context.ACCESSIBILITY_SERVICE); + } + + /** + * Converts a drawable to a tiled version of itself. It will recursively + * traverse layer and state list drawables. + */ + private Drawable tileify(Drawable drawable, boolean clip) { + + if (drawable instanceof LayerDrawable) { + LayerDrawable background = (LayerDrawable) drawable; + final int N = background.getNumberOfLayers(); + Drawable[] outDrawables = new Drawable[N]; + + for (int i = 0; i < N; i++) { + int id = background.getId(i); + outDrawables[i] = tileify(background.getDrawable(i), + (id == android.R.id.progress || id == android.R.id.secondaryProgress)); + } + + LayerDrawable newBg = new LayerDrawable(outDrawables); + + for (int i = 0; i < N; i++) { + newBg.setId(i, background.getId(i)); + } + + return newBg; + + }/* else if (drawable instanceof StateListDrawable) { + StateListDrawable in = (StateListDrawable) drawable; + StateListDrawable out = new StateListDrawable(); + int numStates = in.getStateCount(); + for (int i = 0; i < numStates; i++) { + out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip)); + } + return out; + + }*/ else if (drawable instanceof BitmapDrawable) { + final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap(); + if (mSampleTile == null) { + mSampleTile = tileBitmap; + } + + final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape()); + + final BitmapShader bitmapShader = new BitmapShader(tileBitmap, + Shader.TileMode.REPEAT, Shader.TileMode.CLAMP); + shapeDrawable.getPaint().setShader(bitmapShader); + + return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT, + ClipDrawable.HORIZONTAL) : shapeDrawable; + } + + return drawable; + } + + Shape getDrawableShape() { + final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 }; + return new RoundRectShape(roundedCorners, null, null); + } + + /** + * Convert a AnimationDrawable for use as a barberpole animation. + * Each frame of the animation is wrapped in a ClipDrawable and + * given a tiling BitmapShader. + */ + private Drawable tileifyIndeterminate(Drawable drawable) { + if (drawable instanceof AnimationDrawable) { + AnimationDrawable background = (AnimationDrawable) drawable; + final int N = background.getNumberOfFrames(); + AnimationDrawable newBg = new AnimationDrawable(); + newBg.setOneShot(background.isOneShot()); + + for (int i = 0; i < N; i++) { + Drawable frame = tileify(background.getFrame(i), true); + frame.setLevel(10000); + newBg.addFrame(frame, background.getDuration(i)); + } + newBg.setLevel(10000); + drawable = newBg; + } + return drawable; + } + + /** + *

+ * Initialize the progress bar's default values: + *

+ *
    + *
  • progress = 0
  • + *
  • max = 100
  • + *
  • animation duration = 4000 ms
  • + *
  • indeterminate = false
  • + *
  • behavior = repeat
  • + *
+ */ + private void initProgressBar() { + mMax = 100; + mProgress = 0; + mSecondaryProgress = 0; + mIndeterminate = false; + mOnlyIndeterminate = false; + mDuration = 4000; + mBehavior = AlphaAnimation.RESTART; + mMinWidth = 24; + mMaxWidth = 48; + mMinHeight = 24; + mMaxHeight = 48; + } + + /** + *

Indicate whether this progress bar is in indeterminate mode.

+ * + * @return true if the progress bar is in indeterminate mode + */ + @ViewDebug.ExportedProperty(category = "progress") + public synchronized boolean isIndeterminate() { + return mIndeterminate; + } + + /** + *

Change the indeterminate mode for this progress bar. In indeterminate + * mode, the progress is ignored and the progress bar shows an infinite + * animation instead.

+ * + * If this progress bar's style only supports indeterminate mode (such as the circular + * progress bars), then this will be ignored. + * + * @param indeterminate true to enable the indeterminate mode + */ + public synchronized void setIndeterminate(boolean indeterminate) { + if ((!mOnlyIndeterminate || !mIndeterminate) && indeterminate != mIndeterminate) { + mIndeterminate = indeterminate; + + if (indeterminate) { + // swap between indeterminate and regular backgrounds + mCurrentDrawable = mIndeterminateDrawable; + startAnimation(); + } else { + mCurrentDrawable = mProgressDrawable; + stopAnimation(); + } + } + } + + /** + *

Get the drawable used to draw the progress bar in + * indeterminate mode.

+ * + * @return a {@link android.graphics.drawable.Drawable} instance + * + * @see #setIndeterminateDrawable(android.graphics.drawable.Drawable) + * @see #setIndeterminate(boolean) + */ + public Drawable getIndeterminateDrawable() { + return mIndeterminateDrawable; + } + + /** + *

Define the drawable used to draw the progress bar in + * indeterminate mode.

+ * + * @param d the new drawable + * + * @see #getIndeterminateDrawable() + * @see #setIndeterminate(boolean) + */ + public void setIndeterminateDrawable(Drawable d) { + if (d != null) { + d.setCallback(this); + } + mIndeterminateDrawable = d; + if (mIndeterminate) { + mCurrentDrawable = d; + postInvalidate(); + } + } + + /** + *

Get the drawable used to draw the progress bar in + * progress mode.

+ * + * @return a {@link android.graphics.drawable.Drawable} instance + * + * @see #setProgressDrawable(android.graphics.drawable.Drawable) + * @see #setIndeterminate(boolean) + */ + public Drawable getProgressDrawable() { + return mProgressDrawable; + } + + /** + *

Define the drawable used to draw the progress bar in + * progress mode.

+ * + * @param d the new drawable + * + * @see #getProgressDrawable() + * @see #setIndeterminate(boolean) + */ + public void setProgressDrawable(Drawable d) { + boolean needUpdate; + if (mProgressDrawable != null && d != mProgressDrawable) { + mProgressDrawable.setCallback(null); + needUpdate = true; + } else { + needUpdate = false; + } + + if (d != null) { + d.setCallback(this); + + // Make sure the ProgressBar is always tall enough + int drawableHeight = d.getMinimumHeight(); + if (mMaxHeight < drawableHeight) { + mMaxHeight = drawableHeight; + requestLayout(); + } + } + mProgressDrawable = d; + if (!mIndeterminate) { + mCurrentDrawable = d; + postInvalidate(); + } + + if (needUpdate) { + updateDrawableBounds(getWidth(), getHeight()); + updateDrawableState(); + doRefreshProgress(android.R.id.progress, mProgress, false, false); + doRefreshProgress(android.R.id.secondaryProgress, mSecondaryProgress, false, false); + } + } + + /** + * @return The drawable currently used to draw the progress bar + */ + Drawable getCurrentDrawable() { + return mCurrentDrawable; + } + + @Override + protected boolean verifyDrawable(Drawable who) { + return who == mProgressDrawable || who == mIndeterminateDrawable + || super.verifyDrawable(who); + } + + @Override + public void jumpDrawablesToCurrentState() { + super.jumpDrawablesToCurrentState(); + if (mProgressDrawable != null) mProgressDrawable.jumpToCurrentState(); + if (mIndeterminateDrawable != null) mIndeterminateDrawable.jumpToCurrentState(); + } + + @Override + public void postInvalidate() { + if (!mNoInvalidate) { + super.postInvalidate(); + } + } + + private class RefreshProgressRunnable implements Runnable { + + private int mId; + private int mProgress; + private boolean mFromUser; + + RefreshProgressRunnable(int id, int progress, boolean fromUser) { + mId = id; + mProgress = progress; + mFromUser = fromUser; + } + + public void run() { + doRefreshProgress(mId, mProgress, mFromUser, true); + // Put ourselves back in the cache when we are done + mRefreshProgressRunnable = this; + } + + public void setup(int id, int progress, boolean fromUser) { + mId = id; + mProgress = progress; + mFromUser = fromUser; + } + + } + + private synchronized void doRefreshProgress(int id, int progress, boolean fromUser, + boolean callBackToApp) { + float scale = mMax > 0 ? (float) progress / (float) mMax : 0; + final Drawable d = mCurrentDrawable; + if (d != null) { + Drawable progressDrawable = null; + + if (d instanceof LayerDrawable) { + progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id); + } + + final int level = (int) (scale * MAX_LEVEL); + (progressDrawable != null ? progressDrawable : d).setLevel(level); + } else { + invalidate(); + } + + if (callBackToApp && id == android.R.id.progress) { + onProgressRefresh(scale, fromUser); + } + } + + void onProgressRefresh(float scale, boolean fromUser) { + if (mAccessibilityManager.isEnabled()) { + scheduleAccessibilityEventSender(); + } + } + + private synchronized void refreshProgress(int id, int progress, boolean fromUser) { + if (mUiThreadId == Thread.currentThread().getId()) { + doRefreshProgress(id, progress, fromUser, true); + } else { + RefreshProgressRunnable r; + if (mRefreshProgressRunnable != null) { + // Use cached RefreshProgressRunnable if available + r = mRefreshProgressRunnable; + // Uncache it + mRefreshProgressRunnable = null; + r.setup(id, progress, fromUser); + } else { + // Make a new one + r = new RefreshProgressRunnable(id, progress, fromUser); + } + post(r); + } + } + + /** + *

Set the current progress to the specified value. Does not do anything + * if the progress bar is in indeterminate mode.

+ * + * @param progress the new progress, between 0 and {@link #getMax()} + * + * @see #setIndeterminate(boolean) + * @see #isIndeterminate() + * @see #getProgress() + * @see #incrementProgressBy(int) + */ + public synchronized void setProgress(int progress) { + setProgress(progress, false); + } + + synchronized void setProgress(int progress, boolean fromUser) { + if (mIndeterminate) { + return; + } + + if (progress < 0) { + progress = 0; + } + + if (progress > mMax) { + progress = mMax; + } + + if (progress != mProgress) { + mProgress = progress; + refreshProgress(android.R.id.progress, mProgress, fromUser); + } + } + + /** + *

+ * Set the current secondary progress to the specified value. Does not do + * anything if the progress bar is in indeterminate mode. + *

+ * + * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()} + * @see #setIndeterminate(boolean) + * @see #isIndeterminate() + * @see #getSecondaryProgress() + * @see #incrementSecondaryProgressBy(int) + */ + public synchronized void setSecondaryProgress(int secondaryProgress) { + if (mIndeterminate) { + return; + } + + if (secondaryProgress < 0) { + secondaryProgress = 0; + } + + if (secondaryProgress > mMax) { + secondaryProgress = mMax; + } + + if (secondaryProgress != mSecondaryProgress) { + mSecondaryProgress = secondaryProgress; + refreshProgress(android.R.id.secondaryProgress, mSecondaryProgress, false); + } + } + + /** + *

Get the progress bar's current level of progress. Return 0 when the + * progress bar is in indeterminate mode.

+ * + * @return the current progress, between 0 and {@link #getMax()} + * + * @see #setIndeterminate(boolean) + * @see #isIndeterminate() + * @see #setProgress(int) + * @see #setMax(int) + * @see #getMax() + */ + @ViewDebug.ExportedProperty(category = "progress") + public synchronized int getProgress() { + return mIndeterminate ? 0 : mProgress; + } + + /** + *

Get the progress bar's current level of secondary progress. Return 0 when the + * progress bar is in indeterminate mode.

+ * + * @return the current secondary progress, between 0 and {@link #getMax()} + * + * @see #setIndeterminate(boolean) + * @see #isIndeterminate() + * @see #setSecondaryProgress(int) + * @see #setMax(int) + * @see #getMax() + */ + @ViewDebug.ExportedProperty(category = "progress") + public synchronized int getSecondaryProgress() { + return mIndeterminate ? 0 : mSecondaryProgress; + } + + /** + *

Return the upper limit of this progress bar's range.

+ * + * @return a positive integer + * + * @see #setMax(int) + * @see #getProgress() + * @see #getSecondaryProgress() + */ + @ViewDebug.ExportedProperty(category = "progress") + public synchronized int getMax() { + return mMax; + } + + /** + *

Set the range of the progress bar to 0...max.

+ * + * @param max the upper range of this progress bar + * + * @see #getMax() + * @see #setProgress(int) + * @see #setSecondaryProgress(int) + */ + public synchronized void setMax(int max) { + if (max < 0) { + max = 0; + } + if (max != mMax) { + mMax = max; + postInvalidate(); + + if (mProgress > max) { + mProgress = max; + } + refreshProgress(android.R.id.progress, mProgress, false); + } + } + + /** + *

Increase the progress bar's progress by the specified amount.

+ * + * @param diff the amount by which the progress must be increased + * + * @see #setProgress(int) + */ + public synchronized final void incrementProgressBy(int diff) { + setProgress(mProgress + diff); + } + + /** + *

Increase the progress bar's secondary progress by the specified amount.

+ * + * @param diff the amount by which the secondary progress must be increased + * + * @see #setSecondaryProgress(int) + */ + public synchronized final void incrementSecondaryProgressBy(int diff) { + setSecondaryProgress(mSecondaryProgress + diff); + } + + /** + *

Start the indeterminate progress animation.

+ */ + void startAnimation() { + if (getVisibility() != VISIBLE) { + return; + } + + if (mIndeterminateDrawable instanceof Animatable) { + mShouldStartAnimationDrawable = true; + mAnimation = null; + } else { + if (mInterpolator == null) { + mInterpolator = new LinearInterpolator(); + } + + mTransformation = new Transformation(); + mAnimation = new AlphaAnimation(0.0f, 1.0f); + mAnimation.setRepeatMode(mBehavior); + mAnimation.setRepeatCount(Animation.INFINITE); + mAnimation.setDuration(mDuration); + mAnimation.setInterpolator(mInterpolator); + mAnimation.setStartTime(Animation.START_ON_FIRST_FRAME); + } + postInvalidate(); + } + + /** + *

Stop the indeterminate progress animation.

+ */ + void stopAnimation() { + mAnimation = null; + mTransformation = null; + if (mIndeterminateDrawable instanceof Animatable) { + ((Animatable) mIndeterminateDrawable).stop(); + mShouldStartAnimationDrawable = false; + } + postInvalidate(); + } + + /** + * Sets the acceleration curve for the indeterminate animation. + * The interpolator is loaded as a resource from the specified context. + * + * @param context The application environment + * @param resID The resource identifier of the interpolator to load + */ + public void setInterpolator(Context context, int resID) { + setInterpolator(AnimationUtils.loadInterpolator(context, resID)); + } + + /** + * Sets the acceleration curve for the indeterminate animation. + * Defaults to a linear interpolation. + * + * @param interpolator The interpolator which defines the acceleration curve + */ + public void setInterpolator(Interpolator interpolator) { + mInterpolator = interpolator; + } + + /** + * Gets the acceleration curve type for the indeterminate animation. + * + * @return the {@link Interpolator} associated to this animation + */ + public Interpolator getInterpolator() { + return mInterpolator; + } + + @Override + public void setVisibility(int v) { + if (getVisibility() != v) { + super.setVisibility(v); + + if (mIndeterminate) { + // let's be nice with the UI thread + if (v == GONE || v == INVISIBLE) { + stopAnimation(); + } else { + startAnimation(); + } + } + } + } + + @Override + protected void onVisibilityChanged(View changedView, int visibility) { + super.onVisibilityChanged(changedView, visibility); + + if (mIndeterminate) { + // let's be nice with the UI thread + if (visibility == GONE || visibility == INVISIBLE) { + stopAnimation(); + } else { + startAnimation(); + } + } + } + + @Override + public void invalidateDrawable(Drawable dr) { + if (!mInDrawing) { + if (verifyDrawable(dr)) { + final Rect dirty = dr.getBounds(); + final int scrollX = getScrollX() + getPaddingLeft(); + final int scrollY = getScrollY() + getPaddingTop(); + + invalidate(dirty.left + scrollX, dirty.top + scrollY, + dirty.right + scrollX, dirty.bottom + scrollY); + } else { + super.invalidateDrawable(dr); + } + } + } + + /** + * @hide + * + @Override + public int getResolvedLayoutDirection(Drawable who) { + return (who == mProgressDrawable || who == mIndeterminateDrawable) ? + getResolvedLayoutDirection() : super.getResolvedLayoutDirection(who); + } + */ + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + updateDrawableBounds(w, h); + } + + private void updateDrawableBounds(int w, int h) { + // onDraw will translate the canvas so we draw starting at 0,0 + int right = w - getPaddingRight() - getPaddingLeft(); + int bottom = h - getPaddingBottom() - getPaddingTop(); + int top = 0; + int left = 0; + + if (mIndeterminateDrawable != null) { + // Aspect ratio logic does not apply to AnimationDrawables + if (mOnlyIndeterminate && !(mIndeterminateDrawable instanceof AnimationDrawable)) { + // Maintain aspect ratio. Certain kinds of animated drawables + // get very confused otherwise. + final int intrinsicWidth = mIndeterminateDrawable.getIntrinsicWidth(); + final int intrinsicHeight = mIndeterminateDrawable.getIntrinsicHeight(); + final float intrinsicAspect = (float) intrinsicWidth / intrinsicHeight; + final float boundAspect = (float) w / h; + if (intrinsicAspect != boundAspect) { + if (boundAspect > intrinsicAspect) { + // New width is larger. Make it smaller to match height. + final int width = (int) (h * intrinsicAspect); + left = (w - width) / 2; + right = left + width; + } else { + // New height is larger. Make it smaller to match width. + final int height = (int) (w * (1 / intrinsicAspect)); + top = (h - height) / 2; + bottom = top + height; + } + } + } + mIndeterminateDrawable.setBounds(0, 0, right - left, bottom - top); + mIndeterminateRealLeft = left; + mIndeterminateRealTop = top; + } + + if (mProgressDrawable != null) { + mProgressDrawable.setBounds(0, 0, right, bottom); + } + } + + @Override + protected synchronized void onDraw(Canvas canvas) { + super.onDraw(canvas); + + Drawable d = mCurrentDrawable; + if (d != null) { + // Translate canvas so a indeterminate circular progress bar with padding + // rotates properly in its animation + canvas.save(); + canvas.translate(getPaddingLeft() + mIndeterminateRealLeft, getPaddingTop() + mIndeterminateRealTop); + long time = getDrawingTime(); + if (mAnimation != null) { + mAnimation.getTransformation(time, mTransformation); + float scale = mTransformation.getAlpha(); + try { + mInDrawing = true; + d.setLevel((int) (scale * MAX_LEVEL)); + } finally { + mInDrawing = false; + } + if (SystemClock.uptimeMillis() - mLastDrawTime >= mAnimationResolution) { + mLastDrawTime = SystemClock.uptimeMillis(); + postInvalidateDelayed(mAnimationResolution); + } + } + d.draw(canvas); + canvas.restore(); + if (mShouldStartAnimationDrawable && d instanceof Animatable) { + ((Animatable) d).start(); + mShouldStartAnimationDrawable = false; + } + } + } + + @Override + protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + Drawable d = mCurrentDrawable; + + int dw = 0; + int dh = 0; + if (d != null) { + dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth())); + dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight())); + } + updateDrawableState(); + dw += getPaddingLeft() + getPaddingRight(); + dh += getPaddingTop() + getPaddingBottom(); + + if (IS_HONEYCOMB) { + setMeasuredDimension(View.resolveSizeAndState(dw, widthMeasureSpec, 0), + View.resolveSizeAndState(dh, heightMeasureSpec, 0)); + } else { + setMeasuredDimension(View.resolveSize(dw, widthMeasureSpec), + View.resolveSize(dh, heightMeasureSpec)); + } + } + + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + updateDrawableState(); + } + + private void updateDrawableState() { + int[] state = getDrawableState(); + + if (mProgressDrawable != null && mProgressDrawable.isStateful()) { + mProgressDrawable.setState(state); + } + + if (mIndeterminateDrawable != null && mIndeterminateDrawable.isStateful()) { + mIndeterminateDrawable.setState(state); + } + } + + static class SavedState extends BaseSavedState { + int progress; + int secondaryProgress; + + /** + * Constructor called from {@link IcsProgressBar#onSaveInstanceState()} + */ + SavedState(Parcelable superState) { + super(superState); + } + + /** + * Constructor called from {@link #CREATOR} + */ + private SavedState(Parcel in) { + super(in); + progress = in.readInt(); + secondaryProgress = in.readInt(); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(progress); + out.writeInt(secondaryProgress); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + @Override + public Parcelable onSaveInstanceState() { + // Force our ancestor class to save its state + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + + ss.progress = mProgress; + ss.secondaryProgress = mSecondaryProgress; + + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + + setProgress(ss.progress); + setSecondaryProgress(ss.secondaryProgress); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (mIndeterminate) { + startAnimation(); + } + } + + @Override + protected void onDetachedFromWindow() { + if (mIndeterminate) { + stopAnimation(); + } + if(mRefreshProgressRunnable != null) { + removeCallbacks(mRefreshProgressRunnable); + } + if (mAccessibilityEventSender != null) { + removeCallbacks(mAccessibilityEventSender); + } + // This should come after stopAnimation(), otherwise an invalidate message remains in the + // queue, which can prevent the entire view hierarchy from being GC'ed during a rotation + super.onDetachedFromWindow(); + } + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + event.setItemCount(mMax); + event.setCurrentItemIndex(mProgress); + } + + /** + * Schedule a command for sending an accessibility event. + *
+ * Note: A command is used to ensure that accessibility events + * are sent at most one in a given time frame to save + * system resources while the progress changes quickly. + */ + private void scheduleAccessibilityEventSender() { + if (mAccessibilityEventSender == null) { + mAccessibilityEventSender = new AccessibilityEventSender(); + } else { + removeCallbacks(mAccessibilityEventSender); + } + postDelayed(mAccessibilityEventSender, TIMEOUT_SEND_ACCESSIBILITY_EVENT); + } + + /** + * Command for sending an accessibility event. + */ + private class AccessibilityEventSender implements Runnable { + public void run() { + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsSpinner.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsSpinner.java new file mode 100644 index 00000000..038d1e03 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsSpinner.java @@ -0,0 +1,703 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.internal.widget; + +import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; +import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import com.actionbarsherlock.R; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.res.TypedArray; +import android.database.DataSetObserver; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.PopupWindow; +import android.widget.SpinnerAdapter; + + +/** + * A view that displays one child at a time and lets the user pick among them. + * The items in the Spinner come from the {@link Adapter} associated with + * this view. + * + *

See the Spinner + * tutorial.

+ * + * @attr ref android.R.styleable#Spinner_prompt + */ +public class IcsSpinner extends IcsAbsSpinner implements OnClickListener { + //private static final String TAG = "Spinner"; + + // Only measure this many items to get a decent max width. + private static final int MAX_ITEMS_MEASURED = 15; + + /** + * Use a dialog window for selecting spinner options. + */ + //public static final int MODE_DIALOG = 0; + + /** + * Use a dropdown anchored to the Spinner for selecting spinner options. + */ + public static final int MODE_DROPDOWN = 1; + + /** + * Use the theme-supplied value to select the dropdown mode. + */ + //private static final int MODE_THEME = -1; + + private SpinnerPopup mPopup; + private DropDownAdapter mTempAdapter; + int mDropDownWidth; + + private int mGravity; + private boolean mDisableChildrenWhenDisabled; + + private Rect mTempRect = new Rect(); + + public IcsSpinner(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.actionDropDownStyle); + } + + /** + * Construct a new spinner with the given context's theme, the supplied attribute set, + * and default style. + * + * @param context The Context the view is running in, through which it can + * access the current theme, resources, etc. + * @param attrs The attributes of the XML tag that is inflating the view. + * @param defStyle The default style to apply to this view. If 0, no style + * will be applied (beyond what is included in the theme). This may + * either be an attribute resource, whose value will be retrieved + * from the current theme, or an explicit style resource. + */ + public IcsSpinner(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.SherlockSpinner, defStyle, 0); + + + DropdownPopup popup = new DropdownPopup(context, attrs, defStyle); + + mDropDownWidth = a.getLayoutDimension( + R.styleable.SherlockSpinner_android_dropDownWidth, + ViewGroup.LayoutParams.WRAP_CONTENT); + popup.setBackgroundDrawable(a.getDrawable( + R.styleable.SherlockSpinner_android_popupBackground)); + final int verticalOffset = a.getDimensionPixelOffset( + R.styleable.SherlockSpinner_android_dropDownVerticalOffset, 0); + if (verticalOffset != 0) { + popup.setVerticalOffset(verticalOffset); + } + + final int horizontalOffset = a.getDimensionPixelOffset( + R.styleable.SherlockSpinner_android_dropDownHorizontalOffset, 0); + if (horizontalOffset != 0) { + popup.setHorizontalOffset(horizontalOffset); + } + + mPopup = popup; + + mGravity = a.getInt(R.styleable.SherlockSpinner_android_gravity, Gravity.CENTER); + + mPopup.setPromptText(a.getString(R.styleable.SherlockSpinner_android_prompt)); + + mDisableChildrenWhenDisabled = true; + + a.recycle(); + + // Base constructor can call setAdapter before we initialize mPopup. + // Finish setting things up if this happened. + if (mTempAdapter != null) { + mPopup.setAdapter(mTempAdapter); + mTempAdapter = null; + } + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + if (mDisableChildrenWhenDisabled) { + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + getChildAt(i).setEnabled(enabled); + } + } + } + + /** + * Describes how the selected item view is positioned. Currently only the horizontal component + * is used. The default is determined by the current theme. + * + * @param gravity See {@link android.view.Gravity} + * + * @attr ref android.R.styleable#Spinner_gravity + */ + public void setGravity(int gravity) { + if (mGravity != gravity) { + if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) { + gravity |= Gravity.LEFT; + } + mGravity = gravity; + requestLayout(); + } + } + + @Override + public void setAdapter(SpinnerAdapter adapter) { + super.setAdapter(adapter); + + if (mPopup != null) { + mPopup.setAdapter(new DropDownAdapter(adapter)); + } else { + mTempAdapter = new DropDownAdapter(adapter); + } + } + + @Override + public int getBaseline() { + View child = null; + + if (getChildCount() > 0) { + child = getChildAt(0); + } else if (mAdapter != null && mAdapter.getCount() > 0) { + child = makeAndAddView(0); + mRecycler.put(0, child); + removeAllViewsInLayout(); + } + + if (child != null) { + final int childBaseline = child.getBaseline(); + return childBaseline >= 0 ? child.getTop() + childBaseline : -1; + } else { + return -1; + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + if (mPopup != null && mPopup.isShowing()) { + mPopup.dismiss(); + } + } + + /** + *

A spinner does not support item click events. Calling this method + * will raise an exception.

+ * + * @param l this listener will be ignored + */ + @Override + public void setOnItemClickListener(OnItemClickListener l) { + throw new RuntimeException("setOnItemClickListener cannot be used with a spinner."); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (mPopup != null && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) { + final int measuredWidth = getMeasuredWidth(); + setMeasuredDimension(Math.min(Math.max(measuredWidth, + measureContentWidth(getAdapter(), getBackground())), + MeasureSpec.getSize(widthMeasureSpec)), + getMeasuredHeight()); + } + } + + /** + * @see android.view.View#onLayout(boolean,int,int,int,int) + * + * Creates and positions all views + * + */ + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + mInLayout = true; + layout(0, false); + mInLayout = false; + } + + /** + * Creates and positions all views for this Spinner. + * + * @param delta Change in the selected position. +1 moves selection is moving to the right, + * so views are scrolling to the left. -1 means selection is moving to the left. + */ + @Override + void layout(int delta, boolean animate) { + int childrenLeft = mSpinnerPadding.left; + int childrenWidth = getRight() - getLeft() - mSpinnerPadding.left - mSpinnerPadding.right; + + if (mDataChanged) { + handleDataChanged(); + } + + // Handle the empty set by removing all views + if (mItemCount == 0) { + resetList(); + return; + } + + if (mNextSelectedPosition >= 0) { + setSelectedPositionInt(mNextSelectedPosition); + } + + recycleAllViews(); + + // Clear out old views + removeAllViewsInLayout(); + + // Make selected view and position it + mFirstPosition = mSelectedPosition; + View sel = makeAndAddView(mSelectedPosition); + int width = sel.getMeasuredWidth(); + int selectedOffset = childrenLeft; + switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + case Gravity.CENTER_HORIZONTAL: + selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2); + break; + case Gravity.RIGHT: + selectedOffset = childrenLeft + childrenWidth - width; + break; + } + sel.offsetLeftAndRight(selectedOffset); + + // Flush any cached views that did not get reused above + mRecycler.clear(); + + invalidate(); + + checkSelectionChanged(); + + mDataChanged = false; + mNeedSync = false; + setNextSelectedPositionInt(mSelectedPosition); + } + + /** + * Obtain a view, either by pulling an existing view from the recycler or + * by getting a new one from the adapter. If we are animating, make sure + * there is enough information in the view's layout parameters to animate + * from the old to new positions. + * + * @param position Position in the spinner for the view to obtain + * @return A view that has been added to the spinner + */ + private View makeAndAddView(int position) { + + View child; + + if (!mDataChanged) { + child = mRecycler.get(position); + if (child != null) { + // Position the view + setUpChild(child); + + return child; + } + } + + // Nothing found in the recycler -- ask the adapter for a view + child = mAdapter.getView(position, null, this); + + // Position the view + setUpChild(child); + + return child; + } + + /** + * Helper for makeAndAddView to set the position of a view + * and fill out its layout paramters. + * + * @param child The view to position + */ + private void setUpChild(View child) { + + // Respect layout params that are already in the view. Otherwise + // make some up... + ViewGroup.LayoutParams lp = child.getLayoutParams(); + if (lp == null) { + lp = generateDefaultLayoutParams(); + } + + addViewInLayout(child, 0, lp); + + child.setSelected(hasFocus()); + if (mDisableChildrenWhenDisabled) { + child.setEnabled(isEnabled()); + } + + // Get measure specs + int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec, + mSpinnerPadding.top + mSpinnerPadding.bottom, lp.height); + int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec, + mSpinnerPadding.left + mSpinnerPadding.right, lp.width); + + // Measure child + child.measure(childWidthSpec, childHeightSpec); + + int childLeft; + int childRight; + + // Position vertically based on gravity setting + int childTop = mSpinnerPadding.top + + ((getMeasuredHeight() - mSpinnerPadding.bottom - + mSpinnerPadding.top - child.getMeasuredHeight()) / 2); + int childBottom = childTop + child.getMeasuredHeight(); + + int width = child.getMeasuredWidth(); + childLeft = 0; + childRight = childLeft + width; + + child.layout(childLeft, childTop, childRight, childBottom); + } + + @Override + public boolean performClick() { + boolean handled = super.performClick(); + + if (!handled) { + handled = true; + + if (!mPopup.isShowing()) { + mPopup.show(); + } + } + + return handled; + } + + public void onClick(DialogInterface dialog, int which) { + setSelection(which); + dialog.dismiss(); + } + + /** + * Sets the prompt to display when the dialog is shown. + * @param prompt the prompt to set + */ + public void setPrompt(CharSequence prompt) { + mPopup.setPromptText(prompt); + } + + /** + * Sets the prompt to display when the dialog is shown. + * @param promptId the resource ID of the prompt to display when the dialog is shown + */ + public void setPromptId(int promptId) { + setPrompt(getContext().getText(promptId)); + } + + /** + * @return The prompt to display when the dialog is shown + */ + public CharSequence getPrompt() { + return mPopup.getHintText(); + } + + int measureContentWidth(SpinnerAdapter adapter, Drawable background) { + if (adapter == null) { + return 0; + } + + int width = 0; + View itemView = null; + int itemType = 0; + final int widthMeasureSpec = + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + final int heightMeasureSpec = + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + + // Make sure the number of items we'll measure is capped. If it's a huge data set + // with wildly varying sizes, oh well. + int start = Math.max(0, getSelectedItemPosition()); + final int end = Math.min(adapter.getCount(), start + MAX_ITEMS_MEASURED); + final int count = end - start; + start = Math.max(0, start - (MAX_ITEMS_MEASURED - count)); + for (int i = start; i < end; i++) { + final int positionType = adapter.getItemViewType(i); + if (positionType != itemType) { + itemType = positionType; + itemView = null; + } + itemView = adapter.getView(i, itemView, this); + if (itemView.getLayoutParams() == null) { + itemView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); + } + itemView.measure(widthMeasureSpec, heightMeasureSpec); + width = Math.max(width, itemView.getMeasuredWidth()); + } + + // Add background padding to measured width + if (background != null) { + background.getPadding(mTempRect); + width += mTempRect.left + mTempRect.right; + } + + return width; + } + + /** + *

Wrapper class for an Adapter. Transforms the embedded Adapter instance + * into a ListAdapter.

+ */ + private static class DropDownAdapter implements ListAdapter, SpinnerAdapter { + private SpinnerAdapter mAdapter; + private ListAdapter mListAdapter; + + /** + *

Creates a new ListAdapter wrapper for the specified adapter.

+ * + * @param adapter the Adapter to transform into a ListAdapter + */ + public DropDownAdapter(SpinnerAdapter adapter) { + this.mAdapter = adapter; + if (adapter instanceof ListAdapter) { + this.mListAdapter = (ListAdapter) adapter; + } + } + + public int getCount() { + return mAdapter == null ? 0 : mAdapter.getCount(); + } + + public Object getItem(int position) { + return mAdapter == null ? null : mAdapter.getItem(position); + } + + public long getItemId(int position) { + return mAdapter == null ? -1 : mAdapter.getItemId(position); + } + + public View getView(int position, View convertView, ViewGroup parent) { + return getDropDownView(position, convertView, parent); + } + + public View getDropDownView(int position, View convertView, ViewGroup parent) { + return mAdapter == null ? null : + mAdapter.getDropDownView(position, convertView, parent); + } + + public boolean hasStableIds() { + return mAdapter != null && mAdapter.hasStableIds(); + } + + public void registerDataSetObserver(DataSetObserver observer) { + if (mAdapter != null) { + mAdapter.registerDataSetObserver(observer); + } + } + + public void unregisterDataSetObserver(DataSetObserver observer) { + if (mAdapter != null) { + mAdapter.unregisterDataSetObserver(observer); + } + } + + /** + * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call. + * Otherwise, return true. + */ + public boolean areAllItemsEnabled() { + final ListAdapter adapter = mListAdapter; + if (adapter != null) { + return adapter.areAllItemsEnabled(); + } else { + return true; + } + } + + /** + * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call. + * Otherwise, return true. + */ + public boolean isEnabled(int position) { + final ListAdapter adapter = mListAdapter; + if (adapter != null) { + return adapter.isEnabled(position); + } else { + return true; + } + } + + public int getItemViewType(int position) { + return 0; + } + + public int getViewTypeCount() { + return 1; + } + + public boolean isEmpty() { + return getCount() == 0; + } + } + + /** + * Implements some sort of popup selection interface for selecting a spinner option. + * Allows for different spinner modes. + */ + private interface SpinnerPopup { + public void setAdapter(ListAdapter adapter); + + /** + * Show the popup + */ + public void show(); + + /** + * Dismiss the popup + */ + public void dismiss(); + + /** + * @return true if the popup is showing, false otherwise. + */ + public boolean isShowing(); + + /** + * Set hint text to be displayed to the user. This should provide + * a description of the choice being made. + * @param hintText Hint text to set. + */ + public void setPromptText(CharSequence hintText); + public CharSequence getHintText(); + } + + /* + private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener { + private AlertDialog mPopup; + private ListAdapter mListAdapter; + private CharSequence mPrompt; + + public void dismiss() { + mPopup.dismiss(); + mPopup = null; + } + + public boolean isShowing() { + return mPopup != null ? mPopup.isShowing() : false; + } + + public void setAdapter(ListAdapter adapter) { + mListAdapter = adapter; + } + + public void setPromptText(CharSequence hintText) { + mPrompt = hintText; + } + + public CharSequence getHintText() { + return mPrompt; + } + + public void show() { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + if (mPrompt != null) { + builder.setTitle(mPrompt); + } + mPopup = builder.setSingleChoiceItems(mListAdapter, + getSelectedItemPosition(), this).show(); + } + + public void onClick(DialogInterface dialog, int which) { + setSelection(which); + dismiss(); + } + } + */ + + private class DropdownPopup extends IcsListPopupWindow implements SpinnerPopup { + private CharSequence mHintText; + private ListAdapter mAdapter; + + public DropdownPopup(Context context, AttributeSet attrs, int defStyleRes) { + super(context, attrs, 0, defStyleRes); + + setAnchorView(IcsSpinner.this); + setModal(true); + setPromptPosition(POSITION_PROMPT_ABOVE); + setOnItemClickListener(new OnItemClickListener() { + @SuppressWarnings("rawtypes") + public void onItemClick(AdapterView parent, View v, int position, long id) { + IcsSpinner.this.setSelection(position); + dismiss(); + } + }); + } + + @Override + public void setAdapter(ListAdapter adapter) { + super.setAdapter(adapter); + mAdapter = adapter; + } + + public CharSequence getHintText() { + return mHintText; + } + + public void setPromptText(CharSequence hintText) { + // Hint text is ignored for dropdowns, but maintain it here. + mHintText = hintText; + } + + @Override + public void show() { + final int spinnerPaddingLeft = IcsSpinner.this.getPaddingLeft(); + if (mDropDownWidth == WRAP_CONTENT) { + final int spinnerWidth = IcsSpinner.this.getWidth(); + final int spinnerPaddingRight = IcsSpinner.this.getPaddingRight(); + setContentWidth(Math.max( + measureContentWidth((SpinnerAdapter) mAdapter, getBackground()), + spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight)); + } else if (mDropDownWidth == MATCH_PARENT) { + final int spinnerWidth = IcsSpinner.this.getWidth(); + final int spinnerPaddingRight = IcsSpinner.this.getPaddingRight(); + setContentWidth(spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight); + } else { + setContentWidth(mDropDownWidth); + } + final Drawable background = getBackground(); + int bgOffset = 0; + if (background != null) { + background.getPadding(mTempRect); + bgOffset = -mTempRect.left; + } + setHorizontalOffset(bgOffset + spinnerPaddingLeft); + setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED); + super.show(); + getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); + setSelection(IcsSpinner.this.getSelectedItemPosition()); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsView.java new file mode 100644 index 00000000..a7185d08 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/IcsView.java @@ -0,0 +1,21 @@ +package com.actionbarsherlock.internal.widget; + +import android.view.View; + +final class IcsView { + //No instances + private IcsView() {} + + /** + * Return only the state bits of {@link #getMeasuredWidthAndState()} + * and {@link #getMeasuredHeightAndState()}, combined into one integer. + * The width component is in the regular bits {@link #MEASURED_STATE_MASK} + * and the height component is at the shifted bits + * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. + */ + public static int getMeasuredStateInt(View child) { + return (child.getMeasuredWidth()&View.MEASURED_STATE_MASK) + | ((child.getMeasuredHeight()>>View.MEASURED_HEIGHT_STATE_SHIFT) + & (View.MEASURED_STATE_MASK>>View.MEASURED_HEIGHT_STATE_SHIFT)); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java new file mode 100644 index 00000000..48fb5d8b --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java @@ -0,0 +1,546 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.actionbarsherlock.internal.widget; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.text.TextUtils.TruncateAt; +import android.util.AttributeSet; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import com.actionbarsherlock.R; +import com.actionbarsherlock.app.ActionBar; +import com.actionbarsherlock.internal.nineoldandroids.animation.Animator; +import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator; +import com.actionbarsherlock.internal.nineoldandroids.widget.NineHorizontalScrollView; + +/** + * This widget implements the dynamic action bar tab behavior that can change + * across different configurations or circumstances. + */ +public class ScrollingTabContainerView extends NineHorizontalScrollView + implements IcsAdapterView.OnItemSelectedListener { + //UNUSED private static final String TAG = "ScrollingTabContainerView"; + Runnable mTabSelector; + private TabClickListener mTabClickListener; + + private IcsLinearLayout mTabLayout; + private IcsSpinner mTabSpinner; + private boolean mAllowCollapse; + + private LayoutInflater mInflater; + + int mMaxTabWidth; + private int mContentHeight; + private int mSelectedTabIndex; + + protected Animator mVisibilityAnim; + protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener(); + + private static final /*Time*/Interpolator sAlphaInterpolator = new DecelerateInterpolator(); + + private static final int FADE_DURATION = 200; + + public ScrollingTabContainerView(Context context) { + super(context); + setHorizontalScrollBarEnabled(false); + + TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar, + R.attr.actionBarStyle, 0); + setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0)); + a.recycle(); + + mInflater = LayoutInflater.from(context); + + mTabLayout = createTabLayout(); + addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int widthMode = MeasureSpec.getMode(widthMeasureSpec); + final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY; + setFillViewport(lockedExpanded); + + final int childCount = mTabLayout.getChildCount(); + if (childCount > 1 && + (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) { + if (childCount > 2) { + mMaxTabWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.4f); + } else { + mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2; + } + } else { + mMaxTabWidth = -1; + } + + heightMeasureSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY); + + final boolean canCollapse = !lockedExpanded && mAllowCollapse; + + if (canCollapse) { + // See if we should expand + mTabLayout.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec); + if (mTabLayout.getMeasuredWidth() > MeasureSpec.getSize(widthMeasureSpec)) { + performCollapse(); + } else { + performExpand(); + } + } else { + performExpand(); + } + + final int oldWidth = getMeasuredWidth(); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + final int newWidth = getMeasuredWidth(); + + if (lockedExpanded && oldWidth != newWidth) { + // Recenter the tab display if we're at a new (scrollable) size. + setTabSelected(mSelectedTabIndex); + } + } + + /** + * Indicates whether this view is collapsed into a dropdown menu instead + * of traditional tabs. + * @return true if showing as a spinner + */ + private boolean isCollapsed() { + return mTabSpinner != null && mTabSpinner.getParent() == this; + } + + public void setAllowCollapse(boolean allowCollapse) { + mAllowCollapse = allowCollapse; + } + + private void performCollapse() { + if (isCollapsed()) return; + + if (mTabSpinner == null) { + mTabSpinner = createSpinner(); + } + removeView(mTabLayout); + addView(mTabSpinner, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + if (mTabSpinner.getAdapter() == null) { + mTabSpinner.setAdapter(new TabAdapter()); + } + if (mTabSelector != null) { + removeCallbacks(mTabSelector); + mTabSelector = null; + } + mTabSpinner.setSelection(mSelectedTabIndex); + } + + private boolean performExpand() { + if (!isCollapsed()) return false; + + removeView(mTabSpinner); + addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + setTabSelected(mTabSpinner.getSelectedItemPosition()); + return false; + } + + public void setTabSelected(int position) { + mSelectedTabIndex = position; + final int tabCount = mTabLayout.getChildCount(); + for (int i = 0; i < tabCount; i++) { + final View child = mTabLayout.getChildAt(i); + final boolean isSelected = i == position; + child.setSelected(isSelected); + if (isSelected) { + animateToTab(position); + } + } + } + + public void setContentHeight(int contentHeight) { + mContentHeight = contentHeight; + requestLayout(); + } + + private IcsLinearLayout createTabLayout() { + final IcsLinearLayout tabLayout = (IcsLinearLayout) LayoutInflater.from(getContext()) + .inflate(R.layout.abs__action_bar_tab_bar_view, null); + tabLayout.setMeasureWithLargestChildEnabled(true); + tabLayout.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT)); + return tabLayout; + } + + private IcsSpinner createSpinner() { + final IcsSpinner spinner = new IcsSpinner(getContext(), null, + R.attr.actionDropDownStyle); + spinner.setLayoutParams(new LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT)); + spinner.setOnItemSelectedListener(this); + return spinner; + } + + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + + // Action bar can change size on configuration changes. + // Reread the desired height from the theme-specified style. + TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar, + R.attr.actionBarStyle, 0); + setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0)); + a.recycle(); + } + + public void animateToVisibility(int visibility) { + if (mVisibilityAnim != null) { + mVisibilityAnim.cancel(); + } + if (visibility == VISIBLE) { + if (getVisibility() != VISIBLE) { + setAlpha(0); + } + ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1); + anim.setDuration(FADE_DURATION); + anim.setInterpolator(sAlphaInterpolator); + + anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); + anim.start(); + } else { + ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0); + anim.setDuration(FADE_DURATION); + anim.setInterpolator(sAlphaInterpolator); + + anim.addListener(mVisAnimListener.withFinalVisibility(visibility)); + anim.start(); + } + } + + public void animateToTab(final int position) { + final View tabView = mTabLayout.getChildAt(position); + if (mTabSelector != null) { + removeCallbacks(mTabSelector); + } + mTabSelector = new Runnable() { + public void run() { + final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2; + smoothScrollTo(scrollPos, 0); + mTabSelector = null; + } + }; + post(mTabSelector); + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + if (mTabSelector != null) { + // Re-post the selector we saved + post(mTabSelector); + } + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mTabSelector != null) { + removeCallbacks(mTabSelector); + } + } + + private TabView createTabView(ActionBar.Tab tab, boolean forAdapter) { + //Workaround for not being able to pass a defStyle on pre-3.0 + final TabView tabView = (TabView)mInflater.inflate(R.layout.abs__action_bar_tab, null); + tabView.init(this, tab, forAdapter); + + if (forAdapter) { + tabView.setBackgroundDrawable(null); + tabView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT, + mContentHeight)); + } else { + tabView.setFocusable(true); + + if (mTabClickListener == null) { + mTabClickListener = new TabClickListener(); + } + tabView.setOnClickListener(mTabClickListener); + } + return tabView; + } + + public void addTab(ActionBar.Tab tab, boolean setSelected) { + TabView tabView = createTabView(tab, false); + mTabLayout.addView(tabView, new IcsLinearLayout.LayoutParams(0, + LayoutParams.MATCH_PARENT, 1)); + if (mTabSpinner != null) { + ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); + } + if (setSelected) { + tabView.setSelected(true); + } + if (mAllowCollapse) { + requestLayout(); + } + } + + public void addTab(ActionBar.Tab tab, int position, boolean setSelected) { + final TabView tabView = createTabView(tab, false); + mTabLayout.addView(tabView, position, new IcsLinearLayout.LayoutParams( + 0, LayoutParams.MATCH_PARENT, 1)); + if (mTabSpinner != null) { + ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); + } + if (setSelected) { + tabView.setSelected(true); + } + if (mAllowCollapse) { + requestLayout(); + } + } + + public void updateTab(int position) { + ((TabView) mTabLayout.getChildAt(position)).update(); + if (mTabSpinner != null) { + ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); + } + if (mAllowCollapse) { + requestLayout(); + } + } + + public void removeTabAt(int position) { + mTabLayout.removeViewAt(position); + if (mTabSpinner != null) { + ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); + } + if (mAllowCollapse) { + requestLayout(); + } + } + + public void removeAllTabs() { + mTabLayout.removeAllViews(); + if (mTabSpinner != null) { + ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged(); + } + if (mAllowCollapse) { + requestLayout(); + } + } + + @Override + public void onItemSelected(IcsAdapterView parent, View view, int position, long id) { + TabView tabView = (TabView) view; + tabView.getTab().select(); + } + + @Override + public void onNothingSelected(IcsAdapterView parent) { + } + + public static class TabView extends LinearLayout { + private ScrollingTabContainerView mParent; + private ActionBar.Tab mTab; + private CapitalizingTextView mTextView; + private ImageView mIconView; + private View mCustomView; + + public TabView(Context context, AttributeSet attrs) { + //TODO super(context, null, R.attr.actionBarTabStyle); + super(context, attrs); + } + + public void init(ScrollingTabContainerView parent, ActionBar.Tab tab, boolean forList) { + mParent = parent; + mTab = tab; + + if (forList) { + setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); + } + + update(); + } + + public void bindTab(ActionBar.Tab tab) { + mTab = tab; + update(); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + // Re-measure if we went beyond our maximum size. + if (mParent.mMaxTabWidth > 0 && getMeasuredWidth() > mParent.mMaxTabWidth) { + super.onMeasure(MeasureSpec.makeMeasureSpec(mParent.mMaxTabWidth, MeasureSpec.EXACTLY), + heightMeasureSpec); + } + } + + public void update() { + final ActionBar.Tab tab = mTab; + final View custom = tab.getCustomView(); + if (custom != null) { + final ViewParent customParent = custom.getParent(); + if (customParent != this) { + if (customParent != null) ((ViewGroup) customParent).removeView(custom); + addView(custom); + } + mCustomView = custom; + if (mTextView != null) mTextView.setVisibility(GONE); + if (mIconView != null) { + mIconView.setVisibility(GONE); + mIconView.setImageDrawable(null); + } + } else { + if (mCustomView != null) { + removeView(mCustomView); + mCustomView = null; + } + + final Drawable icon = tab.getIcon(); + final CharSequence text = tab.getText(); + + if (icon != null) { + if (mIconView == null) { + ImageView iconView = new ImageView(getContext()); + LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.CENTER_VERTICAL; + iconView.setLayoutParams(lp); + addView(iconView, 0); + mIconView = iconView; + } + mIconView.setImageDrawable(icon); + mIconView.setVisibility(VISIBLE); + } else if (mIconView != null) { + mIconView.setVisibility(GONE); + mIconView.setImageDrawable(null); + } + + if (text != null) { + if (mTextView == null) { + CapitalizingTextView textView = new CapitalizingTextView(getContext(), null, + R.attr.actionBarTabTextStyle); + textView.setEllipsize(TruncateAt.END); + LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, + LayoutParams.WRAP_CONTENT); + lp.gravity = Gravity.CENTER_VERTICAL; + textView.setLayoutParams(lp); + addView(textView); + mTextView = textView; + } + mTextView.setTextCompat(text); + mTextView.setVisibility(VISIBLE); + } else if (mTextView != null) { + mTextView.setVisibility(GONE); + mTextView.setText(null); + } + + if (mIconView != null) { + mIconView.setContentDescription(tab.getContentDescription()); + } + } + } + + public ActionBar.Tab getTab() { + return mTab; + } + } + + private class TabAdapter extends BaseAdapter { + @Override + public int getCount() { + return mTabLayout.getChildCount(); + } + + @Override + public Object getItem(int position) { + return ((TabView) mTabLayout.getChildAt(position)).getTab(); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = createTabView((ActionBar.Tab) getItem(position), true); + } else { + ((TabView) convertView).bindTab((ActionBar.Tab) getItem(position)); + } + return convertView; + } + } + + private class TabClickListener implements OnClickListener { + public void onClick(View view) { + TabView tabView = (TabView) view; + tabView.getTab().select(); + final int tabCount = mTabLayout.getChildCount(); + for (int i = 0; i < tabCount; i++) { + final View child = mTabLayout.getChildAt(i); + child.setSelected(child == view); + } + } + } + + protected class VisibilityAnimListener implements Animator.AnimatorListener { + private boolean mCanceled = false; + private int mFinalVisibility; + + public VisibilityAnimListener withFinalVisibility(int visibility) { + mFinalVisibility = visibility; + return this; + } + + @Override + public void onAnimationStart(Animator animation) { + setVisibility(VISIBLE); + mVisibilityAnim = animation; + mCanceled = false; + } + + @Override + public void onAnimationEnd(Animator animation) { + if (mCanceled) return; + + mVisibilityAnim = null; + setVisibility(mFinalVisibility); + } + + @Override + public void onAnimationCancel(Animator animation) { + mCanceled = true; + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ScrollingTextView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ScrollingTextView.java deleted file mode 100644 index edd5ec0a..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/internal/widget/ScrollingTextView.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.actionbarsherlock.internal.widget; - -import android.content.Context; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.widget.TextView; - -/** - * @author marco - * Workaround to be able to scroll text inside a TextView without it required - * to be focused. For some strange reason there isn't an easy way to do this - * natively. - * - * Original code written by Evan Cummings: - * http://androidbears.stellarpc.net/?p=185 - */ -public final class ScrollingTextView extends TextView { - - public ScrollingTextView(Context context, AttributeSet attrs, - int defStyle) { - super(context, attrs, defStyle); - } - - public ScrollingTextView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public ScrollingTextView(Context context) { - super(context); - } - - @Override - protected void onFocusChanged(boolean focused, int direction, - Rect previouslyFocusedRect) { - if (focused) { - super.onFocusChanged(focused, direction, previouslyFocusedRect); - } - } - - @Override - public void onWindowFocusChanged(boolean focused) { - if (focused) { - super.onWindowFocusChanged(focused); - } - } - - @Override - public boolean isFocused() { - return true; - } -} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ActionMode.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/ActionMode.java similarity index 52% rename from external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ActionMode.java rename to external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/ActionMode.java index f265b3cd..81b4cd4d 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/ActionMode.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/ActionMode.java @@ -1,11 +1,11 @@ /* - * Copyright 2011 Jake Wharton + * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -14,175 +14,211 @@ * limitations under the License. */ -package android.support.v4.view; +package com.actionbarsherlock.view; import android.view.View; + /** - * Represents a contextual mode of the user interface. Action modes can be used - * for modal interactions with content and replace parts of the normal UI until - * finished. Examples of good action modes include selection modes, search, - * content editing, etc. + * Represents a contextual mode of the user interface. Action modes can be used for + * modal interactions with content and replace parts of the normal UI until finished. + * Examples of good action modes include selection modes, search, content editing, etc. */ public abstract class ActionMode { + private Object mTag; + /** - *

Callback interface for action modes. Supplied to - * {@link android.support.v4.app.FragmentActivity#startActionMode(Callback)}, - * a Callback configures and handles events raised by a user's interaction - * with an action mode.

+ * Set a tag object associated with this ActionMode. * - *

An action mode's lifecycle is as follows: - *

    - *
  • {@link #onCreateActionMode(ActionMode, Menu)} once on initial - * creation
  • - *
  • {@link #onPrepareActionMode(ActionMode, Menu)} after creation and - * any time the ActionMode is invalidated
  • - *
  • {@link #onActionItemClicked(ActionMode, MenuItem)} any time a - * contextual action button is clicked
  • - *
  • {@link #onDestroyActionMode(ActionMode)} when the action mode is - * closed
  • - *
- *

+ *

Like the tag available to views, this allows applications to associate arbitrary + * data with an ActionMode for later reference. + * + * @param tag Tag to associate with this ActionMode + * + * @see #getTag() */ - public interface Callback { - /** - * Called to report a user click on an action button. - * - * @param mode The current ActionMode - * @param item The item that was clicked - * @return true if this callback handled the event, false if the - * standard MenuItem invocation should continue. - */ - boolean onActionItemClicked(ActionMode mode, MenuItem item); - - /** - * Called when action mode is first created. The menu supplied will be - * used to generate action buttons for the action mode. - * - * @param mode ActionMode being created - * @param menu Menu used to populate action buttons - * @return true if the action mode should be created, false if entering - * this mode should be aborted. - */ - boolean onCreateActionMode(ActionMode mode, Menu menu); - - /** - * Called when an action mode is about to be exited and destroyed. - * - * @param mode The current ActionMode being destroyed - */ - void onDestroyActionMode(ActionMode mode); - - /** - * Called to refresh an action mode's action menu whenever it is - * invalidated. - * - * @param mode ActionMode being prepared - * @param menu Menu used to populate action buttons - * @return true if the menu or action mode was updated, false otherwise. - */ - boolean onPrepareActionMode(ActionMode mode, Menu menu); + public void setTag(Object tag) { + mTag = tag; } /** - * Finish and close this action mode. The action mode's - * {@link ActionMode.Callback} will have its - * {@link ActionMode.Callback#onDestroyActionMode(ActionMode)} method - * called. + * Retrieve the tag object associated with this ActionMode. + * + *

Like the tag available to views, this allows applications to associate arbitrary + * data with an ActionMode for later reference. + * + * @return Tag associated with this ActionMode + * + * @see #setTag(Object) */ - public abstract void finish(); + public Object getTag() { + return mTag; + } /** - * Returns the current custom view for this action mode. + * Set the title of the action mode. This method will have no visible effect if + * a custom view has been set. * - * @return The current custom view + * @param title Title string to set + * + * @see #setTitle(int) + * @see #setCustomView(View) */ - public abstract View getCustomView(); + public abstract void setTitle(CharSequence title); /** - * Returns the menu of actions that this action mode presents. + * Set the title of the action mode. This method will have no visible effect if + * a custom view has been set. * - * @return The action mode's menu. + * @param resId Resource ID of a string to set as the title + * + * @see #setTitle(CharSequence) + * @see #setCustomView(View) */ - public abstract Menu getMenu(); + public abstract void setTitle(int resId); /** - * Returns a {@link MenuInflater} with the ActionMode's context. + * Set the subtitle of the action mode. This method will have no visible effect if + * a custom view has been set. * - * @return Menu inflater. + * @param subtitle Subtitle string to set + * + * @see #setSubtitle(int) + * @see #setCustomView(View) */ - public abstract MenuInflater getMenuInflater(); + public abstract void setSubtitle(CharSequence subtitle); /** - * Returns the current subtitle of this action mode. + * Set the subtitle of the action mode. This method will have no visible effect if + * a custom view has been set. * - * @return Subtitle text + * @param resId Resource ID of a string to set as the subtitle + * + * @see #setSubtitle(CharSequence) + * @see #setCustomView(View) */ - public abstract CharSequence getSubtitle(); + public abstract void setSubtitle(int resId); /** - * Returns the current title of this action mode. + * Set a custom view for this action mode. The custom view will take the place of + * the title and subtitle. Useful for things like search boxes. * - * @return Title text + * @param view Custom view to use in place of the title/subtitle. + * + * @see #setTitle(CharSequence) + * @see #setSubtitle(CharSequence) */ - public abstract CharSequence getTitle(); + public abstract void setCustomView(View view); /** * Invalidate the action mode and refresh menu content. The mode's * {@link ActionMode.Callback} will have its - * {@link ActionMode.Callback#onPrepareActionMode(ActionMode, Menu)} method - * called. If it returns true the menu will be scanned for updated content - * and any relevant changes will be reflected to the user. + * {@link Callback#onPrepareActionMode(ActionMode, Menu)} method called. + * If it returns true the menu will be scanned for updated content and any relevant changes + * will be reflected to the user. */ public abstract void invalidate(); /** - * Set a custom view for this action mode. The custom view will take the - * place of the title and subtitle. Useful for things like search boxes. - * - * @param view Custom view to use in place of the title/subtitle. - * @see #setTitle(CharSequence) - * @see #setSubtitle(CharSequence) + * Finish and close this action mode. The action mode's {@link ActionMode.Callback} will + * have its {@link Callback#onDestroyActionMode(ActionMode)} method called. */ - public abstract void setCustomView(View view); + public abstract void finish(); /** - * Set the subtitle of the action mode. This method will have no visible - * effect if a custom view has been set. - * - * @param resId Resource ID of a string to set as the subtitle - * @see #setSubtitle(CharSequence) - * @see #setCustomView(View) + * Returns the menu of actions that this action mode presents. + * @return The action mode's menu. */ - public abstract void setSubtitle(int resId); + public abstract Menu getMenu(); /** - * Set the subtitle of the action mode. This method will have no visible - * effect if a custom view has been set. - * - * @param subtitle Subtitle string to set - * @see #setSubtitle(int) - * @see #setCustomView(View) + * Returns the current title of this action mode. + * @return Title text */ - public abstract void setSubtitle(CharSequence subtitle); + public abstract CharSequence getTitle(); + + /** + * Returns the current subtitle of this action mode. + * @return Subtitle text + */ + public abstract CharSequence getSubtitle(); + + /** + * Returns the current custom view for this action mode. + * @return The current custom view + */ + public abstract View getCustomView(); + + /** + * Returns a {@link MenuInflater} with the ActionMode's context. + */ + public abstract MenuInflater getMenuInflater(); /** - * Set the title of the action mode. This method will have no visible effect - * if a custom view has been set. + * Returns whether the UI presenting this action mode can take focus or not. + * This is used by internal components within the framework that would otherwise + * present an action mode UI that requires focus, such as an EditText as a custom view. * - * @param resId Resource ID of a string to set as the title - * @see #setTitle(CharSequence) - * @see #setCustomView(View) + * @return true if the UI used to show this action mode can take focus + * @hide Internal use only */ - public abstract void setTitle(int resId); + public boolean isUiFocusable() { + return true; + } /** - * Set the title of the action mode. This method will have no visible effect - * if a custom view has been set. + * Callback interface for action modes. Supplied to + * {@link View#startActionMode(Callback)}, a Callback + * configures and handles events raised by a user's interaction with an action mode. * - * @param title Title string to set - * @see #setTitle(int) - * @see #setCustomView(View) + *

An action mode's lifecycle is as follows: + *

    + *
  • {@link Callback#onCreateActionMode(ActionMode, Menu)} once on initial + * creation
  • + *
  • {@link Callback#onPrepareActionMode(ActionMode, Menu)} after creation + * and any time the {@link ActionMode} is invalidated
  • + *
  • {@link Callback#onActionItemClicked(ActionMode, MenuItem)} any time a + * contextual action button is clicked
  • + *
  • {@link Callback#onDestroyActionMode(ActionMode)} when the action mode + * is closed
  • + *
*/ - public abstract void setTitle(CharSequence title); -} + public interface Callback { + /** + * Called when action mode is first created. The menu supplied will be used to + * generate action buttons for the action mode. + * + * @param mode ActionMode being created + * @param menu Menu used to populate action buttons + * @return true if the action mode should be created, false if entering this + * mode should be aborted. + */ + public boolean onCreateActionMode(ActionMode mode, Menu menu); + + /** + * Called to refresh an action mode's action menu whenever it is invalidated. + * + * @param mode ActionMode being prepared + * @param menu Menu used to populate action buttons + * @return true if the menu or action mode was updated, false otherwise. + */ + public boolean onPrepareActionMode(ActionMode mode, Menu menu); + + /** + * Called to report a user click on an action button. + * + * @param mode The current ActionMode + * @param item The item that was clicked + * @return true if this callback handled the event, false if the standard MenuItem + * invocation should continue. + */ + public boolean onActionItemClicked(ActionMode mode, MenuItem item); + + /** + * Called when an action mode is about to be exited and destroyed. + * + * @param mode The current ActionMode being destroyed + */ + public void onDestroyActionMode(ActionMode mode); + } +} \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/ActionProvider.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/ActionProvider.java new file mode 100644 index 00000000..ae7cb1fe --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/ActionProvider.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.view; + +import android.content.Context; +import android.view.View; + +/** + * This class is a mediator for accomplishing a given task, for example sharing a file. + * It is responsible for creating a view that performs an action that accomplishes the task. + * This class also implements other functions such a performing a default action. + *

+ * An ActionProvider can be optionally specified for a {@link MenuItem} and in such a + * case it will be responsible for creating the action view that appears in the + * {@link android.app.ActionBar} as a substitute for the menu item when the item is + * displayed as an action item. Also the provider is responsible for performing a + * default action if a menu item placed on the overflow menu of the ActionBar is + * selected and none of the menu item callbacks has handled the selection. For this + * case the provider can also optionally provide a sub-menu for accomplishing the + * task at hand. + *

+ *

+ * There are two ways for using an action provider for creating and handling of action views: + *

    + *
  • + * Setting the action provider on a {@link MenuItem} directly by calling + * {@link MenuItem#setActionProvider(ActionProvider)}. + *
  • + *
  • + * Declaring the action provider in the menu XML resource. For example: + *
    + * 
    + *   <item android:id="@+id/my_menu_item"
    + *     android:title="Title"
    + *     android:icon="@drawable/my_menu_item_icon"
    + *     android:showAsAction="ifRoom"
    + *     android:actionProviderClass="foo.bar.SomeActionProvider" />
    + * 
    + * 
    + *
  • + *
+ *

+ * + * @see MenuItem#setActionProvider(ActionProvider) + * @see MenuItem#getActionProvider() + */ +public abstract class ActionProvider { + private SubUiVisibilityListener mSubUiVisibilityListener; + + /** + * Creates a new instance. + * + * @param context Context for accessing resources. + */ + public ActionProvider(Context context) { + } + + /** + * Factory method for creating new action views. + * + * @return A new action view. + */ + public abstract View onCreateActionView(); + + /** + * Performs an optional default action. + *

+ * For the case of an action provider placed in a menu item not shown as an action this + * method is invoked if previous callbacks for processing menu selection has handled + * the event. + *

+ *

+ * A menu item selection is processed in the following order: + *

    + *
  • + * Receiving a call to {@link MenuItem.OnMenuItemClickListener#onMenuItemClick + * MenuItem.OnMenuItemClickListener.onMenuItemClick}. + *
  • + *
  • + * Receiving a call to {@link android.app.Activity#onOptionsItemSelected(MenuItem) + * Activity.onOptionsItemSelected(MenuItem)} + *
  • + *
  • + * Receiving a call to {@link android.app.Fragment#onOptionsItemSelected(MenuItem) + * Fragment.onOptionsItemSelected(MenuItem)} + *
  • + *
  • + * Launching the {@link android.content.Intent} set via + * {@link MenuItem#setIntent(android.content.Intent) MenuItem.setIntent(android.content.Intent)} + *
  • + *
  • + * Invoking this method. + *
  • + *
+ *

+ *

+ * The default implementation does not perform any action and returns false. + *

+ */ + public boolean onPerformDefaultAction() { + return false; + } + + /** + * Determines if this ActionProvider has a submenu associated with it. + * + *

Associated submenus will be shown when an action view is not. This + * provider instance will receive a call to {@link #onPrepareSubMenu(SubMenu)} + * after the call to {@link #onPerformDefaultAction()} and before a submenu is + * displayed to the user. + * + * @return true if the item backed by this provider should have an associated submenu + */ + public boolean hasSubMenu() { + return false; + } + + /** + * Called to prepare an associated submenu for the menu item backed by this ActionProvider. + * + *

if {@link #hasSubMenu()} returns true, this method will be called when the + * menu item is selected to prepare the submenu for presentation to the user. Apps + * may use this to create or alter submenu content right before display. + * + * @param subMenu Submenu that will be displayed + */ + public void onPrepareSubMenu(SubMenu subMenu) { + } + + /** + * Notify the system that the visibility of an action view's sub-UI such as + * an anchored popup has changed. This will affect how other system + * visibility notifications occur. + * + * @hide Pending future API approval + */ + public void subUiVisibilityChanged(boolean isVisible) { + if (mSubUiVisibilityListener != null) { + mSubUiVisibilityListener.onSubUiVisibilityChanged(isVisible); + } + } + + /** + * @hide Internal use only + */ + public void setSubUiVisibilityListener(SubUiVisibilityListener listener) { + mSubUiVisibilityListener = listener; + } + + /** + * @hide Internal use only + */ + public interface SubUiVisibilityListener { + public void onSubUiVisibilityChanged(boolean isVisible); + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/CollapsibleActionView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/CollapsibleActionView.java new file mode 100644 index 00000000..43281b01 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/CollapsibleActionView.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.view; + +/** + * When a {@link View} implements this interface it will receive callbacks + * when expanded or collapsed as an action view alongside the optional, + * app-specified callbacks to {@link OnActionExpandListener}. + * + *

See {@link MenuItem} for more information about action views. + * See {@link android.app.ActionBar} for more information about the action bar. + */ +public interface CollapsibleActionView { + /** + * Called when this view is expanded as an action view. + * See {@link MenuItem#expandActionView()}. + */ + public void onActionViewExpanded(); + + /** + * Called when this view is collapsed as an action view. + * See {@link MenuItem#collapseActionView()}. + */ + public void onActionViewCollapsed(); +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/Menu.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/Menu.java new file mode 100644 index 00000000..951f4cce --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/Menu.java @@ -0,0 +1,447 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.view; + +import android.content.ComponentName; +import android.content.Intent; +import android.view.KeyEvent; + +/** + * Interface for managing the items in a menu. + *

+ * By default, every Activity supports an options menu of actions or options. + * You can add items to this menu and handle clicks on your additions. The + * easiest way of adding menu items is inflating an XML file into the + * {@link Menu} via {@link MenuInflater}. The easiest way of attaching code to + * clicks is via {@link Activity#onOptionsItemSelected(MenuItem)} and + * {@link Activity#onContextItemSelected(MenuItem)}. + *

+ * Different menu types support different features: + *

    + *
  1. Context menus: Do not support item shortcuts and item icons. + *
  2. Options menus: The icon menus do not support item check + * marks and only show the item's + * {@link MenuItem#setTitleCondensed(CharSequence) condensed title}. The + * expanded menus (only available if six or more menu items are visible, + * reached via the 'More' item in the icon menu) do not show item icons, and + * item check marks are discouraged. + *
  3. Sub menus: Do not support item icons, or nested sub menus. + *
+ * + *
+ *

Developer Guides

+ *

For more information about creating menus, read the + * Menus developer guide.

+ *
+ */ +public interface Menu { + + /** + * This is the part of an order integer that the user can provide. + * @hide + */ + static final int USER_MASK = 0x0000ffff; + /** + * Bit shift of the user portion of the order integer. + * @hide + */ + static final int USER_SHIFT = 0; + + /** + * This is the part of an order integer that supplies the category of the + * item. + * @hide + */ + static final int CATEGORY_MASK = 0xffff0000; + /** + * Bit shift of the category portion of the order integer. + * @hide + */ + static final int CATEGORY_SHIFT = 16; + + /** + * Value to use for group and item identifier integers when you don't care + * about them. + */ + static final int NONE = 0; + + /** + * First value for group and item identifier integers. + */ + static final int FIRST = 1; + + // Implementation note: Keep these CATEGORY_* in sync with the category enum + // in attrs.xml + + /** + * Category code for the order integer for items/groups that are part of a + * container -- or/add this with your base value. + */ + static final int CATEGORY_CONTAINER = 0x00010000; + + /** + * Category code for the order integer for items/groups that are provided by + * the system -- or/add this with your base value. + */ + static final int CATEGORY_SYSTEM = 0x00020000; + + /** + * Category code for the order integer for items/groups that are + * user-supplied secondary (infrequently used) options -- or/add this with + * your base value. + */ + static final int CATEGORY_SECONDARY = 0x00030000; + + /** + * Category code for the order integer for items/groups that are + * alternative actions on the data that is currently displayed -- or/add + * this with your base value. + */ + static final int CATEGORY_ALTERNATIVE = 0x00040000; + + /** + * Flag for {@link #addIntentOptions}: if set, do not automatically remove + * any existing menu items in the same group. + */ + static final int FLAG_APPEND_TO_GROUP = 0x0001; + + /** + * Flag for {@link #performShortcut}: if set, do not close the menu after + * executing the shortcut. + */ + static final int FLAG_PERFORM_NO_CLOSE = 0x0001; + + /** + * Flag for {@link #performShortcut(int, KeyEvent, int)}: if set, always + * close the menu after executing the shortcut. Closing the menu also resets + * the prepared state. + */ + static final int FLAG_ALWAYS_PERFORM_CLOSE = 0x0002; + + /** + * Add a new item to the menu. This item displays the given title for its + * label. + * + * @param title The text to display for the item. + * @return The newly added menu item. + */ + public MenuItem add(CharSequence title); + + /** + * Add a new item to the menu. This item displays the given title for its + * label. + * + * @param titleRes Resource identifier of title string. + * @return The newly added menu item. + */ + public MenuItem add(int titleRes); + + /** + * Add a new item to the menu. This item displays the given title for its + * label. + * + * @param groupId The group identifier that this item should be part of. + * This can be used to define groups of items for batch state + * changes. Normally use {@link #NONE} if an item should not be in a + * group. + * @param itemId Unique item ID. Use {@link #NONE} if you do not need a + * unique ID. + * @param order The order for the item. Use {@link #NONE} if you do not care + * about the order. See {@link MenuItem#getOrder()}. + * @param title The text to display for the item. + * @return The newly added menu item. + */ + public MenuItem add(int groupId, int itemId, int order, CharSequence title); + + /** + * Variation on {@link #add(int, int, int, CharSequence)} that takes a + * string resource identifier instead of the string itself. + * + * @param groupId The group identifier that this item should be part of. + * This can also be used to define groups of items for batch state + * changes. Normally use {@link #NONE} if an item should not be in a + * group. + * @param itemId Unique item ID. Use {@link #NONE} if you do not need a + * unique ID. + * @param order The order for the item. Use {@link #NONE} if you do not care + * about the order. See {@link MenuItem#getOrder()}. + * @param titleRes Resource identifier of title string. + * @return The newly added menu item. + */ + public MenuItem add(int groupId, int itemId, int order, int titleRes); + + /** + * Add a new sub-menu to the menu. This item displays the given title for + * its label. To modify other attributes on the submenu's menu item, use + * {@link SubMenu#getItem()}. + * + * @param title The text to display for the item. + * @return The newly added sub-menu + */ + SubMenu addSubMenu(final CharSequence title); + + /** + * Add a new sub-menu to the menu. This item displays the given title for + * its label. To modify other attributes on the submenu's menu item, use + * {@link SubMenu#getItem()}. + * + * @param titleRes Resource identifier of title string. + * @return The newly added sub-menu + */ + SubMenu addSubMenu(final int titleRes); + + /** + * Add a new sub-menu to the menu. This item displays the given + * title for its label. To modify other attributes on the + * submenu's menu item, use {@link SubMenu#getItem()}. + *

+ * Note that you can only have one level of sub-menus, i.e. you cannnot add + * a subMenu to a subMenu: An {@link UnsupportedOperationException} will be + * thrown if you try. + * + * @param groupId The group identifier that this item should be part of. + * This can also be used to define groups of items for batch state + * changes. Normally use {@link #NONE} if an item should not be in a + * group. + * @param itemId Unique item ID. Use {@link #NONE} if you do not need a + * unique ID. + * @param order The order for the item. Use {@link #NONE} if you do not care + * about the order. See {@link MenuItem#getOrder()}. + * @param title The text to display for the item. + * @return The newly added sub-menu + */ + SubMenu addSubMenu(final int groupId, final int itemId, int order, final CharSequence title); + + /** + * Variation on {@link #addSubMenu(int, int, int, CharSequence)} that takes + * a string resource identifier for the title instead of the string itself. + * + * @param groupId The group identifier that this item should be part of. + * This can also be used to define groups of items for batch state + * changes. Normally use {@link #NONE} if an item should not be in a group. + * @param itemId Unique item ID. Use {@link #NONE} if you do not need a unique ID. + * @param order The order for the item. Use {@link #NONE} if you do not care about the + * order. See {@link MenuItem#getOrder()}. + * @param titleRes Resource identifier of title string. + * @return The newly added sub-menu + */ + SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes); + + /** + * Add a group of menu items corresponding to actions that can be performed + * for a particular Intent. The Intent is most often configured with a null + * action, the data that the current activity is working with, and includes + * either the {@link Intent#CATEGORY_ALTERNATIVE} or + * {@link Intent#CATEGORY_SELECTED_ALTERNATIVE} to find activities that have + * said they would like to be included as optional action. You can, however, + * use any Intent you want. + * + *

+ * See {@link android.content.pm.PackageManager#queryIntentActivityOptions} + * for more * details on the caller, specifics, and + * intent arguments. The list returned by that function is used + * to populate the resulting menu items. + * + *

+ * All of the menu items of possible options for the intent will be added + * with the given group and id. You can use the group to control ordering of + * the items in relation to other items in the menu. Normally this function + * will automatically remove any existing items in the menu in the same + * group and place a divider above and below the added items; this behavior + * can be modified with the flags parameter. For each of the + * generated items {@link MenuItem#setIntent} is called to associate the + * appropriate Intent with the item; this means the activity will + * automatically be started for you without having to do anything else. + * + * @param groupId The group identifier that the items should be part of. + * This can also be used to define groups of items for batch state + * changes. Normally use {@link #NONE} if the items should not be in + * a group. + * @param itemId Unique item ID. Use {@link #NONE} if you do not need a + * unique ID. + * @param order The order for the items. Use {@link #NONE} if you do not + * care about the order. See {@link MenuItem#getOrder()}. + * @param caller The current activity component name as defined by + * queryIntentActivityOptions(). + * @param specifics Specific items to place first as defined by + * queryIntentActivityOptions(). + * @param intent Intent describing the kinds of items to populate in the + * list as defined by queryIntentActivityOptions(). + * @param flags Additional options controlling how the items are added. + * @param outSpecificItems Optional array in which to place the menu items + * that were generated for each of the specifics that were + * requested. Entries may be null if no activity was found for that + * specific action. + * @return The number of menu items that were added. + * + * @see #FLAG_APPEND_TO_GROUP + * @see MenuItem#setIntent + * @see android.content.pm.PackageManager#queryIntentActivityOptions + */ + public int addIntentOptions(int groupId, int itemId, int order, + ComponentName caller, Intent[] specifics, + Intent intent, int flags, MenuItem[] outSpecificItems); + + /** + * Remove the item with the given identifier. + * + * @param id The item to be removed. If there is no item with this + * identifier, nothing happens. + */ + public void removeItem(int id); + + /** + * Remove all items in the given group. + * + * @param groupId The group to be removed. If there are no items in this + * group, nothing happens. + */ + public void removeGroup(int groupId); + + /** + * Remove all existing items from the menu, leaving it empty as if it had + * just been created. + */ + public void clear(); + + /** + * Control whether a particular group of items can show a check mark. This + * is similar to calling {@link MenuItem#setCheckable} on all of the menu items + * with the given group identifier, but in addition you can control whether + * this group contains a mutually-exclusive set items. This should be called + * after the items of the group have been added to the menu. + * + * @param group The group of items to operate on. + * @param checkable Set to true to allow a check mark, false to + * disallow. The default is false. + * @param exclusive If set to true, only one item in this group can be + * checked at a time; checking an item will automatically + * uncheck all others in the group. If set to false, each + * item can be checked independently of the others. + * + * @see MenuItem#setCheckable + * @see MenuItem#setChecked + */ + public void setGroupCheckable(int group, boolean checkable, boolean exclusive); + + /** + * Show or hide all menu items that are in the given group. + * + * @param group The group of items to operate on. + * @param visible If true the items are visible, else they are hidden. + * + * @see MenuItem#setVisible + */ + public void setGroupVisible(int group, boolean visible); + + /** + * Enable or disable all menu items that are in the given group. + * + * @param group The group of items to operate on. + * @param enabled If true the items will be enabled, else they will be disabled. + * + * @see MenuItem#setEnabled + */ + public void setGroupEnabled(int group, boolean enabled); + + /** + * Return whether the menu currently has item items that are visible. + * + * @return True if there is one or more item visible, + * else false. + */ + public boolean hasVisibleItems(); + + /** + * Return the menu item with a particular identifier. + * + * @param id The identifier to find. + * + * @return The menu item object, or null if there is no item with + * this identifier. + */ + public MenuItem findItem(int id); + + /** + * Get the number of items in the menu. Note that this will change any + * times items are added or removed from the menu. + * + * @return The item count. + */ + public int size(); + + /** + * Gets the menu item at the given index. + * + * @param index The index of the menu item to return. + * @return The menu item. + * @exception IndexOutOfBoundsException + * when {@code index < 0 || >= size()} + */ + public MenuItem getItem(int index); + + /** + * Closes the menu, if open. + */ + public void close(); + + /** + * Execute the menu item action associated with the given shortcut + * character. + * + * @param keyCode The keycode of the shortcut key. + * @param event Key event message. + * @param flags Additional option flags or 0. + * + * @return If the given shortcut exists and is shown, returns + * true; else returns false. + * + * @see #FLAG_PERFORM_NO_CLOSE + */ + public boolean performShortcut(int keyCode, KeyEvent event, int flags); + + /** + * Is a keypress one of the defined shortcut keys for this window. + * @param keyCode the key code from {@link KeyEvent} to check. + * @param event the {@link KeyEvent} to use to help check. + */ + boolean isShortcutKey(int keyCode, KeyEvent event); + + /** + * Execute the menu item action associated with the given menu identifier. + * + * @param id Identifier associated with the menu item. + * @param flags Additional option flags or 0. + * + * @return If the given identifier exists and is shown, returns + * true; else returns false. + * + * @see #FLAG_PERFORM_NO_CLOSE + */ + public boolean performIdentifierAction(int id, int flags); + + + /** + * Control whether the menu should be running in qwerty mode (alphabetic + * shortcuts) or 12-key mode (numeric shortcuts). + * + * @param isQwerty If true the menu will use alphabetic shortcuts; else it + * will use numeric shortcuts. + */ + public void setQwertyMode(boolean isQwerty); +} + diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MenuInflater.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/MenuInflater.java similarity index 50% rename from external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MenuInflater.java rename to external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/MenuInflater.java index f32a2aa1..5a0f4085 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/MenuInflater.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/MenuInflater.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package android.support.v4.view; +package com.actionbarsherlock.view; import java.io.IOException; import java.lang.reflect.Constructor; @@ -23,15 +23,17 @@ import java.lang.reflect.Method; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.content.Context; +import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; import android.util.Xml; import android.view.InflateException; -import android.view.MenuItem; import android.view.View; -import com.actionbarsherlock.internal.view.menu.MenuBuilder; + +import com.actionbarsherlock.R; import com.actionbarsherlock.internal.view.menu.MenuItemImpl; -import com.actionbarsherlock.internal.view.menu.SubMenuBuilder; /** * This class is used to instantiate menu XML files into Menu objects. @@ -42,12 +44,8 @@ import com.actionbarsherlock.internal.view.menu.SubMenuBuilder; * it only works with an XmlPullParser returned from a compiled resource (R. * something file.) */ -public final class MenuInflater extends android.view.MenuInflater { - private static final Class[] ACTION_VIEW_CONSTRUCTOR_SIGNATURE = new Class[] { Context.class }; - private static final Class[] PARAM_TYPES = new Class[] { android.view.MenuItem.class }; - - /** Android XML namespace. */ - private static final String XML_NS = "http://schemas.android.com/apk/res/android"; +public class MenuInflater { + private static final String LOG_TAG = "MenuInflater"; /** Menu tag name in XML. */ private static final String XML_MENU = "menu"; @@ -58,25 +56,43 @@ public final class MenuInflater extends android.view.MenuInflater { /** Item tag name in XML. */ private static final String XML_ITEM = "item"; + private static final int NO_ID = 0; + + private static final Class[] ACTION_VIEW_CONSTRUCTOR_SIGNATURE = new Class[] {Context.class}; - /** Context from which to inflate resources. */ - private final Context mContext; + private static final Class[] ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE = ACTION_VIEW_CONSTRUCTOR_SIGNATURE; - /** Native inflater for context menu fallback. */ - private final android.view.MenuInflater mNativeMenuInflater; + private final Object[] mActionViewConstructorArguments; + private final Object[] mActionProviderConstructorArguments; + + private Context mContext; + private Object mRealOwner; /** * Constructs a menu inflater. * * @see Activity#getMenuInflater() */ - public MenuInflater(Context context, android.view.MenuInflater nativeMenuInflater) { - super(context); + public MenuInflater(Context context) { mContext = context; - mNativeMenuInflater = nativeMenuInflater; + mRealOwner = context; + mActionViewConstructorArguments = new Object[] {context}; + mActionProviderConstructorArguments = mActionViewConstructorArguments; } + /** + * Constructs a menu inflater. + * + * @see Activity#getMenuInflater() + * @hide + */ + public MenuInflater(Context context, Object realOwner) { + mContext = context; + mRealOwner = realOwner; + mActionViewConstructorArguments = new Object[] {context}; + mActionProviderConstructorArguments = mActionViewConstructorArguments; + } /** * Inflate a menu hierarchy from the specified XML resource. Throws @@ -87,20 +103,13 @@ public final class MenuInflater extends android.view.MenuInflater { * @param menu The Menu to inflate into. The items and submenus will be * added to this Menu. */ - @Override - public void inflate(int menuRes, android.view.Menu menu) { - if (!(menu instanceof MenuBuilder)) { - mNativeMenuInflater.inflate(menuRes, menu); - return; - } - - MenuBuilder actionBarMenu = (MenuBuilder)menu; + public void inflate(int menuRes, Menu menu) { XmlResourceParser parser = null; try { parser = mContext.getResources().getLayout(menuRes); AttributeSet attrs = Xml.asAttributeSet(parser); - parseMenu(parser, attrs, actionBarMenu); + parseMenu(parser, attrs, menu); } catch (XmlPullParserException e) { throw new InflateException("Error inflating menu XML", e); } catch (IOException e) { @@ -114,9 +123,9 @@ public final class MenuInflater extends android.view.MenuInflater { * Called internally to fill the given menu. If a sub menu is seen, it will * call this recursively. */ - private void parseMenu(XmlPullParser parser, AttributeSet attrs, MenuBuilder menu) + private void parseMenu(XmlPullParser parser, AttributeSet attrs, Menu menu) throws XmlPullParserException, IOException { - ActionBarMenuState menuState = new ActionBarMenuState(menu); + MenuState menuState = new MenuState(menu); int eventType = parser.getEventType(); String tagName; @@ -153,7 +162,7 @@ public final class MenuInflater extends android.view.MenuInflater { menuState.readItem(attrs); } else if (tagName.equals(XML_MENU)) { // A menu start tag denotes a submenu for an item - SubMenuBuilder subMenu = menuState.addSubMenuItem(); + SubMenu subMenu = menuState.addSubMenuItem(); // Parse the submenu into returned SubMenu parseMenu(parser, attrs, subMenu); @@ -174,7 +183,12 @@ public final class MenuInflater extends android.view.MenuInflater { // Add the item if it hasn't been added (if the item was // a submenu, it would have been added already) if (!menuState.hasAddedItem()) { - menuState.addItem(); + if (menuState.itemActionProvider != null && + menuState.itemActionProvider.hasSubMenu()) { + menuState.addSubMenuItem(); + } else { + menuState.addItem(); + } } } else if (tagName.equals(XML_MENU)) { reachedEndOfMenu = true; @@ -189,7 +203,40 @@ public final class MenuInflater extends android.view.MenuInflater { } } + private static class InflatedOnMenuItemClickListener + implements MenuItem.OnMenuItemClickListener { + private static final Class[] PARAM_TYPES = new Class[] { MenuItem.class }; + + private Object mRealOwner; + private Method mMethod; + + public InflatedOnMenuItemClickListener(Object realOwner, String methodName) { + mRealOwner = realOwner; + Class c = realOwner.getClass(); + try { + mMethod = c.getMethod(methodName, PARAM_TYPES); + } catch (Exception e) { + InflateException ex = new InflateException( + "Couldn't resolve menu item onClick handler " + methodName + + " in class " + c.getName()); + ex.initCause(e); + throw ex; + } + } + public boolean onMenuItemClick(MenuItem item) { + try { + if (mMethod.getReturnType() == Boolean.TYPE) { + return (Boolean) mMethod.invoke(mRealOwner, item); + } else { + mMethod.invoke(mRealOwner, item); + return true; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } /** * State for the current menu. @@ -197,8 +244,8 @@ public final class MenuInflater extends android.view.MenuInflater { * Groups can not be nested unless there is another menu (which will have * its state class). */ - private final class ActionBarMenuState { - private final MenuBuilder menu; + private class MenuState { + private Menu menu; /* * Group state is set on items as they are added, allowing an item to @@ -214,8 +261,8 @@ public final class MenuInflater extends android.view.MenuInflater { private boolean itemAdded; private int itemId; private int itemCategoryOrder; - private String itemTitle; - private String itemTitleCondensed; + private CharSequence itemTitle; + private CharSequence itemTitleCondensed; private int itemIconResId; private char itemAlphabeticShortcut; private char itemNumericShortcut; @@ -229,28 +276,34 @@ public final class MenuInflater extends android.view.MenuInflater { private boolean itemChecked; private boolean itemVisible; private boolean itemEnabled; - private String itemListenerMethodName; + + /** + * Sync to attrs.xml enum, values in MenuItem: + * - 0: never + * - 1: ifRoom + * - 2: always + * - -1: Safe sentinel for "no value". + */ private int itemShowAsAction; - private int itemActionLayout; + + private int itemActionViewLayout; private String itemActionViewClassName; + private String itemActionProviderClassName; + + private String itemListenerMethodName; + + private ActionProvider itemActionProvider; - private static final int defaultGroupId = View.NO_ID; - private static final int defaultItemId = View.NO_ID; + private static final int defaultGroupId = NO_ID; + private static final int defaultItemId = NO_ID; private static final int defaultItemCategory = 0; private static final int defaultItemOrder = 0; private static final int defaultItemCheckable = 0; private static final boolean defaultItemChecked = false; private static final boolean defaultItemVisible = true; private static final boolean defaultItemEnabled = true; - private static final int defaultItemShowAsAction = 0; - private static final int defaultIconResId = View.NO_ID; - - /** Mirror of package-scoped Menu.CATEGORY_MASK. */ - private static final int Menu__CATEGORY_MASK = 0xffff0000; - /** Mirror of package-scoped Menu.USER_MASK. */ - private static final int Menu__USER_MASK = 0x0000ffff; - public ActionBarMenuState(MenuBuilder menu) { + public MenuState(final Menu menu) { this.menu = menu; resetGroup(); @@ -269,101 +322,82 @@ public final class MenuInflater extends android.view.MenuInflater { * Called when the parser is pointing to a group tag. */ public void readGroup(AttributeSet attrs) { - //TypedArray a = mContext.obtainStyledAttributes(attrs, com.android.internal.R.styleable.MenuGroup); - - //groupId = a.getResourceId(com.android.internal.R.styleable.MenuGroup_id, defaultGroupId); - groupId = attrs.getAttributeResourceValue(XML_NS, "id", defaultGroupId); - - //groupCategory = a.getInt(com.android.internal.R.styleable.MenuGroup_menuCategory, defaultItemCategory); - groupCategory = attrs.getAttributeIntValue(XML_NS, "menuCategory", defaultItemCategory); + TypedArray a = mContext.obtainStyledAttributes(attrs, + R.styleable.SherlockMenuGroup); - //groupOrder = a.getInt(com.android.internal.R.styleable.MenuGroup_orderInCategory, defaultItemOrder); - groupOrder = attrs.getAttributeIntValue(XML_NS, "orderInCategory", defaultItemOrder); + groupId = a.getResourceId(R.styleable.SherlockMenuGroup_android_id, defaultGroupId); + groupCategory = a.getInt(R.styleable.SherlockMenuGroup_android_menuCategory, defaultItemCategory); + groupOrder = a.getInt(R.styleable.SherlockMenuGroup_android_orderInCategory, defaultItemOrder); + groupCheckable = a.getInt(R.styleable.SherlockMenuGroup_android_checkableBehavior, defaultItemCheckable); + groupVisible = a.getBoolean(R.styleable.SherlockMenuGroup_android_visible, defaultItemVisible); + groupEnabled = a.getBoolean(R.styleable.SherlockMenuGroup_android_enabled, defaultItemEnabled); - //groupCheckable = a.getInt(com.android.internal.R.styleable.MenuGroup_checkableBehavior, defaultItemCheckable); - groupCheckable = attrs.getAttributeIntValue(XML_NS, "checkableBehavior", defaultItemCheckable); - - //groupVisible = a.getBoolean(com.android.internal.R.styleable.MenuGroup_visible, defaultItemVisible); - groupVisible = attrs.getAttributeBooleanValue(XML_NS, "visible", defaultItemVisible); - - //groupEnabled = a.getBoolean(com.android.internal.R.styleable.MenuGroup_enabled, defaultItemEnabled); - groupEnabled = attrs.getAttributeBooleanValue(XML_NS, "enabled", defaultItemEnabled); - - //a.recycle(); + a.recycle(); } /** * Called when the parser is pointing to an item tag. */ public void readItem(AttributeSet attrs) { - //TypedArray a = mContext.obtainStyledAttributes(attrs, com.android.internal.R.styleable.MenuItem); + TypedArray a = mContext.obtainStyledAttributes(attrs, + R.styleable.SherlockMenuItem); // Inherit attributes from the group as default value - - //itemId = a.getResourceId(com.android.internal.R.styleable.MenuItem_id, defaultItemId); - itemId = attrs.getAttributeResourceValue(XML_NS, "id", defaultItemId); - - //final int category = a.getInt(com.android.internal.R.styleable.MenuItem_menuCategory, groupCategory); - final int category = attrs.getAttributeIntValue(XML_NS, "menuCategory", groupCategory); - - //final int order = a.getInt(com.android.internal.R.styleable.MenuItem_orderInCategory, groupOrder); - final int order = attrs.getAttributeIntValue(XML_NS, "orderInCategory", groupOrder); - - //itemCategoryOrder = (category & Menu.CATEGORY_MASK) | (order & Menu.USER_MASK); - itemCategoryOrder = (category & Menu__CATEGORY_MASK) | (order & Menu__USER_MASK); - - //itemTitle = a.getString(com.android.internal.R.styleable.MenuItem_title); - final int itemTitleId = attrs.getAttributeResourceValue(XML_NS, "title", 0); - if (itemTitleId != 0) { - itemTitle = mContext.getString(itemTitleId); - } else { - itemTitle = attrs.getAttributeValue(XML_NS, "title"); - } - - //itemTitleCondensed = a.getString(com.android.internal.R.styleable.MenuItem_titleCondensed); - final int itemTitleCondensedId = attrs.getAttributeResourceValue(XML_NS, "titleCondensed", 0); - if (itemTitleCondensedId != 0) { - itemTitleCondensed = mContext.getString(itemTitleCondensedId); - } else { - itemTitleCondensed = attrs.getAttributeValue(XML_NS, "titleCondensed"); - } - - //itemIconResId = a.getResourceId(com.android.internal.R.styleable.MenuItem_icon, 0); - itemIconResId = attrs.getAttributeResourceValue(XML_NS, "icon", defaultIconResId); - - //itemAlphabeticShortcut = getShortcut(a.getString(com.android.internal.R.styleable.MenuItem_alphabeticShortcut)); - itemAlphabeticShortcut = getShortcut(attrs.getAttributeValue(XML_NS, "alphabeticShortcut")); - - //itemNumericShortcut = getShortcut(a.getString(com.android.internal.R.styleable.MenuItem_numericShortcut)); - itemNumericShortcut = getShortcut(attrs.getAttributeValue(XML_NS, "numericShortcut")); - - //if (a.hasValue(com.android.internal.R.styleable.MenuItem_checkable)) { - if (attrs.getAttributeValue(XML_NS, "checkable") != null) { + itemId = a.getResourceId(R.styleable.SherlockMenuItem_android_id, defaultItemId); + final int category = a.getInt(R.styleable.SherlockMenuItem_android_menuCategory, groupCategory); + final int order = a.getInt(R.styleable.SherlockMenuItem_android_orderInCategory, groupOrder); + itemCategoryOrder = (category & Menu.CATEGORY_MASK) | (order & Menu.USER_MASK); + itemTitle = a.getText(R.styleable.SherlockMenuItem_android_title); + itemTitleCondensed = a.getText(R.styleable.SherlockMenuItem_android_titleCondensed); + itemIconResId = a.getResourceId(R.styleable.SherlockMenuItem_android_icon, 0); + itemAlphabeticShortcut = + getShortcut(a.getString(R.styleable.SherlockMenuItem_android_alphabeticShortcut)); + itemNumericShortcut = + getShortcut(a.getString(R.styleable.SherlockMenuItem_android_numericShortcut)); + if (a.hasValue(R.styleable.SherlockMenuItem_android_checkable)) { // Item has attribute checkable, use it - //itemCheckable = a.getBoolean(com.android.internal.R.styleable.MenuItem_checkable, false) ? 1 : 0; - itemCheckable = attrs.getAttributeBooleanValue(XML_NS, "checkable", false) ? 1 : 0; + itemCheckable = a.getBoolean(R.styleable.SherlockMenuItem_android_checkable, false) ? 1 : 0; } else { // Item does not have attribute, use the group's (group can have one more state // for checkable that represents the exclusive checkable) itemCheckable = groupCheckable; } - //itemChecked = a.getBoolean(com.android.internal.R.styleable.MenuItem_checked, defaultItemChecked); - itemChecked = attrs.getAttributeBooleanValue(XML_NS, "checked", defaultItemChecked); + itemChecked = a.getBoolean(R.styleable.SherlockMenuItem_android_checked, defaultItemChecked); + itemVisible = a.getBoolean(R.styleable.SherlockMenuItem_android_visible, groupVisible); + itemEnabled = a.getBoolean(R.styleable.SherlockMenuItem_android_enabled, groupEnabled); + + TypedValue value = new TypedValue(); + a.getValue(R.styleable.SherlockMenuItem_android_showAsAction, value); + itemShowAsAction = value.type == TypedValue.TYPE_INT_HEX ? value.data : -1; - //itemVisible = a.getBoolean(com.android.internal.R.styleable.MenuItem_visible, groupVisible); - itemVisible = attrs.getAttributeBooleanValue(XML_NS, "visible", groupVisible); + itemListenerMethodName = a.getString(R.styleable.SherlockMenuItem_android_onClick); + itemActionViewLayout = a.getResourceId(R.styleable.SherlockMenuItem_android_actionLayout, 0); - //itemEnabled = a.getBoolean(com.android.internal.R.styleable.MenuItem_enabled, groupEnabled); - itemEnabled = attrs.getAttributeBooleanValue(XML_NS, "enabled", groupEnabled); + // itemActionViewClassName = a.getString(R.styleable.SherlockMenuItem_android_actionViewClass); + value = new TypedValue(); + a.getValue(R.styleable.SherlockMenuItem_android_actionViewClass, value); + itemActionViewClassName = value.type == TypedValue.TYPE_STRING ? value.string.toString() : null; - //presumed emulation of 3.0+'s MenuInflator: - itemListenerMethodName = attrs.getAttributeValue(XML_NS, "onClick"); - itemShowAsAction = attrs.getAttributeIntValue(XML_NS, "showAsAction", defaultItemShowAsAction); - itemActionLayout = attrs.getAttributeResourceValue(XML_NS, "actionLayout", 0); - itemActionViewClassName = attrs.getAttributeValue(XML_NS, "actionViewClass"); + // itemActionProviderClassName = a.getString(R.styleable.SherlockMenuItem_android_actionProviderClass); + value = new TypedValue(); + a.getValue(R.styleable.SherlockMenuItem_android_actionProviderClass, value); + itemActionProviderClassName = value.type == TypedValue.TYPE_STRING ? value.string.toString() : null; + + final boolean hasActionProvider = itemActionProviderClassName != null; + if (hasActionProvider && itemActionViewLayout == 0 && itemActionViewClassName == null) { + itemActionProvider = newInstance(itemActionProviderClassName, + ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE, + mActionProviderConstructorArguments); + } else { + if (hasActionProvider) { + Log.w(LOG_TAG, "Ignoring attribute 'actionProviderClass'." + + " Action view already specified."); + } + itemActionProvider = null; + } - //a.recycle(); + a.recycle(); itemAdded = false; } @@ -376,7 +410,7 @@ public final class MenuInflater extends android.view.MenuInflater { } } - private void setItem(MenuItemImpl item) { + private void setItem(MenuItem item) { item.setChecked(itemChecked) .setVisible(itemVisible) .setEnabled(itemEnabled) @@ -386,42 +420,57 @@ public final class MenuInflater extends android.view.MenuInflater { .setAlphabeticShortcut(itemAlphabeticShortcut) .setNumericShortcut(itemNumericShortcut); - if (itemShowAsAction > 0) { + if (itemShowAsAction >= 0) { item.setShowAsAction(itemShowAsAction); } + if (itemListenerMethodName != null) { - if (MenuInflater.this.mContext.isRestricted()) { - throw new IllegalStateException("The android:onClick attribute cannot be used within a restricted context"); + if (mContext.isRestricted()) { + throw new IllegalStateException("The android:onClick attribute cannot " + + "be used within a restricted context"); } - item.setOnMenuItemClickListener(new InflatedOnMenuItemClickListener(itemListenerMethodName)); + item.setOnMenuItemClickListener( + new InflatedOnMenuItemClickListener(mRealOwner, itemListenerMethodName)); } + if (itemCheckable >= 2) { - item.setExclusiveCheckable(true); + if (item instanceof MenuItemImpl) { + MenuItemImpl impl = (MenuItemImpl) item; + impl.setExclusiveCheckable(true); + } else { + menu.setGroupCheckable(groupId, true, true); + } } + + boolean actionViewSpecified = false; if (itemActionViewClassName != null) { - try { - Context context = MenuInflater.this.mContext; - ClassLoader loader = context.getClassLoader(); - Class actionViewClass = Class.forName(itemActionViewClassName, true, loader); - Constructor constructor = actionViewClass.getConstructor(ACTION_VIEW_CONSTRUCTOR_SIGNATURE); - View actionView = (View)constructor.newInstance(new Object[] { context }); - item.setActionView(actionView); - } catch (Exception e) { - throw new InflateException(e); + View actionView = (View) newInstance(itemActionViewClassName, + ACTION_VIEW_CONSTRUCTOR_SIGNATURE, mActionViewConstructorArguments); + item.setActionView(actionView); + actionViewSpecified = true; + } + if (itemActionViewLayout > 0) { + if (!actionViewSpecified) { + item.setActionView(itemActionViewLayout); + actionViewSpecified = true; + } else { + Log.w(LOG_TAG, "Ignoring attribute 'itemActionViewLayout'." + + " Action view already specified."); } - } else if (itemActionLayout > 0) { - item.setActionView(itemActionLayout); + } + if (itemActionProvider != null) { + item.setActionProvider(itemActionProvider); } } public void addItem() { itemAdded = true; - setItem((MenuItemImpl)menu.add(groupId, itemId, itemCategoryOrder, itemTitle)); + setItem(menu.add(groupId, itemId, itemCategoryOrder, itemTitle)); } - public SubMenuBuilder addSubMenuItem() { + public SubMenu addSubMenuItem() { itemAdded = true; - SubMenuBuilder subMenu = menu.addSubMenu(groupId, itemId, itemCategoryOrder, itemTitle); + SubMenu subMenu = menu.addSubMenu(groupId, itemId, itemCategoryOrder, itemTitle); setItem(subMenu.getItem()); return subMenu; } @@ -429,36 +478,18 @@ public final class MenuInflater extends android.view.MenuInflater { public boolean hasAddedItem() { return itemAdded; } - } - - class InflatedOnMenuItemClickListener implements android.view.MenuItem.OnMenuItemClickListener { - private Method mMethod; - - public InflatedOnMenuItemClickListener(String methodName) { - final Class localClass = MenuInflater.this.getClass(); - try { - mMethod = localClass.getMethod(methodName, PARAM_TYPES); - } catch (Exception e) { - StringBuilder b = new StringBuilder(); - b.append("Couldn't resolve menu item onClick handler "); - b.append(methodName); - b.append(" in class "); - b.append(localClass.getName()); - throw new InflateException(b.toString(), e); - } - } - @Override - public boolean onMenuItemClick(MenuItem item) { - final Object[] params = new Object[] { item }; + @SuppressWarnings("unchecked") + private T newInstance(String className, Class[] constructorSignature, + Object[] arguments) { try { - if (mMethod.getReturnType() == Boolean.TYPE) { - return (Boolean)mMethod.invoke(MenuInflater.this, params); - } - return false; + Class clazz = mContext.getClassLoader().loadClass(className); + Constructor constructor = clazz.getConstructor(constructorSignature); + return (T) constructor.newInstance(arguments); } catch (Exception e) { - throw new RuntimeException(e); + Log.w(LOG_TAG, "Cannot instantiate class: " + className, e); } + return null; } } -} \ No newline at end of file +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/MenuItem.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/MenuItem.java new file mode 100644 index 00000000..7fc3aa43 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/MenuItem.java @@ -0,0 +1,598 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.view; + +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.View; + +/** + * Interface for direct access to a previously created menu item. + *

+ * An Item is returned by calling one of the {@link android.view.Menu#add} + * methods. + *

+ * For a feature set of specific menu types, see {@link Menu}. + * + *

+ *

Developer Guides

+ *

For information about creating menus, read the + * Menus developer guide.

+ *
+ */ +public interface MenuItem { + /* + * These should be kept in sync with attrs.xml enum constants for showAsAction + */ + /** Never show this item as a button in an Action Bar. */ + public static final int SHOW_AS_ACTION_NEVER = android.view.MenuItem.SHOW_AS_ACTION_NEVER; + /** Show this item as a button in an Action Bar if the system decides there is room for it. */ + public static final int SHOW_AS_ACTION_IF_ROOM = android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM; + /** + * Always show this item as a button in an Action Bar. + * Use sparingly! If too many items are set to always show in the Action Bar it can + * crowd the Action Bar and degrade the user experience on devices with smaller screens. + * A good rule of thumb is to have no more than 2 items set to always show at a time. + */ + public static final int SHOW_AS_ACTION_ALWAYS = android.view.MenuItem.SHOW_AS_ACTION_ALWAYS; + + /** + * When this item is in the action bar, always show it with a text label even if + * it also has an icon specified. + */ + public static final int SHOW_AS_ACTION_WITH_TEXT = android.view.MenuItem.SHOW_AS_ACTION_WITH_TEXT; + + /** + * This item's action view collapses to a normal menu item. + * When expanded, the action view temporarily takes over + * a larger segment of its container. + */ + public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = android.view.MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW; + + /** + * Interface definition for a callback to be invoked when a menu item is + * clicked. + * + * @see Activity#onContextItemSelected(MenuItem) + * @see Activity#onOptionsItemSelected(MenuItem) + */ + public interface OnMenuItemClickListener { + /** + * Called when a menu item has been invoked. This is the first code + * that is executed; if it returns true, no other callbacks will be + * executed. + * + * @param item The menu item that was invoked. + * + * @return Return true to consume this click and prevent others from + * executing. + */ + public boolean onMenuItemClick(MenuItem item); + } + + /** + * Interface definition for a callback to be invoked when a menu item + * marked with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW} is + * expanded or collapsed. + * + * @see MenuItem#expandActionView() + * @see MenuItem#collapseActionView() + * @see MenuItem#setShowAsActionFlags(int) + */ + public interface OnActionExpandListener { + /** + * Called when a menu item with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW} + * is expanded. + * @param item Item that was expanded + * @return true if the item should expand, false if expansion should be suppressed. + */ + public boolean onMenuItemActionExpand(MenuItem item); + + /** + * Called when a menu item with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW} + * is collapsed. + * @param item Item that was collapsed + * @return true if the item should collapse, false if collapsing should be suppressed. + */ + public boolean onMenuItemActionCollapse(MenuItem item); + } + + /** + * Return the identifier for this menu item. The identifier can not + * be changed after the menu is created. + * + * @return The menu item's identifier. + */ + public int getItemId(); + + /** + * Return the group identifier that this menu item is part of. The group + * identifier can not be changed after the menu is created. + * + * @return The menu item's group identifier. + */ + public int getGroupId(); + + /** + * Return the category and order within the category of this item. This + * item will be shown before all items (within its category) that have + * order greater than this value. + *

+ * An order integer contains the item's category (the upper bits of the + * integer; set by or/add the category with the order within the + * category) and the ordering of the item within that category (the + * lower bits). Example categories are {@link Menu#CATEGORY_SYSTEM}, + * {@link Menu#CATEGORY_SECONDARY}, {@link Menu#CATEGORY_ALTERNATIVE}, + * {@link Menu#CATEGORY_CONTAINER}. See {@link Menu} for a full list. + * + * @return The order of this item. + */ + public int getOrder(); + + /** + * Change the title associated with this item. + * + * @param title The new text to be displayed. + * @return This Item so additional setters can be called. + */ + public MenuItem setTitle(CharSequence title); + + /** + * Change the title associated with this item. + *

+ * Some menu types do not sufficient space to show the full title, and + * instead a condensed title is preferred. See {@link Menu} for more + * information. + * + * @param title The resource id of the new text to be displayed. + * @return This Item so additional setters can be called. + * @see #setTitleCondensed(CharSequence) + */ + + public MenuItem setTitle(int title); + + /** + * Retrieve the current title of the item. + * + * @return The title. + */ + public CharSequence getTitle(); + + /** + * Change the condensed title associated with this item. The condensed + * title is used in situations where the normal title may be too long to + * be displayed. + * + * @param title The new text to be displayed as the condensed title. + * @return This Item so additional setters can be called. + */ + public MenuItem setTitleCondensed(CharSequence title); + + /** + * Retrieve the current condensed title of the item. If a condensed + * title was never set, it will return the normal title. + * + * @return The condensed title, if it exists. + * Otherwise the normal title. + */ + public CharSequence getTitleCondensed(); + + /** + * Change the icon associated with this item. This icon will not always be + * shown, so the title should be sufficient in describing this item. See + * {@link Menu} for the menu types that support icons. + * + * @param icon The new icon (as a Drawable) to be displayed. + * @return This Item so additional setters can be called. + */ + public MenuItem setIcon(Drawable icon); + + /** + * Change the icon associated with this item. This icon will not always be + * shown, so the title should be sufficient in describing this item. See + * {@link Menu} for the menu types that support icons. + *

+ * This method will set the resource ID of the icon which will be used to + * lazily get the Drawable when this item is being shown. + * + * @param iconRes The new icon (as a resource ID) to be displayed. + * @return This Item so additional setters can be called. + */ + public MenuItem setIcon(int iconRes); + + /** + * Returns the icon for this item as a Drawable (getting it from resources if it hasn't been + * loaded before). + * + * @return The icon as a Drawable. + */ + public Drawable getIcon(); + + /** + * Change the Intent associated with this item. By default there is no + * Intent associated with a menu item. If you set one, and nothing + * else handles the item, then the default behavior will be to call + * {@link android.content.Context#startActivity} with the given Intent. + * + *

Note that setIntent() can not be used with the versions of + * {@link Menu#add} that take a Runnable, because {@link Runnable#run} + * does not return a value so there is no way to tell if it handled the + * item. In this case it is assumed that the Runnable always handles + * the item, and the intent will never be started. + * + * @see #getIntent + * @param intent The Intent to associated with the item. This Intent + * object is not copied, so be careful not to + * modify it later. + * @return This Item so additional setters can be called. + */ + public MenuItem setIntent(Intent intent); + + /** + * Return the Intent associated with this item. This returns a + * reference to the Intent which you can change as desired to modify + * what the Item is holding. + * + * @see #setIntent + * @return Returns the last value supplied to {@link #setIntent}, or + * null. + */ + public Intent getIntent(); + + /** + * Change both the numeric and alphabetic shortcut associated with this + * item. Note that the shortcut will be triggered when the key that + * generates the given character is pressed alone or along with with the alt + * key. Also note that case is not significant and that alphabetic shortcut + * characters will be displayed in lower case. + *

+ * See {@link Menu} for the menu types that support shortcuts. + * + * @param numericChar The numeric shortcut key. This is the shortcut when + * using a numeric (e.g., 12-key) keyboard. + * @param alphaChar The alphabetic shortcut key. This is the shortcut when + * using a keyboard with alphabetic keys. + * @return This Item so additional setters can be called. + */ + public MenuItem setShortcut(char numericChar, char alphaChar); + + /** + * Change the numeric shortcut associated with this item. + *

+ * See {@link Menu} for the menu types that support shortcuts. + * + * @param numericChar The numeric shortcut key. This is the shortcut when + * using a 12-key (numeric) keyboard. + * @return This Item so additional setters can be called. + */ + public MenuItem setNumericShortcut(char numericChar); + + /** + * Return the char for this menu item's numeric (12-key) shortcut. + * + * @return Numeric character to use as a shortcut. + */ + public char getNumericShortcut(); + + /** + * Change the alphabetic shortcut associated with this item. The shortcut + * will be triggered when the key that generates the given character is + * pressed alone or along with with the alt key. Case is not significant and + * shortcut characters will be displayed in lower case. Note that menu items + * with the characters '\b' or '\n' as shortcuts will get triggered by the + * Delete key or Carriage Return key, respectively. + *

+ * See {@link Menu} for the menu types that support shortcuts. + * + * @param alphaChar The alphabetic shortcut key. This is the shortcut when + * using a keyboard with alphabetic keys. + * @return This Item so additional setters can be called. + */ + public MenuItem setAlphabeticShortcut(char alphaChar); + + /** + * Return the char for this menu item's alphabetic shortcut. + * + * @return Alphabetic character to use as a shortcut. + */ + public char getAlphabeticShortcut(); + + /** + * Control whether this item can display a check mark. Setting this does + * not actually display a check mark (see {@link #setChecked} for that); + * rather, it ensures there is room in the item in which to display a + * check mark. + *

+ * See {@link Menu} for the menu types that support check marks. + * + * @param checkable Set to true to allow a check mark, false to + * disallow. The default is false. + * @see #setChecked + * @see #isCheckable + * @see Menu#setGroupCheckable + * @return This Item so additional setters can be called. + */ + public MenuItem setCheckable(boolean checkable); + + /** + * Return whether the item can currently display a check mark. + * + * @return If a check mark can be displayed, returns true. + * + * @see #setCheckable + */ + public boolean isCheckable(); + + /** + * Control whether this item is shown with a check mark. Note that you + * must first have enabled checking with {@link #setCheckable} or else + * the check mark will not appear. If this item is a member of a group that contains + * mutually-exclusive items (set via {@link Menu#setGroupCheckable(int, boolean, boolean)}, + * the other items in the group will be unchecked. + *

+ * See {@link Menu} for the menu types that support check marks. + * + * @see #setCheckable + * @see #isChecked + * @see Menu#setGroupCheckable + * @param checked Set to true to display a check mark, false to hide + * it. The default value is false. + * @return This Item so additional setters can be called. + */ + public MenuItem setChecked(boolean checked); + + /** + * Return whether the item is currently displaying a check mark. + * + * @return If a check mark is displayed, returns true. + * + * @see #setChecked + */ + public boolean isChecked(); + + /** + * Sets the visibility of the menu item. Even if a menu item is not visible, + * it may still be invoked via its shortcut (to completely disable an item, + * set it to invisible and {@link #setEnabled(boolean) disabled}). + * + * @param visible If true then the item will be visible; if false it is + * hidden. + * @return This Item so additional setters can be called. + */ + public MenuItem setVisible(boolean visible); + + /** + * Return the visibility of the menu item. + * + * @return If true the item is visible; else it is hidden. + */ + public boolean isVisible(); + + /** + * Sets whether the menu item is enabled. Disabling a menu item will not + * allow it to be invoked via its shortcut. The menu item will still be + * visible. + * + * @param enabled If true then the item will be invokable; if false it is + * won't be invokable. + * @return This Item so additional setters can be called. + */ + public MenuItem setEnabled(boolean enabled); + + /** + * Return the enabled state of the menu item. + * + * @return If true the item is enabled and hence invokable; else it is not. + */ + public boolean isEnabled(); + + /** + * Check whether this item has an associated sub-menu. I.e. it is a + * sub-menu of another menu. + * + * @return If true this item has a menu; else it is a + * normal item. + */ + public boolean hasSubMenu(); + + /** + * Get the sub-menu to be invoked when this item is selected, if it has + * one. See {@link #hasSubMenu()}. + * + * @return The associated menu if there is one, else null + */ + public SubMenu getSubMenu(); + + /** + * Set a custom listener for invocation of this menu item. In most + * situations, it is more efficient and easier to use + * {@link Activity#onOptionsItemSelected(MenuItem)} or + * {@link Activity#onContextItemSelected(MenuItem)}. + * + * @param menuItemClickListener The object to receive invokations. + * @return This Item so additional setters can be called. + * @see Activity#onOptionsItemSelected(MenuItem) + * @see Activity#onContextItemSelected(MenuItem) + */ + public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener menuItemClickListener); + + /** + * Gets the extra information linked to this menu item. This extra + * information is set by the View that added this menu item to the + * menu. + * + * @see OnCreateContextMenuListener + * @return The extra information linked to the View that added this + * menu item to the menu. This can be null. + */ + public ContextMenuInfo getMenuInfo(); + + /** + * Sets how this item should display in the presence of an Action Bar. + * The parameter actionEnum is a flag set. One of {@link #SHOW_AS_ACTION_ALWAYS}, + * {@link #SHOW_AS_ACTION_IF_ROOM}, or {@link #SHOW_AS_ACTION_NEVER} should + * be used, and you may optionally OR the value with {@link #SHOW_AS_ACTION_WITH_TEXT}. + * SHOW_AS_ACTION_WITH_TEXT requests that when the item is shown as an action, + * it should be shown with a text label. + * + * @param actionEnum How the item should display. One of + * {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or + * {@link #SHOW_AS_ACTION_NEVER}. SHOW_AS_ACTION_NEVER is the default. + * + * @see android.app.ActionBar + * @see #setActionView(View) + */ + public void setShowAsAction(int actionEnum); + + /** + * Sets how this item should display in the presence of an Action Bar. + * The parameter actionEnum is a flag set. One of {@link #SHOW_AS_ACTION_ALWAYS}, + * {@link #SHOW_AS_ACTION_IF_ROOM}, or {@link #SHOW_AS_ACTION_NEVER} should + * be used, and you may optionally OR the value with {@link #SHOW_AS_ACTION_WITH_TEXT}. + * SHOW_AS_ACTION_WITH_TEXT requests that when the item is shown as an action, + * it should be shown with a text label. + * + *

Note: This method differs from {@link #setShowAsAction(int)} only in that it + * returns the current MenuItem instance for call chaining. + * + * @param actionEnum How the item should display. One of + * {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or + * {@link #SHOW_AS_ACTION_NEVER}. SHOW_AS_ACTION_NEVER is the default. + * + * @see android.app.ActionBar + * @see #setActionView(View) + * @return This MenuItem instance for call chaining. + */ + public MenuItem setShowAsActionFlags(int actionEnum); + + /** + * Set an action view for this menu item. An action view will be displayed in place + * of an automatically generated menu item element in the UI when this item is shown + * as an action within a parent. + *

+ * Note: Setting an action view overrides the action provider + * set via {@link #setActionProvider(ActionProvider)}. + *

+ * + * @param view View to use for presenting this item to the user. + * @return This Item so additional setters can be called. + * + * @see #setShowAsAction(int) + */ + public MenuItem setActionView(View view); + + /** + * Set an action view for this menu item. An action view will be displayed in place + * of an automatically generated menu item element in the UI when this item is shown + * as an action within a parent. + *

+ * Note: Setting an action view overrides the action provider + * set via {@link #setActionProvider(ActionProvider)}. + *

+ * + * @param resId Layout resource to use for presenting this item to the user. + * @return This Item so additional setters can be called. + * + * @see #setShowAsAction(int) + */ + public MenuItem setActionView(int resId); + + /** + * Returns the currently set action view for this menu item. + * + * @return This item's action view + * + * @see #setActionView(View) + * @see #setShowAsAction(int) + */ + public View getActionView(); + + /** + * Sets the {@link ActionProvider} responsible for creating an action view if + * the item is placed on the action bar. The provider also provides a default + * action invoked if the item is placed in the overflow menu. + *

+ * Note: Setting an action provider overrides the action view + * set via {@link #setActionView(int)} or {@link #setActionView(View)}. + *

+ * + * @param actionProvider The action provider. + * @return This Item so additional setters can be called. + * + * @see ActionProvider + */ + public MenuItem setActionProvider(ActionProvider actionProvider); + + /** + * Gets the {@link ActionProvider}. + * + * @return The action provider. + * + * @see ActionProvider + * @see #setActionProvider(ActionProvider) + */ + public ActionProvider getActionProvider(); + + /** + * Expand the action view associated with this menu item. + * The menu item must have an action view set, as well as + * the showAsAction flag {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}. + * If a listener has been set using {@link #setOnActionExpandListener(OnActionExpandListener)} + * it will have its {@link OnActionExpandListener#onMenuItemActionExpand(MenuItem)} + * method invoked. The listener may return false from this method to prevent expanding + * the action view. + * + * @return true if the action view was expanded, false otherwise. + */ + public boolean expandActionView(); + + /** + * Collapse the action view associated with this menu item. + * The menu item must have an action view set, as well as the showAsAction flag + * {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}. If a listener has been set using + * {@link #setOnActionExpandListener(OnActionExpandListener)} it will have its + * {@link OnActionExpandListener#onMenuItemActionCollapse(MenuItem)} method invoked. + * The listener may return false from this method to prevent collapsing the action view. + * + * @return true if the action view was collapsed, false otherwise. + */ + public boolean collapseActionView(); + + /** + * Returns true if this menu item's action view has been expanded. + * + * @return true if the item's action view is expanded, false otherwise. + * + * @see #expandActionView() + * @see #collapseActionView() + * @see #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW + * @see OnActionExpandListener + */ + public boolean isActionViewExpanded(); + + /** + * Set an {@link OnActionExpandListener} on this menu item to be notified when + * the associated action view is expanded or collapsed. The menu item must + * be configured to expand or collapse its action view using the flag + * {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}. + * + * @param listener Listener that will respond to expand/collapse events + * @return This menu item instance for call chaining + */ + public MenuItem setOnActionExpandListener(OnActionExpandListener listener); +} \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/SubMenu.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/SubMenu.java new file mode 100644 index 00000000..397fd1c2 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/SubMenu.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.view; + +import android.graphics.drawable.Drawable; +import android.view.View; + +/** + * Subclass of {@link Menu} for sub menus. + *

+ * Sub menus do not support item icons, or nested sub menus. + * + *

+ *

Developer Guides

+ *

For information about creating menus, read the + * Menus developer guide.

+ *
+ */ + +public interface SubMenu extends Menu { + /** + * Sets the submenu header's title to the title given in titleRes + * resource identifier. + * + * @param titleRes The string resource identifier used for the title. + * @return This SubMenu so additional setters can be called. + */ + public SubMenu setHeaderTitle(int titleRes); + + /** + * Sets the submenu header's title to the title given in title. + * + * @param title The character sequence used for the title. + * @return This SubMenu so additional setters can be called. + */ + public SubMenu setHeaderTitle(CharSequence title); + + /** + * Sets the submenu header's icon to the icon given in iconRes + * resource id. + * + * @param iconRes The resource identifier used for the icon. + * @return This SubMenu so additional setters can be called. + */ + public SubMenu setHeaderIcon(int iconRes); + + /** + * Sets the submenu header's icon to the icon given in icon + * {@link Drawable}. + * + * @param icon The {@link Drawable} used for the icon. + * @return This SubMenu so additional setters can be called. + */ + public SubMenu setHeaderIcon(Drawable icon); + + /** + * Sets the header of the submenu to the {@link View} given in + * view. This replaces the header title and icon (and those + * replace this). + * + * @param view The {@link View} used for the header. + * @return This SubMenu so additional setters can be called. + */ + public SubMenu setHeaderView(View view); + + /** + * Clears the header of the submenu. + */ + public void clearHeader(); + + /** + * Change the icon associated with this submenu's item in its parent menu. + * + * @see MenuItem#setIcon(int) + * @param iconRes The new icon (as a resource ID) to be displayed. + * @return This SubMenu so additional setters can be called. + */ + public SubMenu setIcon(int iconRes); + + /** + * Change the icon associated with this submenu's item in its parent menu. + * + * @see MenuItem#setIcon(Drawable) + * @param icon The new icon (as a Drawable) to be displayed. + * @return This SubMenu so additional setters can be called. + */ + public SubMenu setIcon(Drawable icon); + + /** + * Gets the {@link MenuItem} that represents this submenu in the parent + * menu. Use this for setting additional item attributes. + * + * @return The {@link MenuItem} that launches the submenu when invoked. + */ + public MenuItem getItem(); +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/Window.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/Window.java similarity index 51% rename from external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/Window.java rename to external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/Window.java index f2a6400e..a340a429 100644 --- a/external/JakeWharton-ActionBarSherlock/library/src/android/support/v4/view/Window.java +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/view/Window.java @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 The Android Open Source Project - * 2011 Jake Wharton + * Copyright (C) 2011 Jake Wharton * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ * limitations under the License. */ -package android.support.v4.view; +package com.actionbarsherlock.view; import android.content.Context; @@ -32,57 +32,34 @@ import android.content.Context; * implementation.

*/ public abstract class Window extends android.view.Window { - /* - * We use long values so that we can intercept the call to - * requestWindowFeature in our Activity. - */ - - /** - * Flag for enabling the Action Bar. This is enabled by default for some - * devices. The Action Bar replaces the title bar and provides an alternate - * location for an on-screen menu button on some devices. - */ public static final long FEATURE_ACTION_BAR = android.view.Window.FEATURE_ACTION_BAR; - - /** - * Enable the pre-3.0 action bar implementation to honor the 'withText' - * attribute on menu items regardless of display resolution and/or density. - */ - //Hopefully the native Window.FEATURE_XXX numbering won't get this high anytime soon. - public static final long FEATURE_ACTION_BAR_ITEM_TEXT = 31; - - /** - * Flag for requesting an Action Bar that overlays window content. Normally - * an Action Bar will sit in the space above window content, but if this - * feature is requested along with {@link #FEATURE_ACTION_BAR} it will be - * layered over the window content itself. This is useful if you would like - * your app to have more control over how the Action Bar is displayed, such - * as letting application content scroll beneath an Action Bar with a - * transparent background or otherwise displaying a transparent/translucent - * Action Bar over application content. - */ public static final long FEATURE_ACTION_BAR_OVERLAY = android.view.Window.FEATURE_ACTION_BAR_OVERLAY; - - /** - * Flag for specifying the behavior of action modes when an Action Bar is - * not present. If overlay is enabled, the action mode UI will be allowed to - * cover existing window content. - */ public static final long FEATURE_ACTION_MODE_OVERLAY = android.view.Window.FEATURE_ACTION_MODE_OVERLAY; - - /** - * Flag for indeterminate progress . - */ + public static final long FEATURE_NO_TITLE = android.view.Window.FEATURE_NO_TITLE; + public static final long FEATURE_PROGRESS = android.view.Window.FEATURE_PROGRESS; public static final long FEATURE_INDETERMINATE_PROGRESS = android.view.Window.FEATURE_INDETERMINATE_PROGRESS; - - /** * Create a new instance for a context. * * @param context Context. */ - public Window(Context context) { + private Window(Context context) { super(context); } + + + public interface Callback { + /** + * Called when a panel's menu item has been selected by the user. + * + * @param featureId The panel that the menu is in. + * @param item The menu item that was selected. + * + * @return boolean Return true to finish processing of selection, or + * false to perform the normal menu handling (calling its + * Runnable or sending a Message to its target Handler). + */ + public boolean onMenuItemSelected(int featureId, MenuItem item); + } } diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ActivityChooserModel.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ActivityChooserModel.java new file mode 100644 index 00000000..d7f110fc --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ActivityChooserModel.java @@ -0,0 +1,1104 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.widget; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.database.DataSetObservable; +import android.os.Handler; +import android.text.TextUtils; +import android.util.Log; +import android.util.Xml; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +/** + *

+ * This class represents a data model for choosing a component for handing a + * given {@link Intent}. The model is responsible for querying the system for + * activities that can handle the given intent and order found activities + * based on historical data of previous choices. The historical data is stored + * in an application private file. If a client does not want to have persistent + * choice history the file can be omitted, thus the activities will be ordered + * based on historical usage for the current session. + *

+ *

+ * For each backing history file there is a singleton instance of this class. Thus, + * several clients that specify the same history file will share the same model. Note + * that if multiple clients are sharing the same model they should implement semantically + * equivalent functionality since setting the model intent will change the found + * activities and they may be inconsistent with the functionality of some of the clients. + * For example, choosing a share activity can be implemented by a single backing + * model and two different views for performing the selection. If however, one of the + * views is used for sharing but the other for importing, for example, then each + * view should be backed by a separate model. + *

+ *

+ * The way clients interact with this class is as follows: + *

+ *

+ *

+ * 
+ *  // Get a model and set it to a couple of clients with semantically similar function.
+ *  ActivityChooserModel dataModel =
+ *      ActivityChooserModel.get(context, "task_specific_history_file_name.xml");
+ *
+ *  ActivityChooserModelClient modelClient1 = getActivityChooserModelClient1();
+ *  modelClient1.setActivityChooserModel(dataModel);
+ *
+ *  ActivityChooserModelClient modelClient2 = getActivityChooserModelClient2();
+ *  modelClient2.setActivityChooserModel(dataModel);
+ *
+ *  // Set an intent to choose a an activity for.
+ *  dataModel.setIntent(intent);
+ * 
+ * 
+ * 

+ *

+ * Note: This class is thread safe. + *

+ * + * @hide + */ +class ActivityChooserModel extends DataSetObservable { + + /** + * Client that utilizes an {@link ActivityChooserModel}. + */ + public interface ActivityChooserModelClient { + + /** + * Sets the {@link ActivityChooserModel}. + * + * @param dataModel The model. + */ + public void setActivityChooserModel(ActivityChooserModel dataModel); + } + + /** + * Defines a sorter that is responsible for sorting the activities + * based on the provided historical choices and an intent. + */ + public interface ActivitySorter { + + /** + * Sorts the activities in descending order of relevance + * based on previous history and an intent. + * + * @param intent The {@link Intent}. + * @param activities Activities to be sorted. + * @param historicalRecords Historical records. + */ + // This cannot be done by a simple comparator since an Activity weight + // is computed from history. Note that Activity implements Comparable. + public void sort(Intent intent, List activities, + List historicalRecords); + } + + /** + * Listener for choosing an activity. + */ + public interface OnChooseActivityListener { + + /** + * Called when an activity has been chosen. The client can decide whether + * an activity can be chosen and if so the caller of + * {@link ActivityChooserModel#chooseActivity(int)} will receive and {@link Intent} + * for launching it. + *

+ * Note: Modifying the intent is not permitted and + * any changes to the latter will be ignored. + *

+ * + * @param host The listener's host model. + * @param intent The intent for launching the chosen activity. + * @return Whether the intent is handled and should not be delivered to clients. + * + * @see ActivityChooserModel#chooseActivity(int) + */ + public boolean onChooseActivity(ActivityChooserModel host, Intent intent); + } + + /** + * Flag for selecting debug mode. + */ + private static final boolean DEBUG = false; + + /** + * Tag used for logging. + */ + private static final String LOG_TAG = ActivityChooserModel.class.getSimpleName(); + + /** + * The root tag in the history file. + */ + private static final String TAG_HISTORICAL_RECORDS = "historical-records"; + + /** + * The tag for a record in the history file. + */ + private static final String TAG_HISTORICAL_RECORD = "historical-record"; + + /** + * Attribute for the activity. + */ + private static final String ATTRIBUTE_ACTIVITY = "activity"; + + /** + * Attribute for the choice time. + */ + private static final String ATTRIBUTE_TIME = "time"; + + /** + * Attribute for the choice weight. + */ + private static final String ATTRIBUTE_WEIGHT = "weight"; + + /** + * The default name of the choice history file. + */ + public static final String DEFAULT_HISTORY_FILE_NAME = + "activity_choser_model_history.xml"; + + /** + * The default maximal length of the choice history. + */ + public static final int DEFAULT_HISTORY_MAX_LENGTH = 50; + + /** + * The amount with which to inflate a chosen activity when set as default. + */ + private static final int DEFAULT_ACTIVITY_INFLATION = 5; + + /** + * Default weight for a choice record. + */ + private static final float DEFAULT_HISTORICAL_RECORD_WEIGHT = 1.0f; + + /** + * The extension of the history file. + */ + private static final String HISTORY_FILE_EXTENSION = ".xml"; + + /** + * An invalid item index. + */ + private static final int INVALID_INDEX = -1; + + /** + * Lock to guard the model registry. + */ + private static final Object sRegistryLock = new Object(); + + /** + * This the registry for data models. + */ + private static final Map sDataModelRegistry = + new HashMap(); + + /** + * Lock for synchronizing on this instance. + */ + private final Object mInstanceLock = new Object(); + + /** + * List of activities that can handle the current intent. + */ + private final List mActivites = new ArrayList(); + + /** + * List with historical choice records. + */ + private final List mHistoricalRecords = new ArrayList(); + + /** + * Context for accessing resources. + */ + private final Context mContext; + + /** + * The name of the history file that backs this model. + */ + private final String mHistoryFileName; + + /** + * The intent for which a activity is being chosen. + */ + private Intent mIntent; + + /** + * The sorter for ordering activities based on intent and past choices. + */ + private ActivitySorter mActivitySorter = new DefaultSorter(); + + /** + * The maximal length of the choice history. + */ + private int mHistoryMaxSize = DEFAULT_HISTORY_MAX_LENGTH; + + /** + * Flag whether choice history can be read. In general many clients can + * share the same data model and {@link #readHistoricalData()} may be called + * by arbitrary of them any number of times. Therefore, this class guarantees + * that the very first read succeeds and subsequent reads can be performed + * only after a call to {@link #persistHistoricalData()} followed by change + * of the share records. + */ + private boolean mCanReadHistoricalData = true; + + /** + * Flag whether the choice history was read. This is used to enforce that + * before calling {@link #persistHistoricalData()} a call to + * {@link #persistHistoricalData()} has been made. This aims to avoid a + * scenario in which a choice history file exits, it is not read yet and + * it is overwritten. Note that always all historical records are read in + * full and the file is rewritten. This is necessary since we need to + * purge old records that are outside of the sliding window of past choices. + */ + private boolean mReadShareHistoryCalled = false; + + /** + * Flag whether the choice records have changed. In general many clients can + * share the same data model and {@link #persistHistoricalData()} may be called + * by arbitrary of them any number of times. Therefore, this class guarantees + * that choice history will be persisted only if it has changed. + */ + private boolean mHistoricalRecordsChanged = true; + + /** + * Hander for scheduling work on client tread. + */ + private final Handler mHandler = new Handler(); + + /** + * Policy for controlling how the model handles chosen activities. + */ + private OnChooseActivityListener mActivityChoserModelPolicy; + + /** + * Gets the data model backed by the contents of the provided file with historical data. + * Note that only one data model is backed by a given file, thus multiple calls with + * the same file name will return the same model instance. If no such instance is present + * it is created. + *

+ * Note: To use the default historical data file clients should explicitly + * pass as file name {@link #DEFAULT_HISTORY_FILE_NAME}. If no persistence of the choice + * history is desired clients should pass null for the file name. In such + * case a new model is returned for each invocation. + *

+ * + *

+ * Always use difference historical data files for semantically different actions. + * For example, sharing is different from importing. + *

+ * + * @param context Context for loading resources. + * @param historyFileName File name with choice history, null + * if the model should not be backed by a file. In this case the activities + * will be ordered only by data from the current session. + * + * @return The model. + */ + public static ActivityChooserModel get(Context context, String historyFileName) { + synchronized (sRegistryLock) { + ActivityChooserModel dataModel = sDataModelRegistry.get(historyFileName); + if (dataModel == null) { + dataModel = new ActivityChooserModel(context, historyFileName); + sDataModelRegistry.put(historyFileName, dataModel); + } + dataModel.readHistoricalData(); + return dataModel; + } + } + + /** + * Creates a new instance. + * + * @param context Context for loading resources. + * @param historyFileName The history XML file. + */ + private ActivityChooserModel(Context context, String historyFileName) { + mContext = context.getApplicationContext(); + if (!TextUtils.isEmpty(historyFileName) + && !historyFileName.endsWith(HISTORY_FILE_EXTENSION)) { + mHistoryFileName = historyFileName + HISTORY_FILE_EXTENSION; + } else { + mHistoryFileName = historyFileName; + } + } + + /** + * Sets an intent for which to choose a activity. + *

+ * Note: Clients must set only semantically similar + * intents for each data model. + *

+ * + * @param intent The intent. + */ + public void setIntent(Intent intent) { + synchronized (mInstanceLock) { + if (mIntent == intent) { + return; + } + mIntent = intent; + loadActivitiesLocked(); + } + } + + /** + * Gets the intent for which a activity is being chosen. + * + * @return The intent. + */ + public Intent getIntent() { + synchronized (mInstanceLock) { + return mIntent; + } + } + + /** + * Gets the number of activities that can handle the intent. + * + * @return The activity count. + * + * @see #setIntent(Intent) + */ + public int getActivityCount() { + synchronized (mInstanceLock) { + return mActivites.size(); + } + } + + /** + * Gets an activity at a given index. + * + * @return The activity. + * + * @see ActivityResolveInfo + * @see #setIntent(Intent) + */ + public ResolveInfo getActivity(int index) { + synchronized (mInstanceLock) { + return mActivites.get(index).resolveInfo; + } + } + + /** + * Gets the index of a the given activity. + * + * @param activity The activity index. + * + * @return The index if found, -1 otherwise. + */ + public int getActivityIndex(ResolveInfo activity) { + List activities = mActivites; + final int activityCount = activities.size(); + for (int i = 0; i < activityCount; i++) { + ActivityResolveInfo currentActivity = activities.get(i); + if (currentActivity.resolveInfo == activity) { + return i; + } + } + return INVALID_INDEX; + } + + /** + * Chooses a activity to handle the current intent. This will result in + * adding a historical record for that action and construct intent with + * its component name set such that it can be immediately started by the + * client. + *

+ * Note: By calling this method the client guarantees + * that the returned intent will be started. This intent is returned to + * the client solely to let additional customization before the start. + *

+ * + * @return An {@link Intent} for launching the activity or null if the + * policy has consumed the intent. + * + * @see HistoricalRecord + * @see OnChooseActivityListener + */ + public Intent chooseActivity(int index) { + ActivityResolveInfo chosenActivity = mActivites.get(index); + + ComponentName chosenName = new ComponentName( + chosenActivity.resolveInfo.activityInfo.packageName, + chosenActivity.resolveInfo.activityInfo.name); + + Intent choiceIntent = new Intent(mIntent); + choiceIntent.setComponent(chosenName); + + if (mActivityChoserModelPolicy != null) { + // Do not allow the policy to change the intent. + Intent choiceIntentCopy = new Intent(choiceIntent); + final boolean handled = mActivityChoserModelPolicy.onChooseActivity(this, + choiceIntentCopy); + if (handled) { + return null; + } + } + + HistoricalRecord historicalRecord = new HistoricalRecord(chosenName, + System.currentTimeMillis(), DEFAULT_HISTORICAL_RECORD_WEIGHT); + addHisoricalRecord(historicalRecord); + + return choiceIntent; + } + + /** + * Sets the listener for choosing an activity. + * + * @param listener The listener. + */ + public void setOnChooseActivityListener(OnChooseActivityListener listener) { + mActivityChoserModelPolicy = listener; + } + + /** + * Gets the default activity, The default activity is defined as the one + * with highest rank i.e. the first one in the list of activities that can + * handle the intent. + * + * @return The default activity, null id not activities. + * + * @see #getActivity(int) + */ + public ResolveInfo getDefaultActivity() { + synchronized (mInstanceLock) { + if (!mActivites.isEmpty()) { + return mActivites.get(0).resolveInfo; + } + } + return null; + } + + /** + * Sets the default activity. The default activity is set by adding a + * historical record with weight high enough that this activity will + * become the highest ranked. Such a strategy guarantees that the default + * will eventually change if not used. Also the weight of the record for + * setting a default is inflated with a constant amount to guarantee that + * it will stay as default for awhile. + * + * @param index The index of the activity to set as default. + */ + public void setDefaultActivity(int index) { + ActivityResolveInfo newDefaultActivity = mActivites.get(index); + ActivityResolveInfo oldDefaultActivity = mActivites.get(0); + + final float weight; + if (oldDefaultActivity != null) { + // Add a record with weight enough to boost the chosen at the top. + weight = oldDefaultActivity.weight - newDefaultActivity.weight + + DEFAULT_ACTIVITY_INFLATION; + } else { + weight = DEFAULT_HISTORICAL_RECORD_WEIGHT; + } + + ComponentName defaultName = new ComponentName( + newDefaultActivity.resolveInfo.activityInfo.packageName, + newDefaultActivity.resolveInfo.activityInfo.name); + HistoricalRecord historicalRecord = new HistoricalRecord(defaultName, + System.currentTimeMillis(), weight); + addHisoricalRecord(historicalRecord); + } + + /** + * Reads the history data from the backing file if the latter + * was provided. Calling this method more than once before a call + * to {@link #persistHistoricalData()} has been made has no effect. + *

+ * Note: Historical data is read asynchronously and + * as soon as the reading is completed any registered + * {@link DataSetObserver}s will be notified. Also no historical + * data is read until this method is invoked. + *

+ */ + private void readHistoricalData() { + synchronized (mInstanceLock) { + if (!mCanReadHistoricalData || !mHistoricalRecordsChanged) { + return; + } + mCanReadHistoricalData = false; + mReadShareHistoryCalled = true; + if (!TextUtils.isEmpty(mHistoryFileName)) { + /*AsyncTask.*/SERIAL_EXECUTOR.execute(new HistoryLoader()); + } + } + } + + private static final Executor SERIAL_EXECUTOR = Executors.newSingleThreadExecutor(); + + /** + * Persists the history data to the backing file if the latter + * was provided. Calling this method before a call to {@link #readHistoricalData()} + * throws an exception. Calling this method more than one without choosing an + * activity has not effect. + * + * @throws IllegalStateException If this method is called before a call to + * {@link #readHistoricalData()}. + */ + private void persistHistoricalData() { + synchronized (mInstanceLock) { + if (!mReadShareHistoryCalled) { + throw new IllegalStateException("No preceding call to #readHistoricalData"); + } + if (!mHistoricalRecordsChanged) { + return; + } + mHistoricalRecordsChanged = false; + mCanReadHistoricalData = true; + if (!TextUtils.isEmpty(mHistoryFileName)) { + /*AsyncTask.*/SERIAL_EXECUTOR.execute(new HistoryPersister()); + } + } + } + + /** + * Sets the sorter for ordering activities based on historical data and an intent. + * + * @param activitySorter The sorter. + * + * @see ActivitySorter + */ + public void setActivitySorter(ActivitySorter activitySorter) { + synchronized (mInstanceLock) { + if (mActivitySorter == activitySorter) { + return; + } + mActivitySorter = activitySorter; + sortActivities(); + } + } + + /** + * Sorts the activities based on history and an intent. If + * a sorter is not specified this a default implementation is used. + * + * @see #setActivitySorter(ActivitySorter) + */ + private void sortActivities() { + synchronized (mInstanceLock) { + if (mActivitySorter != null && !mActivites.isEmpty()) { + mActivitySorter.sort(mIntent, mActivites, + Collections.unmodifiableList(mHistoricalRecords)); + notifyChanged(); + } + } + } + + /** + * Sets the maximal size of the historical data. Defaults to + * {@link #DEFAULT_HISTORY_MAX_LENGTH} + *

+ * Note: Setting this property will immediately + * enforce the specified max history size by dropping enough old + * historical records to enforce the desired size. Thus, any + * records that exceed the history size will be discarded and + * irreversibly lost. + *

+ * + * @param historyMaxSize The max history size. + */ + public void setHistoryMaxSize(int historyMaxSize) { + synchronized (mInstanceLock) { + if (mHistoryMaxSize == historyMaxSize) { + return; + } + mHistoryMaxSize = historyMaxSize; + pruneExcessiveHistoricalRecordsLocked(); + sortActivities(); + } + } + + /** + * Gets the history max size. + * + * @return The history max size. + */ + public int getHistoryMaxSize() { + synchronized (mInstanceLock) { + return mHistoryMaxSize; + } + } + + /** + * Gets the history size. + * + * @return The history size. + */ + public int getHistorySize() { + synchronized (mInstanceLock) { + return mHistoricalRecords.size(); + } + } + + /** + * Adds a historical record. + * + * @param historicalRecord The record to add. + * @return True if the record was added. + */ + private boolean addHisoricalRecord(HistoricalRecord historicalRecord) { + synchronized (mInstanceLock) { + final boolean added = mHistoricalRecords.add(historicalRecord); + if (added) { + mHistoricalRecordsChanged = true; + pruneExcessiveHistoricalRecordsLocked(); + persistHistoricalData(); + sortActivities(); + } + return added; + } + } + + /** + * Prunes older excessive records to guarantee {@link #mHistoryMaxSize}. + */ + private void pruneExcessiveHistoricalRecordsLocked() { + List choiceRecords = mHistoricalRecords; + final int pruneCount = choiceRecords.size() - mHistoryMaxSize; + if (pruneCount <= 0) { + return; + } + mHistoricalRecordsChanged = true; + for (int i = 0; i < pruneCount; i++) { + HistoricalRecord prunedRecord = choiceRecords.remove(0); + if (DEBUG) { + Log.i(LOG_TAG, "Pruned: " + prunedRecord); + } + } + } + + /** + * Loads the activities. + */ + private void loadActivitiesLocked() { + mActivites.clear(); + if (mIntent != null) { + List resolveInfos = + mContext.getPackageManager().queryIntentActivities(mIntent, 0); + final int resolveInfoCount = resolveInfos.size(); + for (int i = 0; i < resolveInfoCount; i++) { + ResolveInfo resolveInfo = resolveInfos.get(i); + mActivites.add(new ActivityResolveInfo(resolveInfo)); + } + sortActivities(); + } else { + notifyChanged(); + } + } + + /** + * Represents a record in the history. + */ + public final static class HistoricalRecord { + + /** + * The activity name. + */ + public final ComponentName activity; + + /** + * The choice time. + */ + public final long time; + + /** + * The record weight. + */ + public final float weight; + + /** + * Creates a new instance. + * + * @param activityName The activity component name flattened to string. + * @param time The time the activity was chosen. + * @param weight The weight of the record. + */ + public HistoricalRecord(String activityName, long time, float weight) { + this(ComponentName.unflattenFromString(activityName), time, weight); + } + + /** + * Creates a new instance. + * + * @param activityName The activity name. + * @param time The time the activity was chosen. + * @param weight The weight of the record. + */ + public HistoricalRecord(ComponentName activityName, long time, float weight) { + this.activity = activityName; + this.time = time; + this.weight = weight; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((activity == null) ? 0 : activity.hashCode()); + result = prime * result + (int) (time ^ (time >>> 32)); + result = prime * result + Float.floatToIntBits(weight); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + HistoricalRecord other = (HistoricalRecord) obj; + if (activity == null) { + if (other.activity != null) { + return false; + } + } else if (!activity.equals(other.activity)) { + return false; + } + if (time != other.time) { + return false; + } + if (Float.floatToIntBits(weight) != Float.floatToIntBits(other.weight)) { + return false; + } + return true; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("["); + builder.append("; activity:").append(activity); + builder.append("; time:").append(time); + builder.append("; weight:").append(new BigDecimal(weight)); + builder.append("]"); + return builder.toString(); + } + } + + /** + * Represents an activity. + */ + public final class ActivityResolveInfo implements Comparable { + + /** + * The {@link ResolveInfo} of the activity. + */ + public final ResolveInfo resolveInfo; + + /** + * Weight of the activity. Useful for sorting. + */ + public float weight; + + /** + * Creates a new instance. + * + * @param resolveInfo activity {@link ResolveInfo}. + */ + public ActivityResolveInfo(ResolveInfo resolveInfo) { + this.resolveInfo = resolveInfo; + } + + @Override + public int hashCode() { + return 31 + Float.floatToIntBits(weight); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ActivityResolveInfo other = (ActivityResolveInfo) obj; + if (Float.floatToIntBits(weight) != Float.floatToIntBits(other.weight)) { + return false; + } + return true; + } + + public int compareTo(ActivityResolveInfo another) { + return Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("["); + builder.append("resolveInfo:").append(resolveInfo.toString()); + builder.append("; weight:").append(new BigDecimal(weight)); + builder.append("]"); + return builder.toString(); + } + } + + /** + * Default activity sorter implementation. + */ + private final class DefaultSorter implements ActivitySorter { + private static final float WEIGHT_DECAY_COEFFICIENT = 0.95f; + + private final Map mPackageNameToActivityMap = + new HashMap(); + + public void sort(Intent intent, List activities, + List historicalRecords) { + Map packageNameToActivityMap = + mPackageNameToActivityMap; + packageNameToActivityMap.clear(); + + final int activityCount = activities.size(); + for (int i = 0; i < activityCount; i++) { + ActivityResolveInfo activity = activities.get(i); + activity.weight = 0.0f; + String packageName = activity.resolveInfo.activityInfo.packageName; + packageNameToActivityMap.put(packageName, activity); + } + + final int lastShareIndex = historicalRecords.size() - 1; + float nextRecordWeight = 1; + for (int i = lastShareIndex; i >= 0; i--) { + HistoricalRecord historicalRecord = historicalRecords.get(i); + String packageName = historicalRecord.activity.getPackageName(); + ActivityResolveInfo activity = packageNameToActivityMap.get(packageName); + if (activity != null) { + activity.weight += historicalRecord.weight * nextRecordWeight; + nextRecordWeight = nextRecordWeight * WEIGHT_DECAY_COEFFICIENT; + } + } + + Collections.sort(activities); + + if (DEBUG) { + for (int i = 0; i < activityCount; i++) { + Log.i(LOG_TAG, "Sorted: " + activities.get(i)); + } + } + } + } + + /** + * Command for reading the historical records from a file off the UI thread. + */ + private final class HistoryLoader implements Runnable { + + public void run() { + FileInputStream fis = null; + try { + fis = mContext.openFileInput(mHistoryFileName); + } catch (FileNotFoundException fnfe) { + if (DEBUG) { + Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName); + } + return; + } + try { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(fis, null); + + int type = XmlPullParser.START_DOCUMENT; + while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) { + type = parser.next(); + } + + if (!TAG_HISTORICAL_RECORDS.equals(parser.getName())) { + throw new XmlPullParserException("Share records file does not start with " + + TAG_HISTORICAL_RECORDS + " tag."); + } + + List readRecords = new ArrayList(); + + while (true) { + type = parser.next(); + if (type == XmlPullParser.END_DOCUMENT) { + break; + } + if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { + continue; + } + String nodeName = parser.getName(); + if (!TAG_HISTORICAL_RECORD.equals(nodeName)) { + throw new XmlPullParserException("Share records file not well-formed."); + } + + String activity = parser.getAttributeValue(null, ATTRIBUTE_ACTIVITY); + final long time = + Long.parseLong(parser.getAttributeValue(null, ATTRIBUTE_TIME)); + final float weight = + Float.parseFloat(parser.getAttributeValue(null, ATTRIBUTE_WEIGHT)); + + HistoricalRecord readRecord = new HistoricalRecord(activity, time, + weight); + readRecords.add(readRecord); + + if (DEBUG) { + Log.i(LOG_TAG, "Read " + readRecord.toString()); + } + } + + if (DEBUG) { + Log.i(LOG_TAG, "Read " + readRecords.size() + " historical records."); + } + + synchronized (mInstanceLock) { + Set uniqueShareRecords = + new LinkedHashSet(readRecords); + + // Make sure no duplicates. Example: Read a file with + // one record, add one record, persist the two records, + // add a record, read the persisted records - the + // read two records should not be added again. + List historicalRecords = mHistoricalRecords; + final int historicalRecordsCount = historicalRecords.size(); + for (int i = historicalRecordsCount - 1; i >= 0; i--) { + HistoricalRecord historicalRecord = historicalRecords.get(i); + uniqueShareRecords.add(historicalRecord); + } + + if (historicalRecords.size() == uniqueShareRecords.size()) { + return; + } + + // Make sure the oldest records go to the end. + historicalRecords.clear(); + historicalRecords.addAll(uniqueShareRecords); + + mHistoricalRecordsChanged = true; + + // Do this on the client thread since the client may be on the UI + // thread, wait for data changes which happen during sorting, and + // perform UI modification based on the data change. + mHandler.post(new Runnable() { + public void run() { + pruneExcessiveHistoricalRecordsLocked(); + sortActivities(); + } + }); + } + } catch (XmlPullParserException xppe) { + Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, xppe); + } catch (IOException ioe) { + Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, ioe); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException ioe) { + /* ignore */ + } + } + } + } + } + + /** + * Command for persisting the historical records to a file off the UI thread. + */ + private final class HistoryPersister implements Runnable { + + public void run() { + FileOutputStream fos = null; + List records = null; + + synchronized (mInstanceLock) { + records = new ArrayList(mHistoricalRecords); + } + + try { + fos = mContext.openFileOutput(mHistoryFileName, Context.MODE_PRIVATE); + } catch (FileNotFoundException fnfe) { + Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, fnfe); + return; + } + + XmlSerializer serializer = Xml.newSerializer(); + + try { + serializer.setOutput(fos, null); + serializer.startDocument("UTF-8", true); + serializer.startTag(null, TAG_HISTORICAL_RECORDS); + + final int recordCount = records.size(); + for (int i = 0; i < recordCount; i++) { + HistoricalRecord record = records.remove(0); + serializer.startTag(null, TAG_HISTORICAL_RECORD); + serializer.attribute(null, ATTRIBUTE_ACTIVITY, record.activity.flattenToString()); + serializer.attribute(null, ATTRIBUTE_TIME, String.valueOf(record.time)); + serializer.attribute(null, ATTRIBUTE_WEIGHT, String.valueOf(record.weight)); + serializer.endTag(null, TAG_HISTORICAL_RECORD); + if (DEBUG) { + Log.i(LOG_TAG, "Wrote " + record.toString()); + } + } + + serializer.endTag(null, TAG_HISTORICAL_RECORDS); + serializer.endDocument(); + + if (DEBUG) { + Log.i(LOG_TAG, "Wrote " + recordCount + " historical records."); + } + } catch (IllegalArgumentException iae) { + Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, iae); + } catch (IllegalStateException ise) { + Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, ise); + } catch (IOException ioe) { + Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, ioe); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + /* ignore */ + } + } + } + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ActivityChooserView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ActivityChooserView.java new file mode 100644 index 00000000..e19ea9e9 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ActivityChooserView.java @@ -0,0 +1,827 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.widget; + +import android.os.Build; +import com.actionbarsherlock.R; +import com.actionbarsherlock.internal.widget.IcsLinearLayout; +import com.actionbarsherlock.internal.widget.IcsListPopupWindow; +import com.actionbarsherlock.view.ActionProvider; +import com.actionbarsherlock.widget.ActivityChooserModel.ActivityChooserModelClient; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.database.DataSetObserver; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.PopupWindow; +import android.widget.TextView; + +/** + * This class is a view for choosing an activity for handling a given {@link Intent}. + *

+ * The view is composed of two adjacent buttons: + *

    + *
  • + * The left button is an immediate action and allows one click activity choosing. + * Tapping this button immediately executes the intent without requiring any further + * user input. Long press on this button shows a popup for changing the default + * activity. + *
  • + *
  • + * The right button is an overflow action and provides an optimized menu + * of additional activities. Tapping this button shows a popup anchored to this + * view, listing the most frequently used activities. This list is initially + * limited to a small number of items in frequency used order. The last item, + * "Show all..." serves as an affordance to display all available activities. + *
  • + *
+ *

+ * + * @hide + */ +class ActivityChooserView extends ViewGroup implements ActivityChooserModelClient { + + /** + * An adapter for displaying the activities in an {@link AdapterView}. + */ + private final ActivityChooserViewAdapter mAdapter; + + /** + * Implementation of various interfaces to avoid publishing them in the APIs. + */ + private final Callbacks mCallbacks; + + /** + * The content of this view. + */ + private final IcsLinearLayout mActivityChooserContent; + + /** + * Stores the background drawable to allow hiding and latter showing. + */ + private final Drawable mActivityChooserContentBackground; + + /** + * The expand activities action button; + */ + private final FrameLayout mExpandActivityOverflowButton; + + /** + * The image for the expand activities action button; + */ + private final ImageView mExpandActivityOverflowButtonImage; + + /** + * The default activities action button; + */ + private final FrameLayout mDefaultActivityButton; + + /** + * The image for the default activities action button; + */ + private final ImageView mDefaultActivityButtonImage; + + /** + * The maximal width of the list popup. + */ + private final int mListPopupMaxWidth; + + /** + * The ActionProvider hosting this view, if applicable. + */ + ActionProvider mProvider; + + /** + * Observer for the model data. + */ + private final DataSetObserver mModelDataSetOberver = new DataSetObserver() { + + @Override + public void onChanged() { + super.onChanged(); + mAdapter.notifyDataSetChanged(); + } + @Override + public void onInvalidated() { + super.onInvalidated(); + mAdapter.notifyDataSetInvalidated(); + } + }; + + private final OnGlobalLayoutListener mOnGlobalLayoutListener = new OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + if (isShowingPopup()) { + if (!isShown()) { + getListPopupWindow().dismiss(); + } else { + getListPopupWindow().show(); + if (mProvider != null) { + mProvider.subUiVisibilityChanged(true); + } + } + } + } + }; + + /** + * Popup window for showing the activity overflow list. + */ + private IcsListPopupWindow mListPopupWindow; + + /** + * Listener for the dismissal of the popup/alert. + */ + private PopupWindow.OnDismissListener mOnDismissListener; + + /** + * Flag whether a default activity currently being selected. + */ + private boolean mIsSelectingDefaultActivity; + + /** + * The count of activities in the popup. + */ + private int mInitialActivityCount = ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_DEFAULT; + + /** + * Flag whether this view is attached to a window. + */ + private boolean mIsAttachedToWindow; + + /** + * String resource for formatting content description of the default target. + */ + private int mDefaultActionButtonContentDescription; + + private final Context mContext; + + /** + * Create a new instance. + * + * @param context The application environment. + */ + public ActivityChooserView(Context context) { + this(context, null); + } + + /** + * Create a new instance. + * + * @param context The application environment. + * @param attrs A collection of attributes. + */ + public ActivityChooserView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + /** + * Create a new instance. + * + * @param context The application environment. + * @param attrs A collection of attributes. + * @param defStyle The default style to apply to this view. + */ + public ActivityChooserView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mContext = context; + + TypedArray attributesArray = context.obtainStyledAttributes(attrs, + R.styleable.SherlockActivityChooserView, defStyle, 0); + + mInitialActivityCount = attributesArray.getInt( + R.styleable.SherlockActivityChooserView_initialActivityCount, + ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_DEFAULT); + + Drawable expandActivityOverflowButtonDrawable = attributesArray.getDrawable( + R.styleable.SherlockActivityChooserView_expandActivityOverflowButtonDrawable); + + attributesArray.recycle(); + + LayoutInflater inflater = LayoutInflater.from(mContext); + inflater.inflate(R.layout.abs__activity_chooser_view, this, true); + + mCallbacks = new Callbacks(); + + mActivityChooserContent = (IcsLinearLayout) findViewById(R.id.abs__activity_chooser_view_content); + mActivityChooserContentBackground = mActivityChooserContent.getBackground(); + + mDefaultActivityButton = (FrameLayout) findViewById(R.id.abs__default_activity_button); + mDefaultActivityButton.setOnClickListener(mCallbacks); + mDefaultActivityButton.setOnLongClickListener(mCallbacks); + mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.abs__image); + + mExpandActivityOverflowButton = (FrameLayout) findViewById(R.id.abs__expand_activities_button); + mExpandActivityOverflowButton.setOnClickListener(mCallbacks); + mExpandActivityOverflowButtonImage = + (ImageView) mExpandActivityOverflowButton.findViewById(R.id.abs__image); + mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable); + + mAdapter = new ActivityChooserViewAdapter(); + mAdapter.registerDataSetObserver(new DataSetObserver() { + @Override + public void onChanged() { + super.onChanged(); + updateAppearance(); + } + }); + + Resources resources = context.getResources(); + mListPopupMaxWidth = Math.max(resources.getDisplayMetrics().widthPixels / 2, + resources.getDimensionPixelSize(R.dimen.abs__config_prefDialogWidth)); + } + + /** + * {@inheritDoc} + */ + public void setActivityChooserModel(ActivityChooserModel dataModel) { + mAdapter.setDataModel(dataModel); + if (isShowingPopup()) { + dismissPopup(); + showPopup(); + } + } + + /** + * Sets the background for the button that expands the activity + * overflow list. + * + * Note: Clients would like to set this drawable + * as a clue about the action the chosen activity will perform. For + * example, if a share activity is to be chosen the drawable should + * give a clue that sharing is to be performed. + * + * @param drawable The drawable. + */ + public void setExpandActivityOverflowButtonDrawable(Drawable drawable) { + mExpandActivityOverflowButtonImage.setImageDrawable(drawable); + } + + /** + * Sets the content description for the button that expands the activity + * overflow list. + * + * description as a clue about the action performed by the button. + * For example, if a share activity is to be chosen the content + * description should be something like "Share with". + * + * @param resourceId The content description resource id. + */ + public void setExpandActivityOverflowButtonContentDescription(int resourceId) { + CharSequence contentDescription = mContext.getString(resourceId); + mExpandActivityOverflowButtonImage.setContentDescription(contentDescription); + } + + /** + * Set the provider hosting this view, if applicable. + * @hide Internal use only + */ + public void setProvider(ActionProvider provider) { + mProvider = provider; + } + + /** + * Shows the popup window with activities. + * + * @return True if the popup was shown, false if already showing. + */ + public boolean showPopup() { + if (isShowingPopup() || !mIsAttachedToWindow) { + return false; + } + mIsSelectingDefaultActivity = false; + showPopupUnchecked(mInitialActivityCount); + return true; + } + + /** + * Shows the popup no matter if it was already showing. + * + * @param maxActivityCount The max number of activities to display. + */ + private void showPopupUnchecked(int maxActivityCount) { + if (mAdapter.getDataModel() == null) { + throw new IllegalStateException("No data model. Did you call #setDataModel?"); + } + + getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener); + + final boolean defaultActivityButtonShown = + mDefaultActivityButton.getVisibility() == VISIBLE; + + final int activityCount = mAdapter.getActivityCount(); + final int maxActivityCountOffset = defaultActivityButtonShown ? 1 : 0; + if (maxActivityCount != ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED + && activityCount > maxActivityCount + maxActivityCountOffset) { + mAdapter.setShowFooterView(true); + mAdapter.setMaxActivityCount(maxActivityCount - 1); + } else { + mAdapter.setShowFooterView(false); + mAdapter.setMaxActivityCount(maxActivityCount); + } + + IcsListPopupWindow popupWindow = getListPopupWindow(); + if (!popupWindow.isShowing()) { + if (mIsSelectingDefaultActivity || !defaultActivityButtonShown) { + mAdapter.setShowDefaultActivity(true, defaultActivityButtonShown); + } else { + mAdapter.setShowDefaultActivity(false, false); + } + final int contentWidth = Math.min(mAdapter.measureContentWidth(), mListPopupMaxWidth); + popupWindow.setContentWidth(contentWidth); + popupWindow.show(); + if (mProvider != null) { + mProvider.subUiVisibilityChanged(true); + } + popupWindow.getListView().setContentDescription(mContext.getString( + R.string.abs__activitychooserview_choose_application)); + } + } + + /** + * Dismisses the popup window with activities. + * + * @return True if dismissed, false if already dismissed. + */ + public boolean dismissPopup() { + if (isShowingPopup()) { + getListPopupWindow().dismiss(); + ViewTreeObserver viewTreeObserver = getViewTreeObserver(); + if (viewTreeObserver.isAlive()) { + viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener); + } + } + return true; + } + + /** + * Gets whether the popup window with activities is shown. + * + * @return True if the popup is shown. + */ + public boolean isShowingPopup() { + return getListPopupWindow().isShowing(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + ActivityChooserModel dataModel = mAdapter.getDataModel(); + if (dataModel != null) { + dataModel.registerObserver(mModelDataSetOberver); + } + mIsAttachedToWindow = true; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + ActivityChooserModel dataModel = mAdapter.getDataModel(); + if (dataModel != null) { + try { + dataModel.unregisterObserver(mModelDataSetOberver); + } catch (IllegalStateException e) { + //Oh, well... fixes issue #557 + } + } + ViewTreeObserver viewTreeObserver = getViewTreeObserver(); + if (viewTreeObserver.isAlive()) { + viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener); + } + mIsAttachedToWindow = false; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + View child = mActivityChooserContent; + // If the default action is not visible we want to be as tall as the + // ActionBar so if this widget is used in the latter it will look as + // a normal action button. + if (mDefaultActivityButton.getVisibility() != VISIBLE) { + heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), + MeasureSpec.EXACTLY); + } + measureChild(child, widthMeasureSpec, heightMeasureSpec); + setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight()); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + mActivityChooserContent.layout(0, 0, right - left, bottom - top); + if (getListPopupWindow().isShowing()) { + showPopupUnchecked(mAdapter.getMaxActivityCount()); + } else { + dismissPopup(); + } + } + + public ActivityChooserModel getDataModel() { + return mAdapter.getDataModel(); + } + + /** + * Sets a listener to receive a callback when the popup is dismissed. + * + * @param listener The listener to be notified. + */ + public void setOnDismissListener(PopupWindow.OnDismissListener listener) { + mOnDismissListener = listener; + } + + /** + * Sets the initial count of items shown in the activities popup + * i.e. the items before the popup is expanded. This is an upper + * bound since it is not guaranteed that such number of intent + * handlers exist. + * + * @param itemCount The initial popup item count. + */ + public void setInitialActivityCount(int itemCount) { + mInitialActivityCount = itemCount; + } + + /** + * Sets a content description of the default action button. This + * resource should be a string taking one formatting argument and + * will be used for formatting the content description of the button + * dynamically as the default target changes. For example, a resource + * pointing to the string "share with %1$s" will result in a content + * description "share with Bluetooth" for the Bluetooth activity. + * + * @param resourceId The resource id. + */ + public void setDefaultActionButtonContentDescription(int resourceId) { + mDefaultActionButtonContentDescription = resourceId; + } + + /** + * Gets the list popup window which is lazily initialized. + * + * @return The popup. + */ + private IcsListPopupWindow getListPopupWindow() { + if (mListPopupWindow == null) { + mListPopupWindow = new IcsListPopupWindow(getContext()); + mListPopupWindow.setAdapter(mAdapter); + mListPopupWindow.setAnchorView(ActivityChooserView.this); + mListPopupWindow.setModal(true); + mListPopupWindow.setOnItemClickListener(mCallbacks); + mListPopupWindow.setOnDismissListener(mCallbacks); + } + return mListPopupWindow; + } + + /** + * Updates the buttons state. + */ + private void updateAppearance() { + // Expand overflow button. + if (mAdapter.getCount() > 0) { + mExpandActivityOverflowButton.setEnabled(true); + } else { + mExpandActivityOverflowButton.setEnabled(false); + } + // Default activity button. + final int activityCount = mAdapter.getActivityCount(); + final int historySize = mAdapter.getHistorySize(); + if (activityCount > 0 && historySize > 0) { + mDefaultActivityButton.setVisibility(VISIBLE); + ResolveInfo activity = mAdapter.getDefaultActivity(); + PackageManager packageManager = mContext.getPackageManager(); + mDefaultActivityButtonImage.setImageDrawable(activity.loadIcon(packageManager)); + if (mDefaultActionButtonContentDescription != 0) { + CharSequence label = activity.loadLabel(packageManager); + String contentDescription = mContext.getString( + mDefaultActionButtonContentDescription, label); + mDefaultActivityButton.setContentDescription(contentDescription); + } + } else { + mDefaultActivityButton.setVisibility(View.GONE); + } + // Activity chooser content. + if (mDefaultActivityButton.getVisibility() == VISIBLE) { + mActivityChooserContent.setBackgroundDrawable(mActivityChooserContentBackground); + } else { + mActivityChooserContent.setBackgroundDrawable(null); + mActivityChooserContent.setPadding(0, 0, 0, 0); + } + } + + /** + * Interface implementation to avoid publishing them in the APIs. + */ + private class Callbacks implements AdapterView.OnItemClickListener, + View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener { + + // AdapterView#OnItemClickListener + public void onItemClick(AdapterView parent, View view, int position, long id) { + ActivityChooserViewAdapter adapter = (ActivityChooserViewAdapter) parent.getAdapter(); + final int itemViewType = adapter.getItemViewType(position); + switch (itemViewType) { + case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_FOOTER: { + showPopupUnchecked(ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED); + } break; + case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_ACTIVITY: { + dismissPopup(); + if (mIsSelectingDefaultActivity) { + // The item at position zero is the default already. + if (position > 0) { + mAdapter.getDataModel().setDefaultActivity(position); + } + } else { + // If the default target is not shown in the list, the first + // item in the model is default action => adjust index + position = mAdapter.getShowDefaultActivity() ? position : position + 1; + Intent launchIntent = mAdapter.getDataModel().chooseActivity(position); + if (launchIntent != null) { + mContext.startActivity(launchIntent); + } + } + } break; + default: + throw new IllegalArgumentException(); + } + } + + // View.OnClickListener + public void onClick(View view) { + if (view == mDefaultActivityButton) { + dismissPopup(); + ResolveInfo defaultActivity = mAdapter.getDefaultActivity(); + final int index = mAdapter.getDataModel().getActivityIndex(defaultActivity); + Intent launchIntent = mAdapter.getDataModel().chooseActivity(index); + if (launchIntent != null) { + mContext.startActivity(launchIntent); + } + } else if (view == mExpandActivityOverflowButton) { + mIsSelectingDefaultActivity = false; + showPopupUnchecked(mInitialActivityCount); + } else { + throw new IllegalArgumentException(); + } + } + + // OnLongClickListener#onLongClick + @Override + public boolean onLongClick(View view) { + if (view == mDefaultActivityButton) { + if (mAdapter.getCount() > 0) { + mIsSelectingDefaultActivity = true; + showPopupUnchecked(mInitialActivityCount); + } + } else { + throw new IllegalArgumentException(); + } + return true; + } + + // PopUpWindow.OnDismissListener#onDismiss + public void onDismiss() { + notifyOnDismissListener(); + if (mProvider != null) { + mProvider.subUiVisibilityChanged(false); + } + } + + private void notifyOnDismissListener() { + if (mOnDismissListener != null) { + mOnDismissListener.onDismiss(); + } + } + } + + private static class SetActivated { + public static void invoke(View view, boolean activated) { + view.setActivated(activated); + } + } + + private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; + + /** + * Adapter for backing the list of activities shown in the popup. + */ + private class ActivityChooserViewAdapter extends BaseAdapter { + + public static final int MAX_ACTIVITY_COUNT_UNLIMITED = Integer.MAX_VALUE; + + public static final int MAX_ACTIVITY_COUNT_DEFAULT = 4; + + private static final int ITEM_VIEW_TYPE_ACTIVITY = 0; + + private static final int ITEM_VIEW_TYPE_FOOTER = 1; + + private static final int ITEM_VIEW_TYPE_COUNT = 3; + + private ActivityChooserModel mDataModel; + + private int mMaxActivityCount = MAX_ACTIVITY_COUNT_DEFAULT; + + private boolean mShowDefaultActivity; + + private boolean mHighlightDefaultActivity; + + private boolean mShowFooterView; + + public void setDataModel(ActivityChooserModel dataModel) { + ActivityChooserModel oldDataModel = mAdapter.getDataModel(); + if (oldDataModel != null && isShown()) { + try { + oldDataModel.unregisterObserver(mModelDataSetOberver); + } catch (IllegalStateException e) { + //Oh, well... fixes issue #557 + } + } + mDataModel = dataModel; + if (dataModel != null && isShown()) { + dataModel.registerObserver(mModelDataSetOberver); + } + notifyDataSetChanged(); + } + + @Override + public int getItemViewType(int position) { + if (mShowFooterView && position == getCount() - 1) { + return ITEM_VIEW_TYPE_FOOTER; + } else { + return ITEM_VIEW_TYPE_ACTIVITY; + } + } + + @Override + public int getViewTypeCount() { + return ITEM_VIEW_TYPE_COUNT; + } + + public int getCount() { + int count = 0; + int activityCount = mDataModel.getActivityCount(); + if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) { + activityCount--; + } + count = Math.min(activityCount, mMaxActivityCount); + if (mShowFooterView) { + count++; + } + return count; + } + + public Object getItem(int position) { + final int itemViewType = getItemViewType(position); + switch (itemViewType) { + case ITEM_VIEW_TYPE_FOOTER: + return null; + case ITEM_VIEW_TYPE_ACTIVITY: + if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) { + position++; + } + return mDataModel.getActivity(position); + default: + throw new IllegalArgumentException(); + } + } + + public long getItemId(int position) { + return position; + } + + public View getView(int position, View convertView, ViewGroup parent) { + final int itemViewType = getItemViewType(position); + switch (itemViewType) { + case ITEM_VIEW_TYPE_FOOTER: + if (convertView == null || convertView.getId() != ITEM_VIEW_TYPE_FOOTER) { + convertView = LayoutInflater.from(getContext()).inflate( + R.layout.abs__activity_chooser_view_list_item, parent, false); + convertView.setId(ITEM_VIEW_TYPE_FOOTER); + TextView titleView = (TextView) convertView.findViewById(R.id.abs__title); + titleView.setText(mContext.getString( + R.string.abs__activity_chooser_view_see_all)); + } + return convertView; + case ITEM_VIEW_TYPE_ACTIVITY: + if (convertView == null || convertView.getId() != R.id.abs__list_item) { + convertView = LayoutInflater.from(getContext()).inflate( + R.layout.abs__activity_chooser_view_list_item, parent, false); + } + PackageManager packageManager = mContext.getPackageManager(); + // Set the icon + ImageView iconView = (ImageView) convertView.findViewById(R.id.abs__icon); + ResolveInfo activity = (ResolveInfo) getItem(position); + iconView.setImageDrawable(activity.loadIcon(packageManager)); + // Set the title. + TextView titleView = (TextView) convertView.findViewById(R.id.abs__title); + titleView.setText(activity.loadLabel(packageManager)); + if (IS_HONEYCOMB) { + // Highlight the default. + if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) { + SetActivated.invoke(convertView, true); + } else { + SetActivated.invoke(convertView, false); + } + } + return convertView; + default: + throw new IllegalArgumentException(); + } + } + + public int measureContentWidth() { + // The user may have specified some of the target not to be shown but we + // want to measure all of them since after expansion they should fit. + final int oldMaxActivityCount = mMaxActivityCount; + mMaxActivityCount = MAX_ACTIVITY_COUNT_UNLIMITED; + + int contentWidth = 0; + View itemView = null; + + final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + final int count = getCount(); + + for (int i = 0; i < count; i++) { + itemView = getView(i, itemView, null); + itemView.measure(widthMeasureSpec, heightMeasureSpec); + contentWidth = Math.max(contentWidth, itemView.getMeasuredWidth()); + } + + mMaxActivityCount = oldMaxActivityCount; + + return contentWidth; + } + + public void setMaxActivityCount(int maxActivityCount) { + if (mMaxActivityCount != maxActivityCount) { + mMaxActivityCount = maxActivityCount; + notifyDataSetChanged(); + } + } + + public ResolveInfo getDefaultActivity() { + return mDataModel.getDefaultActivity(); + } + + public void setShowFooterView(boolean showFooterView) { + if (mShowFooterView != showFooterView) { + mShowFooterView = showFooterView; + notifyDataSetChanged(); + } + } + + public int getActivityCount() { + return mDataModel.getActivityCount(); + } + + public int getHistorySize() { + return mDataModel.getHistorySize(); + } + + public int getMaxActivityCount() { + return mMaxActivityCount; + } + + public ActivityChooserModel getDataModel() { + return mDataModel; + } + + public void setShowDefaultActivity(boolean showDefaultActivity, + boolean highlightDefaultActivity) { + if (mShowDefaultActivity != showDefaultActivity + || mHighlightDefaultActivity != highlightDefaultActivity) { + mShowDefaultActivity = showDefaultActivity; + mHighlightDefaultActivity = highlightDefaultActivity; + notifyDataSetChanged(); + } + } + + public boolean getShowDefaultActivity() { + return mShowDefaultActivity; + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/SearchView.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/SearchView.java new file mode 100644 index 00000000..c9e7897d --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/SearchView.java @@ -0,0 +1,1811 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.widget; + +import android.app.PendingIntent; +import android.app.SearchManager; +import android.app.SearchableInfo; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.database.Cursor; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.ResultReceiver; +import android.speech.RecognizerIntent; +import android.support.v4.view.KeyEventCompat; +import android.support.v4.widget.CursorAdapter; +import android.text.Editable; +import android.text.InputType; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.text.style.ImageSpan; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewTreeObserver; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.AutoCompleteTextView; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; +import com.actionbarsherlock.R; +import com.actionbarsherlock.view.CollapsibleActionView; + +import java.lang.reflect.Method; +import java.util.WeakHashMap; + +import static com.actionbarsherlock.widget.SuggestionsAdapter.getColumnString; + +/** + * A widget that provides a user interface for the user to enter a search query and submit a request + * to a search provider. Shows a list of query suggestions or results, if available, and allows the + * user to pick a suggestion or result to launch into. + * + *

+ * When the SearchView is used in an ActionBar as an action view for a collapsible menu item, it + * needs to be set to iconified by default using {@link #setIconifiedByDefault(boolean) + * setIconifiedByDefault(true)}. This is the default, so nothing needs to be done. + *

+ *

+ * If you want the search field to always be visible, then call setIconifiedByDefault(false). + *

+ * + *
+ *

Developer Guides

+ *

For information about using {@code SearchView}, read the + * Search developer guide.

+ *
+ * + * @see android.view.MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW + * @attr ref android.R.styleable#SearchView_iconifiedByDefault + * @attr ref android.R.styleable#SearchView_imeOptions + * @attr ref android.R.styleable#SearchView_inputType + * @attr ref android.R.styleable#SearchView_maxWidth + * @attr ref android.R.styleable#SearchView_queryHint + */ +public class SearchView extends LinearLayout implements CollapsibleActionView { + + private static final boolean DBG = false; + private static final String LOG_TAG = "SearchView"; + + /** + * Private constant for removing the microphone in the keyboard. + */ + private static final String IME_OPTION_NO_MICROPHONE = "nm"; + + private OnQueryTextListener mOnQueryChangeListener; + private OnCloseListener mOnCloseListener; + private OnFocusChangeListener mOnQueryTextFocusChangeListener; + private OnSuggestionListener mOnSuggestionListener; + private OnClickListener mOnSearchClickListener; + + private boolean mIconifiedByDefault; + private boolean mIconified; + private CursorAdapter mSuggestionsAdapter; + private View mSearchButton; + private View mSubmitButton; + private View mSearchPlate; + private View mSubmitArea; + private ImageView mCloseButton; + private View mSearchEditFrame; + private View mVoiceButton; + private SearchAutoComplete mQueryTextView; + private View mDropDownAnchor; + private ImageView mSearchHintIcon; + private boolean mSubmitButtonEnabled; + private CharSequence mQueryHint; + private boolean mQueryRefinement; + private boolean mClearingFocus; + private int mMaxWidth; + private boolean mVoiceButtonEnabled; + private CharSequence mOldQueryText; + private CharSequence mUserQuery; + private boolean mExpandedInActionView; + private int mCollapsedImeOptions; + + private SearchableInfo mSearchable; + private Bundle mAppSearchData; + + /* + * SearchView can be set expanded before the IME is ready to be shown during + * initial UI setup. The show operation is asynchronous to account for this. + */ + private Runnable mShowImeRunnable = new Runnable() { + public void run() { + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + + if (imm != null) { + showSoftInputUnchecked(SearchView.this, imm, 0); + } + } + }; + + private Runnable mUpdateDrawableStateRunnable = new Runnable() { + public void run() { + updateFocusedState(); + } + }; + + private Runnable mReleaseCursorRunnable = new Runnable() { + public void run() { + if (mSuggestionsAdapter != null && mSuggestionsAdapter instanceof SuggestionsAdapter) { + mSuggestionsAdapter.changeCursor(null); + } + } + }; + + // For voice searching + private final Intent mVoiceWebSearchIntent; + private final Intent mVoiceAppSearchIntent; + + // A weak map of drawables we've gotten from other packages, so we don't load them + // more than once. + private final WeakHashMap mOutsideDrawablesCache = + new WeakHashMap(); + + /** + * Callbacks for changes to the query text. + */ + public interface OnQueryTextListener { + + /** + * Called when the user submits the query. This could be due to a key press on the + * keyboard or due to pressing a submit button. + * The listener can override the standard behavior by returning true + * to indicate that it has handled the submit request. Otherwise return false to + * let the SearchView handle the submission by launching any associated intent. + * + * @param query the query text that is to be submitted + * + * @return true if the query has been handled by the listener, false to let the + * SearchView perform the default action. + */ + boolean onQueryTextSubmit(String query); + + /** + * Called when the query text is changed by the user. + * + * @param newText the new content of the query text field. + * + * @return false if the SearchView should perform the default action of showing any + * suggestions if available, true if the action was handled by the listener. + */ + boolean onQueryTextChange(String newText); + } + + public interface OnCloseListener { + + /** + * The user is attempting to close the SearchView. + * + * @return true if the listener wants to override the default behavior of clearing the + * text field and dismissing it, false otherwise. + */ + boolean onClose(); + } + + /** + * Callback interface for selection events on suggestions. These callbacks + * are only relevant when a SearchableInfo has been specified by {@link #setSearchableInfo}. + */ + public interface OnSuggestionListener { + + /** + * Called when a suggestion was selected by navigating to it. + * @param position the absolute position in the list of suggestions. + * + * @return true if the listener handles the event and wants to override the default + * behavior of possibly rewriting the query based on the selected item, false otherwise. + */ + boolean onSuggestionSelect(int position); + + /** + * Called when a suggestion was clicked. + * @param position the absolute position of the clicked item in the list of suggestions. + * + * @return true if the listener handles the event and wants to override the default + * behavior of launching any intent or submitting a search query specified on that item. + * Return false otherwise. + */ + boolean onSuggestionClick(int position); + } + + public SearchView(Context context) { + this(context, null); + } + + public SearchView(Context context, AttributeSet attrs) { + super(context, attrs); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { + throw new IllegalStateException("SearchView is API 8+ only."); + } + + LayoutInflater inflater = (LayoutInflater) context + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + inflater.inflate(R.layout.abs__search_view, this, true); + + mSearchButton = findViewById(R.id.abs__search_button); + mQueryTextView = (SearchAutoComplete) findViewById(R.id.abs__search_src_text); + mQueryTextView.setSearchView(this); + + mSearchEditFrame = findViewById(R.id.abs__search_edit_frame); + mSearchPlate = findViewById(R.id.abs__search_plate); + mSubmitArea = findViewById(R.id.abs__submit_area); + mSubmitButton = findViewById(R.id.abs__search_go_btn); + mCloseButton = (ImageView) findViewById(R.id.abs__search_close_btn); + mVoiceButton = findViewById(R.id.abs__search_voice_btn); + mSearchHintIcon = (ImageView) findViewById(R.id.abs__search_mag_icon); + + mSearchButton.setOnClickListener(mOnClickListener); + mCloseButton.setOnClickListener(mOnClickListener); + mSubmitButton.setOnClickListener(mOnClickListener); + mVoiceButton.setOnClickListener(mOnClickListener); + mQueryTextView.setOnClickListener(mOnClickListener); + + mQueryTextView.addTextChangedListener(mTextWatcher); + mQueryTextView.setOnEditorActionListener(mOnEditorActionListener); + mQueryTextView.setOnItemClickListener(mOnItemClickListener); + mQueryTextView.setOnItemSelectedListener(mOnItemSelectedListener); + mQueryTextView.setOnKeyListener(mTextKeyListener); + // Inform any listener of focus changes + mQueryTextView.setOnFocusChangeListener(new OnFocusChangeListener() { + + public void onFocusChange(View v, boolean hasFocus) { + if (mOnQueryTextFocusChangeListener != null) { + mOnQueryTextFocusChangeListener.onFocusChange(SearchView.this, hasFocus); + } + } + }); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockSearchView, 0, 0); + setIconifiedByDefault(a.getBoolean(R.styleable.SherlockSearchView_iconifiedByDefault, true)); + int maxWidth = a.getDimensionPixelSize(R.styleable.SherlockSearchView_android_maxWidth, -1); + if (maxWidth != -1) { + setMaxWidth(maxWidth); + } + CharSequence queryHint = a.getText(R.styleable.SherlockSearchView_queryHint); + if (!TextUtils.isEmpty(queryHint)) { + setQueryHint(queryHint); + } + int imeOptions = a.getInt(R.styleable.SherlockSearchView_android_imeOptions, -1); + if (imeOptions != -1) { + setImeOptions(imeOptions); + } + int inputType = a.getInt(R.styleable.SherlockSearchView_android_inputType, -1); + if (inputType != -1) { + setInputType(inputType); + } + + a.recycle(); + + boolean focusable = true; + + a = context.obtainStyledAttributes(attrs, R.styleable.SherlockView, 0, 0); + focusable = a.getBoolean(R.styleable.SherlockView_android_focusable, focusable); + a.recycle(); + setFocusable(focusable); + + // Save voice intent for later queries/launching + mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH); + mVoiceWebSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mVoiceWebSearchIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, + RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH); + + mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); + mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + mDropDownAnchor = findViewById(mQueryTextView.getDropDownAnchor()); + if (mDropDownAnchor != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + mDropDownAnchor.addOnLayoutChangeListener(new OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { + adjustDropDownSizeAndPosition(); + } + }); + } else { + mDropDownAnchor.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override public void onGlobalLayout() { + adjustDropDownSizeAndPosition(); + } + }); + } + } + + updateViewsVisibility(mIconifiedByDefault); + updateQueryHint(); + } + + /** + * Sets the SearchableInfo for this SearchView. Properties in the SearchableInfo are used + * to display labels, hints, suggestions, create intents for launching search results screens + * and controlling other affordances such as a voice button. + * + * @param searchable a SearchableInfo can be retrieved from the SearchManager, for a specific + * activity or a global search provider. + */ + public void setSearchableInfo(SearchableInfo searchable) { + mSearchable = searchable; + if (mSearchable != null) { + updateSearchAutoComplete(); + updateQueryHint(); + } + // Cache the voice search capability + mVoiceButtonEnabled = hasVoiceSearch(); + + if (mVoiceButtonEnabled) { + // Disable the microphone on the keyboard, as a mic is displayed near the text box + // TODO: use imeOptions to disable voice input when the new API will be available + mQueryTextView.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE); + } + updateViewsVisibility(isIconified()); + } + + /** + * Sets the APP_DATA for legacy SearchDialog use. + * @param appSearchData bundle provided by the app when launching the search dialog + * @hide + */ + public void setAppSearchData(Bundle appSearchData) { + mAppSearchData = appSearchData; + } + + /** + * Sets the IME options on the query text field. + * + * @see TextView#setImeOptions(int) + * @param imeOptions the options to set on the query text field + * + * @attr ref android.R.styleable#SearchView_imeOptions + */ + public void setImeOptions(int imeOptions) { + mQueryTextView.setImeOptions(imeOptions); + } + + /** + * Returns the IME options set on the query text field. + * @return the ime options + * @see TextView#setImeOptions(int) + * + * @attr ref android.R.styleable#SearchView_imeOptions + */ + public int getImeOptions() { + return mQueryTextView.getImeOptions(); + } + + /** + * Sets the input type on the query text field. + * + * @see TextView#setInputType(int) + * @param inputType the input type to set on the query text field + * + * @attr ref android.R.styleable#SearchView_inputType + */ + public void setInputType(int inputType) { + mQueryTextView.setInputType(inputType); + } + + /** + * Returns the input type set on the query text field. + * @return the input type + * + * @attr ref android.R.styleable#SearchView_inputType + */ + public int getInputType() { + return mQueryTextView.getInputType(); + } + + /** @hide */ + @Override + public boolean requestFocus(int direction, Rect previouslyFocusedRect) { + // Don't accept focus if in the middle of clearing focus + if (mClearingFocus) return false; + // Check if SearchView is focusable. + if (!isFocusable()) return false; + // If it is not iconified, then give the focus to the text field + if (!isIconified()) { + boolean result = mQueryTextView.requestFocus(direction, previouslyFocusedRect); + if (result) { + updateViewsVisibility(false); + } + return result; + } else { + return super.requestFocus(direction, previouslyFocusedRect); + } + } + + /** @hide */ + @Override + public void clearFocus() { + mClearingFocus = true; + setImeVisibility(false); + super.clearFocus(); + mQueryTextView.clearFocus(); + mClearingFocus = false; + } + + /** + * Sets a listener for user actions within the SearchView. + * + * @param listener the listener object that receives callbacks when the user performs + * actions in the SearchView such as clicking on buttons or typing a query. + */ + public void setOnQueryTextListener(OnQueryTextListener listener) { + mOnQueryChangeListener = listener; + } + + /** + * Sets a listener to inform when the user closes the SearchView. + * + * @param listener the listener to call when the user closes the SearchView. + */ + public void setOnCloseListener(OnCloseListener listener) { + mOnCloseListener = listener; + } + + /** + * Sets a listener to inform when the focus of the query text field changes. + * + * @param listener the listener to inform of focus changes. + */ + public void setOnQueryTextFocusChangeListener(OnFocusChangeListener listener) { + mOnQueryTextFocusChangeListener = listener; + } + + /** + * Sets a listener to inform when a suggestion is focused or clicked. + * + * @param listener the listener to inform of suggestion selection events. + */ + public void setOnSuggestionListener(OnSuggestionListener listener) { + mOnSuggestionListener = listener; + } + + /** + * Sets a listener to inform when the search button is pressed. This is only + * relevant when the text field is not visible by default. Calling {@link #setIconified + * setIconified(false)} can also cause this listener to be informed. + * + * @param listener the listener to inform when the search button is clicked or + * the text field is programmatically de-iconified. + */ + public void setOnSearchClickListener(OnClickListener listener) { + mOnSearchClickListener = listener; + } + + /** + * Returns the query string currently in the text field. + * + * @return the query string + */ + public CharSequence getQuery() { + return mQueryTextView.getText(); + } + + /** + * Sets a query string in the text field and optionally submits the query as well. + * + * @param query the query string. This replaces any query text already present in the + * text field. + * @param submit whether to submit the query right now or only update the contents of + * text field. + */ + public void setQuery(CharSequence query, boolean submit) { + mQueryTextView.setText(query); + if (query != null) { + mQueryTextView.setSelection(mQueryTextView.length()); + mUserQuery = query; + } + + // If the query is not empty and submit is requested, submit the query + if (submit && !TextUtils.isEmpty(query)) { + onSubmitQuery(); + } + } + + /** + * Sets the hint text to display in the query text field. This overrides any hint specified + * in the SearchableInfo. + * + * @param hint the hint text to display + * + * @attr ref android.R.styleable#SearchView_queryHint + */ + public void setQueryHint(CharSequence hint) { + mQueryHint = hint; + updateQueryHint(); + } + + /** + * Gets the hint text to display in the query text field. + * @return the query hint text, if specified, null otherwise. + * + * @attr ref android.R.styleable#SearchView_queryHint + */ + public CharSequence getQueryHint() { + if (mQueryHint != null) { + return mQueryHint; + } else if (mSearchable != null) { + CharSequence hint = null; + int hintId = mSearchable.getHintId(); + if (hintId != 0) { + hint = getContext().getString(hintId); + } + return hint; + } + return null; + } + + /** + * Sets the default or resting state of the search field. If true, a single search icon is + * shown by default and expands to show the text field and other buttons when pressed. Also, + * if the default state is iconified, then it collapses to that state when the close button + * is pressed. Changes to this property will take effect immediately. + * + *

The default value is true.

+ * + * @param iconified whether the search field should be iconified by default + * + * @attr ref android.R.styleable#SearchView_iconifiedByDefault + */ + public void setIconifiedByDefault(boolean iconified) { + if (mIconifiedByDefault == iconified) return; + mIconifiedByDefault = iconified; + updateViewsVisibility(iconified); + updateQueryHint(); + } + + /** + * Returns the default iconified state of the search field. + * @return + * + * @attr ref android.R.styleable#SearchView_iconifiedByDefault + */ + public boolean isIconfiedByDefault() { + return mIconifiedByDefault; + } + + /** + * Iconifies or expands the SearchView. Any query text is cleared when iconified. This is + * a temporary state and does not override the default iconified state set by + * {@link #setIconifiedByDefault(boolean)}. If the default state is iconified, then + * a false here will only be valid until the user closes the field. And if the default + * state is expanded, then a true here will only clear the text field and not close it. + * + * @param iconify a true value will collapse the SearchView to an icon, while a false will + * expand it. + */ + public void setIconified(boolean iconify) { + if (iconify) { + onCloseClicked(); + } else { + onSearchClicked(); + } + } + + /** + * Returns the current iconified state of the SearchView. + * + * @return true if the SearchView is currently iconified, false if the search field is + * fully visible. + */ + public boolean isIconified() { + return mIconified; + } + + /** + * Enables showing a submit button when the query is non-empty. In cases where the SearchView + * is being used to filter the contents of the current activity and doesn't launch a separate + * results activity, then the submit button should be disabled. + * + * @param enabled true to show a submit button for submitting queries, false if a submit + * button is not required. + */ + public void setSubmitButtonEnabled(boolean enabled) { + mSubmitButtonEnabled = enabled; + updateViewsVisibility(isIconified()); + } + + /** + * Returns whether the submit button is enabled when necessary or never displayed. + * + * @return whether the submit button is enabled automatically when necessary + */ + public boolean isSubmitButtonEnabled() { + return mSubmitButtonEnabled; + } + + /** + * Specifies if a query refinement button should be displayed alongside each suggestion + * or if it should depend on the flags set in the individual items retrieved from the + * suggestions provider. Clicking on the query refinement button will replace the text + * in the query text field with the text from the suggestion. This flag only takes effect + * if a SearchableInfo has been specified with {@link #setSearchableInfo(SearchableInfo)} + * and not when using a custom adapter. + * + * @param enable true if all items should have a query refinement button, false if only + * those items that have a query refinement flag set should have the button. + * + * @see SearchManager#SUGGEST_COLUMN_FLAGS + * @see SearchManager#FLAG_QUERY_REFINEMENT + */ + public void setQueryRefinementEnabled(boolean enable) { + mQueryRefinement = enable; + if (mSuggestionsAdapter instanceof SuggestionsAdapter) { + ((SuggestionsAdapter) mSuggestionsAdapter).setQueryRefinement( + enable ? SuggestionsAdapter.REFINE_ALL : SuggestionsAdapter.REFINE_BY_ENTRY); + } + } + + /** + * Returns whether query refinement is enabled for all items or only specific ones. + * @return true if enabled for all items, false otherwise. + */ + public boolean isQueryRefinementEnabled() { + return mQueryRefinement; + } + + /** + * You can set a custom adapter if you wish. Otherwise the default adapter is used to + * display the suggestions from the suggestions provider associated with the SearchableInfo. + * + * @see #setSearchableInfo(SearchableInfo) + */ + public void setSuggestionsAdapter(CursorAdapter adapter) { + mSuggestionsAdapter = adapter; + + mQueryTextView.setAdapter(mSuggestionsAdapter); + } + + /** + * Returns the adapter used for suggestions, if any. + * @return the suggestions adapter + */ + public CursorAdapter getSuggestionsAdapter() { + return mSuggestionsAdapter; + } + + /** + * Makes the view at most this many pixels wide + * + * @attr ref android.R.styleable#SearchView_maxWidth + */ + public void setMaxWidth(int maxpixels) { + mMaxWidth = maxpixels; + + requestLayout(); + } + + /** + * Gets the specified maximum width in pixels, if set. Returns zero if + * no maximum width was specified. + * @return the maximum width of the view + * + * @attr ref android.R.styleable#SearchView_maxWidth + */ + public int getMaxWidth() { + return mMaxWidth; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + // Let the standard measurements take effect in iconified state. + if (isIconified()) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + return; + } + + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int width = MeasureSpec.getSize(widthMeasureSpec); + + switch (widthMode) { + case MeasureSpec.AT_MOST: + // If there is an upper limit, don't exceed maximum width (explicit or implicit) + if (mMaxWidth > 0) { + width = Math.min(mMaxWidth, width); + } else { + width = Math.min(getPreferredWidth(), width); + } + break; + case MeasureSpec.EXACTLY: + // If an exact width is specified, still don't exceed any specified maximum width + if (mMaxWidth > 0) { + width = Math.min(mMaxWidth, width); + } + break; + case MeasureSpec.UNSPECIFIED: + // Use maximum width, if specified, else preferred width + width = mMaxWidth > 0 ? mMaxWidth : getPreferredWidth(); + break; + } + widthMode = MeasureSpec.EXACTLY; + super.onMeasure(MeasureSpec.makeMeasureSpec(width, widthMode), heightMeasureSpec); + } + + private int getPreferredWidth() { + return getContext().getResources() + .getDimensionPixelSize(R.dimen.abs__search_view_preferred_width); + } + + private void updateViewsVisibility(final boolean collapsed) { + mIconified = collapsed; + // Visibility of views that are visible when collapsed + final int visCollapsed = collapsed ? VISIBLE : GONE; + // Is there text in the query + final boolean hasText = !TextUtils.isEmpty(mQueryTextView.getText()); + + mSearchButton.setVisibility(visCollapsed); + updateSubmitButton(hasText); + mSearchEditFrame.setVisibility(collapsed ? GONE : VISIBLE); + mSearchHintIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE); + updateCloseButton(); + updateVoiceButton(!hasText); + updateSubmitArea(); + } + + private boolean hasVoiceSearch() { + if (mSearchable != null && mSearchable.getVoiceSearchEnabled()) { + Intent testIntent = null; + if (mSearchable.getVoiceSearchLaunchWebSearch()) { + testIntent = mVoiceWebSearchIntent; + } else if (mSearchable.getVoiceSearchLaunchRecognizer()) { + testIntent = mVoiceAppSearchIntent; + } + if (testIntent != null) { + ResolveInfo ri = getContext().getPackageManager().resolveActivity(testIntent, + PackageManager.MATCH_DEFAULT_ONLY); + return ri != null; + } + } + return false; + } + + private boolean isSubmitAreaEnabled() { + return (mSubmitButtonEnabled || mVoiceButtonEnabled) && !isIconified(); + } + + private void updateSubmitButton(boolean hasText) { + int visibility = GONE; + if (mSubmitButtonEnabled && isSubmitAreaEnabled() && hasFocus() + && (hasText || !mVoiceButtonEnabled)) { + visibility = VISIBLE; + } + mSubmitButton.setVisibility(visibility); + } + + private void updateSubmitArea() { + int visibility = GONE; + if (isSubmitAreaEnabled() + && (mSubmitButton.getVisibility() == VISIBLE + || mVoiceButton.getVisibility() == VISIBLE)) { + visibility = VISIBLE; + } + mSubmitArea.setVisibility(visibility); + } + + private void updateCloseButton() { + final boolean hasText = !TextUtils.isEmpty(mQueryTextView.getText()); + // Should we show the close button? It is not shown if there's no focus, + // field is not iconified by default and there is no text in it. + final boolean showClose = hasText || (mIconifiedByDefault && !mExpandedInActionView); + mCloseButton.setVisibility(showClose ? VISIBLE : GONE); + mCloseButton.getDrawable().setState(hasText ? ENABLED_STATE_SET : EMPTY_STATE_SET); + } + + private void postUpdateFocusedState() { + post(mUpdateDrawableStateRunnable); + } + + private void updateFocusedState() { + boolean focused = mQueryTextView.hasFocus(); + mSearchPlate.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET); + mSubmitArea.getBackground().setState(focused ? FOCUSED_STATE_SET : EMPTY_STATE_SET); + invalidate(); + } + + @Override + protected void onDetachedFromWindow() { + removeCallbacks(mUpdateDrawableStateRunnable); + post(mReleaseCursorRunnable); + super.onDetachedFromWindow(); + } + + private void setImeVisibility(final boolean visible) { + if (visible) { + post(mShowImeRunnable); + } else { + removeCallbacks(mShowImeRunnable); + InputMethodManager imm = (InputMethodManager) + getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + + if (imm != null) { + imm.hideSoftInputFromWindow(getWindowToken(), 0); + } + } + } + + /** + * Called by the SuggestionsAdapter + * @hide + */ + /* package */void onQueryRefine(CharSequence queryText) { + setQuery(queryText); + } + + private final OnClickListener mOnClickListener = new OnClickListener() { + + public void onClick(View v) { + if (v == mSearchButton) { + onSearchClicked(); + } else if (v == mCloseButton) { + onCloseClicked(); + } else if (v == mSubmitButton) { + onSubmitQuery(); + } else if (v == mVoiceButton) { + onVoiceClicked(); + } else if (v == mQueryTextView) { + forceSuggestionQuery(); + } + } + }; + + /** + * Handles the key down event for dealing with action keys. + * + * @param keyCode This is the keycode of the typed key, and is the same value as + * found in the KeyEvent parameter. + * @param event The complete event record for the typed key + * + * @return true if the event was handled here, or false if not. + */ + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (mSearchable == null) { + return false; + } + + // if it's an action specified by the searchable activity, launch the + // entered query with the action key + // TODO SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); + // TODO if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) { + // TODO launchQuerySearch(keyCode, actionKey.getQueryActionMsg(), mQueryTextView.getText() + // TODO .toString()); + // TODO return true; + // TODO } + + return super.onKeyDown(keyCode, event); + } + + /** + * React to the user typing "enter" or other hardwired keys while typing in + * the search box. This handles these special keys while the edit box has + * focus. + */ + View.OnKeyListener mTextKeyListener = new View.OnKeyListener() { + public boolean onKey(View v, int keyCode, KeyEvent event) { + // guard against possible race conditions + if (mSearchable == null) { + return false; + } + + if (DBG) { + Log.d(LOG_TAG, "mTextListener.onKey(" + keyCode + "," + event + "), selection: " + + mQueryTextView.getListSelection()); + } + + // If a suggestion is selected, handle enter, search key, and action keys + // as presses on the selected suggestion + if (mQueryTextView.isPopupShowing() + && mQueryTextView.getListSelection() != ListView.INVALID_POSITION) { + return onSuggestionsKey(v, keyCode, event); + } + + // If there is text in the query box, handle enter, and action keys + // The search key is handled by the dialog's onKeyDown(). + if (!mQueryTextView.isEmpty() && KeyEventCompat.hasNoModifiers(event)) { + if (event.getAction() == KeyEvent.ACTION_UP) { + if (keyCode == KeyEvent.KEYCODE_ENTER) { + v.cancelLongPress(); + + // Launch as a regular search. + launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, mQueryTextView.getText() + .toString()); + return true; + } + } + if (event.getAction() == KeyEvent.ACTION_DOWN) { + // TODO SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); + // TODO if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) { + // TODO launchQuerySearch(keyCode, actionKey.getQueryActionMsg(), mQueryTextView + // TODO .getText().toString()); + // TODO return true; + // TODO } + } + } + return false; + } + }; + + /** + * React to the user typing while in the suggestions list. First, check for + * action keys. If not handled, try refocusing regular characters into the + * EditText. + */ + private boolean onSuggestionsKey(View v, int keyCode, KeyEvent event) { + // guard against possible race conditions (late arrival after dismiss) + if (mSearchable == null) { + return false; + } + if (mSuggestionsAdapter == null) { + return false; + } + if (event.getAction() == KeyEvent.ACTION_DOWN && KeyEventCompat.hasNoModifiers(event)) { + // First, check for enter or search (both of which we'll treat as a + // "click") + if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH + || keyCode == KeyEvent.KEYCODE_TAB) { + int position = mQueryTextView.getListSelection(); + return onItemClicked(position, KeyEvent.KEYCODE_UNKNOWN, null); + } + + // Next, check for left/right moves, which we use to "return" the + // user to the edit view + if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { + // give "focus" to text editor, with cursor at the beginning if + // left key, at end if right key + // TODO: Reverse left/right for right-to-left languages, e.g. + // Arabic + int selPoint = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? 0 : mQueryTextView + .length(); + mQueryTextView.setSelection(selPoint); + mQueryTextView.setListSelection(0); + mQueryTextView.clearListSelection(); + ensureImeVisible(mQueryTextView, true); + + return true; + } + + // Next, check for an "up and out" move + if (keyCode == KeyEvent.KEYCODE_DPAD_UP && 0 == mQueryTextView.getListSelection()) { + // TODO: restoreUserQuery(); + // let ACTV complete the move + return false; + } + + // Next, check for an "action key" + // TODO SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); + // TODO if ((actionKey != null) + // TODO && ((actionKey.getSuggestActionMsg() != null) || (actionKey + // TODO .getSuggestActionMsgColumn() != null))) { + // TODO // launch suggestion using action key column + // TODO int position = mQueryTextView.getListSelection(); + // TODO if (position != ListView.INVALID_POSITION) { + // TODO Cursor c = mSuggestionsAdapter.getCursor(); + // TODO if (c.moveToPosition(position)) { + // TODO final String actionMsg = getActionKeyMessage(c, actionKey); + // TODO if (actionMsg != null && (actionMsg.length() > 0)) { + // TODO return onItemClicked(position, keyCode, actionMsg); + // TODO } + // TODO } + // TODO } + // TODO } + } + return false; + } + + /** + * For a given suggestion and a given cursor row, get the action message. If + * not provided by the specific row/column, also check for a single + * definition (for the action key). + * + * @param c The cursor providing suggestions + * @param actionKey The actionkey record being examined + * + * @return Returns a string, or null if no action key message for this + * suggestion + */ + // TODO private static String getActionKeyMessage(Cursor c, SearchableInfo.ActionKeyInfo actionKey) { + // TODO String result = null; + // TODO // check first in the cursor data, for a suggestion-specific message + // TODO final String column = actionKey.getSuggestActionMsgColumn(); + // TODO if (column != null) { + // TODO result = SuggestionsAdapter.getColumnString(c, column); + // TODO } + // TODO // If the cursor didn't give us a message, see if there's a single + // TODO // message defined + // TODO // for the actionkey (for all suggestions) + // TODO if (result == null) { + // TODO result = actionKey.getSuggestActionMsg(); + // TODO } + // TODO return result; + // TODO } + + private int getSearchIconId() { + TypedValue outValue = new TypedValue(); + getContext().getTheme().resolveAttribute(R.attr.searchViewSearchIcon, + outValue, true); + return outValue.resourceId; + } + + private CharSequence getDecoratedHint(CharSequence hintText) { + // If the field is always expanded, then don't add the search icon to the hint + if (!mIconifiedByDefault) return hintText; + + SpannableStringBuilder ssb = new SpannableStringBuilder(" "); // for the icon + ssb.append(hintText); + Drawable searchIcon = getContext().getResources().getDrawable(getSearchIconId()); + int textSize = (int) (mQueryTextView.getTextSize() * 1.25); + searchIcon.setBounds(0, 0, textSize, textSize); + ssb.setSpan(new ImageSpan(searchIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + return ssb; + } + + private void updateQueryHint() { + if (mQueryHint != null) { + mQueryTextView.setHint(getDecoratedHint(mQueryHint)); + } else if (mSearchable != null) { + CharSequence hint = null; + int hintId = mSearchable.getHintId(); + if (hintId != 0) { + hint = getContext().getString(hintId); + } + if (hint != null) { + mQueryTextView.setHint(getDecoratedHint(hint)); + } + } else { + mQueryTextView.setHint(getDecoratedHint("")); + } + } + + /** + * Updates the auto-complete text view. + */ + private void updateSearchAutoComplete() { + // TODO mQueryTextView.setDropDownAnimationStyle(0); // no animation + mQueryTextView.setThreshold(mSearchable.getSuggestThreshold()); + mQueryTextView.setImeOptions(mSearchable.getImeOptions()); + int inputType = mSearchable.getInputType(); + // We only touch this if the input type is set up for text (which it almost certainly + // should be, in the case of search!) + if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) { + // The existence of a suggestions authority is the proxy for "suggestions + // are available here" + inputType &= ~InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE; + if (mSearchable.getSuggestAuthority() != null) { + inputType |= InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE; + // TYPE_TEXT_FLAG_AUTO_COMPLETE means that the text editor is performing + // auto-completion based on its own semantics, which it will present to the user + // as they type. This generally means that the input method should not show its + // own candidates, and the spell checker should not be in action. The text editor + // supplies its candidates by calling InputMethodManager.displayCompletions(), + // which in turn will call InputMethodSession.displayCompletions(). + inputType |= InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS; + } + } + mQueryTextView.setInputType(inputType); + if (mSuggestionsAdapter != null) { + mSuggestionsAdapter.changeCursor(null); + } + // attach the suggestions adapter, if suggestions are available + // The existence of a suggestions authority is the proxy for "suggestions available here" + if (mSearchable.getSuggestAuthority() != null) { + mSuggestionsAdapter = new SuggestionsAdapter(getContext(), + this, mSearchable, mOutsideDrawablesCache); + mQueryTextView.setAdapter(mSuggestionsAdapter); + ((SuggestionsAdapter) mSuggestionsAdapter).setQueryRefinement( + mQueryRefinement ? SuggestionsAdapter.REFINE_ALL + : SuggestionsAdapter.REFINE_BY_ENTRY); + } + } + + /** + * Update the visibility of the voice button. There are actually two voice search modes, + * either of which will activate the button. + * @param empty whether the search query text field is empty. If it is, then the other + * criteria apply to make the voice button visible. + */ + private void updateVoiceButton(boolean empty) { + int visibility = GONE; + if (mVoiceButtonEnabled && !isIconified() && empty) { + visibility = VISIBLE; + mSubmitButton.setVisibility(GONE); + } + mVoiceButton.setVisibility(visibility); + } + + private final OnEditorActionListener mOnEditorActionListener = new OnEditorActionListener() { + + /** + * Called when the input method default action key is pressed. + */ + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + onSubmitQuery(); + return true; + } + }; + + private void onTextChanged(CharSequence newText) { + CharSequence text = mQueryTextView.getText(); + mUserQuery = text; + boolean hasText = !TextUtils.isEmpty(text); + updateSubmitButton(hasText); + updateVoiceButton(!hasText); + updateCloseButton(); + updateSubmitArea(); + if (mOnQueryChangeListener != null && !TextUtils.equals(newText, mOldQueryText)) { + mOnQueryChangeListener.onQueryTextChange(newText.toString()); + } + mOldQueryText = newText.toString(); + } + + private void onSubmitQuery() { + CharSequence query = mQueryTextView.getText(); + if (query != null && TextUtils.getTrimmedLength(query) > 0) { + if (mOnQueryChangeListener == null + || !mOnQueryChangeListener.onQueryTextSubmit(query.toString())) { + if (mSearchable != null) { + launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null, query.toString()); + setImeVisibility(false); + } + dismissSuggestions(); + } + } + } + + private void dismissSuggestions() { + mQueryTextView.dismissDropDown(); + } + + private void onCloseClicked() { + CharSequence text = mQueryTextView.getText(); + if (TextUtils.isEmpty(text)) { + if (mIconifiedByDefault) { + // If the app doesn't override the close behavior + if (mOnCloseListener == null || !mOnCloseListener.onClose()) { + // hide the keyboard and remove focus + clearFocus(); + // collapse the search field + updateViewsVisibility(true); + } + } + } else { + mQueryTextView.setText(""); + mQueryTextView.requestFocus(); + setImeVisibility(true); + } + + } + + private void onSearchClicked() { + updateViewsVisibility(false); + mQueryTextView.requestFocus(); + setImeVisibility(true); + if (mOnSearchClickListener != null) { + mOnSearchClickListener.onClick(this); + } + } + + private void onVoiceClicked() { + // guard against possible race conditions + if (mSearchable == null) { + return; + } + SearchableInfo searchable = mSearchable; + try { + if (searchable.getVoiceSearchLaunchWebSearch()) { + Intent webSearchIntent = createVoiceWebSearchIntent(mVoiceWebSearchIntent, + searchable); + getContext().startActivity(webSearchIntent); + } else if (searchable.getVoiceSearchLaunchRecognizer()) { + Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent, + searchable); + getContext().startActivity(appSearchIntent); + } + } catch (ActivityNotFoundException e) { + // Should not happen, since we check the availability of + // voice search before showing the button. But just in case... + Log.w(LOG_TAG, "Could not find voice search activity"); + } + } + + void onTextFocusChanged() { + updateViewsVisibility(isIconified()); + // Delayed update to make sure that the focus has settled down and window focus changes + // don't affect it. A synchronous update was not working. + postUpdateFocusedState(); + if (mQueryTextView.hasFocus()) { + forceSuggestionQuery(); + } + } + + @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + super.onWindowFocusChanged(hasWindowFocus); + + postUpdateFocusedState(); + } + + /** + * {@inheritDoc} + */ + @Override + public void onActionViewCollapsed() { + clearFocus(); + updateViewsVisibility(true); + mQueryTextView.setImeOptions(mCollapsedImeOptions); + mExpandedInActionView = false; + } + + /** + * {@inheritDoc} + */ + @Override + public void onActionViewExpanded() { + if (mExpandedInActionView) return; + + mExpandedInActionView = true; + mCollapsedImeOptions = mQueryTextView.getImeOptions(); + mQueryTextView.setImeOptions(mCollapsedImeOptions | EditorInfo.IME_FLAG_NO_FULLSCREEN); + mQueryTextView.setText(""); + setIconified(false); + } + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + event.setClassName(SearchView.class.getName()); + } + + @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setClassName(SearchView.class.getName()); + } + + private void adjustDropDownSizeAndPosition() { + if (mDropDownAnchor.getWidth() > 1) { + Resources res = getContext().getResources(); + int anchorPadding = mSearchPlate.getPaddingLeft(); + Rect dropDownPadding = new Rect(); + int iconOffset = mIconifiedByDefault + ? res.getDimensionPixelSize(R.dimen.abs__dropdownitem_icon_width) + + res.getDimensionPixelSize(R.dimen.abs__dropdownitem_text_padding_left) + : 0; + mQueryTextView.getDropDownBackground().getPadding(dropDownPadding); + mQueryTextView.setDropDownHorizontalOffset(-(dropDownPadding.left + iconOffset) + + anchorPadding); + mQueryTextView.setDropDownWidth(mDropDownAnchor.getWidth() + dropDownPadding.left + + dropDownPadding.right + iconOffset - (anchorPadding)); + } + } + + private boolean onItemClicked(int position, int actionKey, String actionMsg) { + if (mOnSuggestionListener == null + || !mOnSuggestionListener.onSuggestionClick(position)) { + launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null); + setImeVisibility(false); + dismissSuggestions(); + return true; + } + return false; + } + + private boolean onItemSelected(int position) { + if (mOnSuggestionListener == null + || !mOnSuggestionListener.onSuggestionSelect(position)) { + rewriteQueryFromSuggestion(position); + return true; + } + return false; + } + + private final OnItemClickListener mOnItemClickListener = new OnItemClickListener() { + + /** + * Implements OnItemClickListener + */ + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (DBG) Log.d(LOG_TAG, "onItemClick() position " + position); + onItemClicked(position, KeyEvent.KEYCODE_UNKNOWN, null); + } + }; + + private final OnItemSelectedListener mOnItemSelectedListener = new OnItemSelectedListener() { + + /** + * Implements OnItemSelectedListener + */ + public void onItemSelected(AdapterView parent, View view, int position, long id) { + if (DBG) Log.d(LOG_TAG, "onItemSelected() position " + position); + SearchView.this.onItemSelected(position); + } + + /** + * Implements OnItemSelectedListener + */ + public void onNothingSelected(AdapterView parent) { + if (DBG) + Log.d(LOG_TAG, "onNothingSelected()"); + } + }; + + /** + * Query rewriting. + */ + private void rewriteQueryFromSuggestion(int position) { + CharSequence oldQuery = mQueryTextView.getText(); + Cursor c = mSuggestionsAdapter.getCursor(); + if (c == null) { + return; + } + if (c.moveToPosition(position)) { + // Get the new query from the suggestion. + CharSequence newQuery = mSuggestionsAdapter.convertToString(c); + if (newQuery != null) { + // The suggestion rewrites the query. + // Update the text field, without getting new suggestions. + setQuery(newQuery); + } else { + // The suggestion does not rewrite the query, restore the user's query. + setQuery(oldQuery); + } + } else { + // We got a bad position, restore the user's query. + setQuery(oldQuery); + } + } + + /** + * Launches an intent based on a suggestion. + * + * @param position The index of the suggestion to create the intent from. + * @param actionKey The key code of the action key that was pressed, + * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. + * @param actionMsg The message for the action key that was pressed, + * or null if none. + * @return true if a successful launch, false if could not (e.g. bad position). + */ + private boolean launchSuggestion(int position, int actionKey, String actionMsg) { + Cursor c = mSuggestionsAdapter.getCursor(); + if ((c != null) && c.moveToPosition(position)) { + + Intent intent = createIntentFromSuggestion(c, actionKey, actionMsg); + + // launch the intent + launchIntent(intent); + + return true; + } + return false; + } + + /** + * Launches an intent, including any special intent handling. + */ + private void launchIntent(Intent intent) { + if (intent == null) { + return; + } + try { + // If the intent was created from a suggestion, it will always have an explicit + // component here. + getContext().startActivity(intent); + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "Failed launch activity: " + intent, ex); + } + } + + /** + * Sets the text in the query box, without updating the suggestions. + */ + private void setQuery(CharSequence query) { + setText(mQueryTextView, query, true); + // Move the cursor to the end + mQueryTextView.setSelection(TextUtils.isEmpty(query) ? 0 : query.length()); + } + + private void launchQuerySearch(int actionKey, String actionMsg, String query) { + String action = Intent.ACTION_SEARCH; + Intent intent = createIntent(action, null, null, query, actionKey, actionMsg); + getContext().startActivity(intent); + } + + /** + * Constructs an intent from the given information and the search dialog state. + * + * @param action Intent action. + * @param data Intent data, or null. + * @param extraData Data for {@link SearchManager#EXTRA_DATA_KEY} or null. + * @param query Intent query, or null. + * @param actionKey The key code of the action key that was pressed, + * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. + * @param actionMsg The message for the action key that was pressed, + * or null if none. + * @return The intent. + */ + private Intent createIntent(String action, Uri data, String extraData, String query, + int actionKey, String actionMsg) { + // Now build the Intent + Intent intent = new Intent(action); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + // We need CLEAR_TOP to avoid reusing an old task that has other activities + // on top of the one we want. We don't want to do this in in-app search though, + // as it can be destructive to the activity stack. + if (data != null) { + intent.setData(data); + } + intent.putExtra(SearchManager.USER_QUERY, mUserQuery); + if (query != null) { + intent.putExtra(SearchManager.QUERY, query); + } + if (extraData != null) { + intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData); + } + if (mAppSearchData != null) { + intent.putExtra(SearchManager.APP_DATA, mAppSearchData); + } + if (actionKey != KeyEvent.KEYCODE_UNKNOWN) { + intent.putExtra(SearchManager.ACTION_KEY, actionKey); + intent.putExtra(SearchManager.ACTION_MSG, actionMsg); + } + intent.setComponent(mSearchable.getSearchActivity()); + return intent; + } + + /** + * Create and return an Intent that can launch the voice search activity for web search. + */ + private Intent createVoiceWebSearchIntent(Intent baseIntent, SearchableInfo searchable) { + Intent voiceIntent = new Intent(baseIntent); + ComponentName searchActivity = searchable.getSearchActivity(); + voiceIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, searchActivity == null ? null + : searchActivity.flattenToShortString()); + return voiceIntent; + } + + /** + * Create and return an Intent that can launch the voice search activity, perform a specific + * voice transcription, and forward the results to the searchable activity. + * + * @param baseIntent The voice app search intent to start from + * @return A completely-configured intent ready to send to the voice search activity + */ + private Intent createVoiceAppSearchIntent(Intent baseIntent, SearchableInfo searchable) { + ComponentName searchActivity = searchable.getSearchActivity(); + + // create the necessary intent to set up a search-and-forward operation + // in the voice search system. We have to keep the bundle separate, + // because it becomes immutable once it enters the PendingIntent + Intent queryIntent = new Intent(Intent.ACTION_SEARCH); + queryIntent.setComponent(searchActivity); + PendingIntent pending = PendingIntent.getActivity(getContext(), 0, queryIntent, + PendingIntent.FLAG_ONE_SHOT); + + // Now set up the bundle that will be inserted into the pending intent + // when it's time to do the search. We always build it here (even if empty) + // because the voice search activity will always need to insert "QUERY" into + // it anyway. + Bundle queryExtras = new Bundle(); + + // Now build the intent to launch the voice search. Add all necessary + // extras to launch the voice recognizer, and then all the necessary extras + // to forward the results to the searchable activity + Intent voiceIntent = new Intent(baseIntent); + + // Add all of the configuration options supplied by the searchable's metadata + String languageModel = RecognizerIntent.LANGUAGE_MODEL_FREE_FORM; + String prompt = null; + String language = null; + int maxResults = 1; + + Resources resources = getResources(); + if (searchable.getVoiceLanguageModeId() != 0) { + languageModel = resources.getString(searchable.getVoiceLanguageModeId()); + } + if (searchable.getVoicePromptTextId() != 0) { + prompt = resources.getString(searchable.getVoicePromptTextId()); + } + if (searchable.getVoiceLanguageId() != 0) { + language = resources.getString(searchable.getVoiceLanguageId()); + } + if (searchable.getVoiceMaxResults() != 0) { + maxResults = searchable.getVoiceMaxResults(); + } + voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel); + voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt); + voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); + voiceIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults); + voiceIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, searchActivity == null ? null + : searchActivity.flattenToShortString()); + + // Add the values that configure forwarding the results + voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, pending); + voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT_BUNDLE, queryExtras); + + return voiceIntent; + } + + /** + * When a particular suggestion has been selected, perform the various lookups required + * to use the suggestion. This includes checking the cursor for suggestion-specific data, + * and/or falling back to the XML for defaults; It also creates REST style Uri data when + * the suggestion includes a data id. + * + * @param c The suggestions cursor, moved to the row of the user's selection + * @param actionKey The key code of the action key that was pressed, + * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. + * @param actionMsg The message for the action key that was pressed, + * or null if none. + * @return An intent for the suggestion at the cursor's position. + */ + private Intent createIntentFromSuggestion(Cursor c, int actionKey, String actionMsg) { + try { + // use specific action if supplied, or default action if supplied, or fixed default + String action = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_ACTION); + + if (action == null) { + action = mSearchable.getSuggestIntentAction(); + } + if (action == null) { + action = Intent.ACTION_SEARCH; + } + + // use specific data if supplied, or default data if supplied + String data = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA); + if (data == null) { + data = mSearchable.getSuggestIntentData(); + } + // then, if an ID was provided, append it. + if (data != null) { + String id = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); + if (id != null) { + data = data + "/" + Uri.encode(id); + } + } + Uri dataUri = (data == null) ? null : Uri.parse(data); + + String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY); + String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); + + return createIntent(action, dataUri, extraData, query, actionKey, actionMsg); + } catch (RuntimeException e ) { + int rowNum; + try { // be really paranoid now + rowNum = c.getPosition(); + } catch (RuntimeException e2 ) { + rowNum = -1; + } + Log.w(LOG_TAG, "Search suggestions cursor at row " + rowNum + + " returned exception.", e); + return null; + } + } + + private void forceSuggestionQuery() { + try { + Method before = SearchAutoComplete.class.getMethod("doBeforeTextChanged"); + Method after = SearchAutoComplete.class.getMethod("doAfterTextChanged"); + before.setAccessible(true); + after.setAccessible(true); + before.invoke(mQueryTextView); + after.invoke(mQueryTextView); + } catch (Exception e) { + // Oh well... + } + } + + static boolean isLandscapeMode(Context context) { + return context.getResources().getConfiguration().orientation + == Configuration.ORIENTATION_LANDSCAPE; + } + + /** + * Callback to watch the text field for empty/non-empty + */ + private TextWatcher mTextWatcher = new TextWatcher() { + + public void beforeTextChanged(CharSequence s, int start, int before, int after) { } + + public void onTextChanged(CharSequence s, int start, + int before, int after) { + SearchView.this.onTextChanged(s); + } + + public void afterTextChanged(Editable s) { + } + }; + + /** + * Local subclass for AutoCompleteTextView. + * @hide + */ + public static class SearchAutoComplete extends AutoCompleteTextView { + + private int mThreshold; + private SearchView mSearchView; + + public SearchAutoComplete(Context context) { + super(context); + mThreshold = getThreshold(); + } + + public SearchAutoComplete(Context context, AttributeSet attrs) { + super(context, attrs); + mThreshold = getThreshold(); + } + + public SearchAutoComplete(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mThreshold = getThreshold(); + } + + void setSearchView(SearchView searchView) { + mSearchView = searchView; + } + + @Override + public void setThreshold(int threshold) { + super.setThreshold(threshold); + mThreshold = threshold; + } + + /** + * Returns true if the text field is empty, or contains only whitespace. + */ + private boolean isEmpty() { + return TextUtils.getTrimmedLength(getText()) == 0; + } + + /** + * We override this method to avoid replacing the query box text when a + * suggestion is clicked. + */ + @Override + protected void replaceText(CharSequence text) { + } + + /** + * We override this method to avoid an extra onItemClick being called on + * the drop-down's OnItemClickListener by + * {@link AutoCompleteTextView#onKeyUp(int, KeyEvent)} when an item is + * clicked with the trackball. + */ + @Override + public void performCompletion() { + } + + /** + * We override this method to be sure and show the soft keyboard if + * appropriate when the TextView has focus. + */ + @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + super.onWindowFocusChanged(hasWindowFocus); + + if (hasWindowFocus && mSearchView.hasFocus() && getVisibility() == VISIBLE) { + InputMethodManager inputManager = (InputMethodManager) getContext() + .getSystemService(Context.INPUT_METHOD_SERVICE); + inputManager.showSoftInput(this, 0); + // If in landscape mode, then make sure that + // the ime is in front of the dropdown. + if (isLandscapeMode(getContext())) { + ensureImeVisible(this, true); + } + } + } + + @Override + protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { + super.onFocusChanged(focused, direction, previouslyFocusedRect); + mSearchView.onTextFocusChanged(); + } + + /** + * We override this method so that we can allow a threshold of zero, + * which ACTV does not. + */ + @Override + public boolean enoughToFilter() { + return mThreshold <= 0 || super.enoughToFilter(); + } + + @Override + public boolean onKeyPreIme(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + // special case for the back key, we do not even try to send it + // to the drop down list but instead, consume it immediately + if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + state.startTracking(event, this); + } + return true; + } else if (event.getAction() == KeyEvent.ACTION_UP) { + KeyEvent.DispatcherState state = getKeyDispatcherState(); + if (state != null) { + state.handleUpEvent(event); + } + if (event.isTracking() && !event.isCanceled()) { + mSearchView.clearFocus(); + mSearchView.setImeVisibility(false); + return true; + } + } + } + return super.onKeyPreIme(keyCode, event); + } + + } + + private static void ensureImeVisible(AutoCompleteTextView view, boolean visible) { + try { + Method method = AutoCompleteTextView.class.getMethod("ensureImeVisible", boolean.class); + method.setAccessible(true); + method.invoke(view, visible); + } catch (Exception e) { + //Oh well... + } + } + + private static void showSoftInputUnchecked(View view, InputMethodManager imm, int flags) { + try { + Method method = imm.getClass().getMethod("showSoftInputUnchecked", int.class, ResultReceiver.class); + method.setAccessible(true); + method.invoke(imm, flags, null); + } catch (Exception e) { + //Fallback to public API which hopefully does mostly the same thing + imm.showSoftInput(view, flags); + } + } + + private static void setText(AutoCompleteTextView view, CharSequence text, boolean filter) { + try { + Method method = AutoCompleteTextView.class.getMethod("setText", CharSequence.class, boolean.class); + method.setAccessible(true); + method.invoke(view, text, filter); + } catch (Exception e) { + //Fallback to public API which hopefully does mostly the same thing + view.setText(text); + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ShareActionProvider.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ShareActionProvider.java new file mode 100644 index 00000000..83e9f0ca --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/ShareActionProvider.java @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.widget; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; +import android.util.TypedValue; +import android.view.View; + +import com.actionbarsherlock.R; +import com.actionbarsherlock.view.ActionProvider; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuItem; +import com.actionbarsherlock.view.MenuItem.OnMenuItemClickListener; +import com.actionbarsherlock.view.SubMenu; +import com.actionbarsherlock.widget.ActivityChooserModel.OnChooseActivityListener; + +/** + * This is a provider for a share action. It is responsible for creating views + * that enable data sharing and also to show a sub menu with sharing activities + * if the hosting item is placed on the overflow menu. + *

+ * Here is how to use the action provider with custom backing file in a {@link MenuItem}: + *

+ *

+ *

+ * 
+ *  // In Activity#onCreateOptionsMenu
+ *  public boolean onCreateOptionsMenu(Menu menu) {
+ *      // Get the menu item.
+ *      MenuItem menuItem = menu.findItem(R.id.my_menu_item);
+ *      // Get the provider and hold onto it to set/change the share intent.
+ *      mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
+ *      // Set history different from the default before getting the action
+ *      // view since a call to {@link MenuItem#getActionView() MenuItem.getActionView()} calls
+ *      // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this
+ *      // line if using the default share history file is desired.
+ *      mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
+ *      . . .
+ *  }
+ *
+ *  // Somewhere in the application.
+ *  public void doShare(Intent shareIntent) {
+ *      // When you want to share set the share intent.
+ *      mShareActionProvider.setShareIntent(shareIntent);
+ *  }
+ * 
+ * + *

+ *

+ * Note: While the sample snippet demonstrates how to use this provider + * in the context of a menu item, the use of the provider is not limited to menu items. + *

+ * + * @see ActionProvider + */ +public class ShareActionProvider extends ActionProvider { + + /** + * Listener for the event of selecting a share target. + */ + public interface OnShareTargetSelectedListener { + + /** + * Called when a share target has been selected. The client can + * decide whether to handle the intent or rely on the default + * behavior which is launching it. + *

+ * Note: Modifying the intent is not permitted and + * any changes to the latter will be ignored. + *

+ * + * @param source The source of the notification. + * @param intent The intent for launching the chosen share target. + * @return Whether the client has handled the intent. + */ + public boolean onShareTargetSelected(ShareActionProvider source, Intent intent); + } + + /** + * The default for the maximal number of activities shown in the sub-menu. + */ + private static final int DEFAULT_INITIAL_ACTIVITY_COUNT = 4; + + /** + * The the maximum number activities shown in the sub-menu. + */ + private int mMaxShownActivityCount = DEFAULT_INITIAL_ACTIVITY_COUNT; + + /** + * Listener for handling menu item clicks. + */ + private final ShareMenuItemOnMenuItemClickListener mOnMenuItemClickListener = + new ShareMenuItemOnMenuItemClickListener(); + + /** + * The default name for storing share history. + */ + public static final String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml"; + + /** + * Context for accessing resources. + */ + private final Context mContext; + + /** + * The name of the file with share history data. + */ + private String mShareHistoryFileName = DEFAULT_SHARE_HISTORY_FILE_NAME; + + private OnShareTargetSelectedListener mOnShareTargetSelectedListener; + + private OnChooseActivityListener mOnChooseActivityListener; + + /** + * Creates a new instance. + * + * @param context Context for accessing resources. + */ + public ShareActionProvider(Context context) { + super(context); + mContext = context; + } + + /** + * Sets a listener to be notified when a share target has been selected. + * The listener can optionally decide to handle the selection and + * not rely on the default behavior which is to launch the activity. + *

+ * Note: If you choose the backing share history file + * you will still be notified in this callback. + *

+ * @param listener The listener. + */ + public void setOnShareTargetSelectedListener(OnShareTargetSelectedListener listener) { + mOnShareTargetSelectedListener = listener; + setActivityChooserPolicyIfNeeded(); + } + + /** + * {@inheritDoc} + */ + @Override + public View onCreateActionView() { + // Create the view and set its data model. + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName); + ActivityChooserView activityChooserView = new ActivityChooserView(mContext); + activityChooserView.setActivityChooserModel(dataModel); + + // Lookup and set the expand action icon. + TypedValue outTypedValue = new TypedValue(); + mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true); + Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId); + activityChooserView.setExpandActivityOverflowButtonDrawable(drawable); + activityChooserView.setProvider(this); + + // Set content description. + activityChooserView.setDefaultActionButtonContentDescription( + R.string.abs__shareactionprovider_share_with_application); + activityChooserView.setExpandActivityOverflowButtonContentDescription( + R.string.abs__shareactionprovider_share_with); + + return activityChooserView; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean hasSubMenu() { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public void onPrepareSubMenu(SubMenu subMenu) { + // Clear since the order of items may change. + subMenu.clear(); + + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName); + PackageManager packageManager = mContext.getPackageManager(); + + final int expandedActivityCount = dataModel.getActivityCount(); + final int collapsedActivityCount = Math.min(expandedActivityCount, mMaxShownActivityCount); + + // Populate the sub-menu with a sub set of the activities. + for (int i = 0; i < collapsedActivityCount; i++) { + ResolveInfo activity = dataModel.getActivity(i); + subMenu.add(0, i, i, activity.loadLabel(packageManager)) + .setIcon(activity.loadIcon(packageManager)) + .setOnMenuItemClickListener(mOnMenuItemClickListener); + } + + if (collapsedActivityCount < expandedActivityCount) { + // Add a sub-menu for showing all activities as a list item. + SubMenu expandedSubMenu = subMenu.addSubMenu(Menu.NONE, collapsedActivityCount, + collapsedActivityCount, + mContext.getString(R.string.abs__activity_chooser_view_see_all)); + for (int i = 0; i < expandedActivityCount; i++) { + ResolveInfo activity = dataModel.getActivity(i); + expandedSubMenu.add(0, i, i, activity.loadLabel(packageManager)) + .setIcon(activity.loadIcon(packageManager)) + .setOnMenuItemClickListener(mOnMenuItemClickListener); + } + } + } + + /** + * Sets the file name of a file for persisting the share history which + * history will be used for ordering share targets. This file will be used + * for all view created by {@link #onCreateActionView()}. Defaults to + * {@link #DEFAULT_SHARE_HISTORY_FILE_NAME}. Set to null + * if share history should not be persisted between sessions. + *

+ * Note: The history file name can be set any time, however + * only the action views created by {@link #onCreateActionView()} after setting + * the file name will be backed by the provided file. + *

+ * + * @param shareHistoryFile The share history file name. + */ + public void setShareHistoryFileName(String shareHistoryFile) { + mShareHistoryFileName = shareHistoryFile; + setActivityChooserPolicyIfNeeded(); + } + + /** + * Sets an intent with information about the share action. Here is a + * sample for constructing a share intent: + *

+ *

+     * 
+     *  Intent shareIntent = new Intent(Intent.ACTION_SEND);
+     *  shareIntent.setType("image/*");
+     *  Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg"));
+     *  shareIntent.putExtra(Intent.EXTRA_STREAM, uri.toString());
+     * 
+ * + *

+ * + * @param shareIntent The share intent. + * + * @see Intent#ACTION_SEND + * @see Intent#ACTION_SEND_MULTIPLE + */ + public void setShareIntent(Intent shareIntent) { + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, + mShareHistoryFileName); + dataModel.setIntent(shareIntent); + } + + /** + * Reusable listener for handling share item clicks. + */ + private class ShareMenuItemOnMenuItemClickListener implements OnMenuItemClickListener { + @Override + public boolean onMenuItemClick(MenuItem item) { + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, + mShareHistoryFileName); + final int itemId = item.getItemId(); + Intent launchIntent = dataModel.chooseActivity(itemId); + if (launchIntent != null) { + mContext.startActivity(launchIntent); + } + return true; + } + } + + /** + * Set the activity chooser policy of the model backed by the current + * share history file if needed which is if there is a registered callback. + */ + private void setActivityChooserPolicyIfNeeded() { + if (mOnShareTargetSelectedListener == null) { + return; + } + if (mOnChooseActivityListener == null) { + mOnChooseActivityListener = new ShareAcitivityChooserModelPolicy(); + } + ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName); + dataModel.setOnChooseActivityListener(mOnChooseActivityListener); + } + + /** + * Policy that delegates to the {@link OnShareTargetSelectedListener}, if such. + */ + private class ShareAcitivityChooserModelPolicy implements OnChooseActivityListener { + @Override + public boolean onChooseActivity(ActivityChooserModel host, Intent intent) { + if (mOnShareTargetSelectedListener != null) { + return mOnShareTargetSelectedListener.onShareTargetSelected( + ShareActionProvider.this, intent); + } + return false; + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/SuggestionsAdapter.java b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/SuggestionsAdapter.java new file mode 100644 index 00000000..bd5cbd71 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/src/com/actionbarsherlock/widget/SuggestionsAdapter.java @@ -0,0 +1,733 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.actionbarsherlock.widget; + +import android.app.SearchManager; +import android.app.SearchableInfo; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.ColorStateList; +import android.content.res.Resources; +import android.database.Cursor; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.widget.ResourceCursorAdapter; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.TextUtils; +import android.text.style.TextAppearanceSpan; +import android.util.Log; +import android.util.TypedValue; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import com.actionbarsherlock.R; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.WeakHashMap; + +/** + * Provides the contents for the suggestion drop-down list. + * + * @hide + */ +class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListener { + + private static final boolean DBG = false; + private static final String LOG_TAG = "SuggestionsAdapter"; + private static final int QUERY_LIMIT = 50; + + static final int REFINE_NONE = 0; + static final int REFINE_BY_ENTRY = 1; + static final int REFINE_ALL = 2; + + private SearchManager mSearchManager; + private SearchView mSearchView; + private Context mProviderContext; + private WeakHashMap mOutsideDrawablesCache; + private boolean mClosed = false; + private int mQueryRefinement = REFINE_BY_ENTRY; + + // URL color + private ColorStateList mUrlColor; + + static final int INVALID_INDEX = -1; + + // Cached column indexes, updated when the cursor changes. + private int mText1Col = INVALID_INDEX; + private int mText2Col = INVALID_INDEX; + private int mText2UrlCol = INVALID_INDEX; + private int mIconName1Col = INVALID_INDEX; + private int mIconName2Col = INVALID_INDEX; + private int mFlagsCol = INVALID_INDEX; + + // private final Runnable mStartSpinnerRunnable; + // private final Runnable mStopSpinnerRunnable; + + /** + * The amount of time we delay in the filter when the user presses the delete key. + */ + //private static final long DELETE_KEY_POST_DELAY = 500L; + + public SuggestionsAdapter(Context context, SearchView searchView, + SearchableInfo mSearchable, WeakHashMap outsideDrawablesCache) { + super(context, + R.layout.abs__search_dropdown_item_icons_2line, + null, // no initial cursor + true); // auto-requery + mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); + mProviderContext = mContext; + mSearchView = searchView; + + mOutsideDrawablesCache = outsideDrawablesCache; + + // mStartSpinnerRunnable = new Runnable() { + // public void run() { + // // mSearchView.setWorking(true); // TODO: + // } + // }; + // + // mStopSpinnerRunnable = new Runnable() { + // public void run() { + // // mSearchView.setWorking(false); // TODO: + // } + // }; + + // delay 500ms when deleting +// TODO getFilter().setDelayer(new Filter.Delayer() { +// +// private int mPreviousLength = 0; +// +// public long getPostingDelay(CharSequence constraint) { +// if (constraint == null) return 0; +// +// long delay = constraint.length() < mPreviousLength ? DELETE_KEY_POST_DELAY : 0; +// mPreviousLength = constraint.length(); +// return delay; +// } +// }); + } + + /** + * Enables query refinement for all suggestions. This means that an additional icon + * will be shown for each entry. When clicked, the suggested text on that line will be + * copied to the query text field. + *

+ * + * @param refineWhat which queries to refine. Possible values are {@link #REFINE_NONE}, + * {@link #REFINE_BY_ENTRY}, and {@link #REFINE_ALL}. + */ + public void setQueryRefinement(int refineWhat) { + mQueryRefinement = refineWhat; + } + + /** + * Returns the current query refinement preference. + * @return value of query refinement preference + */ + public int getQueryRefinement() { + return mQueryRefinement; + } + + /** + * Overridden to always return false, since we cannot be sure that + * suggestion sources return stable IDs. + */ + @Override + public boolean hasStableIds() { + return false; + } + + /** + * Use the search suggestions provider to obtain a live cursor. This will be called + * in a worker thread, so it's OK if the query is slow (e.g. round trip for suggestions). + * The results will be processed in the UI thread and changeCursor() will be called. + */ + @Override + public Cursor runQueryOnBackgroundThread(CharSequence constraint) { + if (DBG) Log.d(LOG_TAG, "runQueryOnBackgroundThread(" + constraint + ")"); + String query = (constraint == null) ? "" : constraint.toString(); + /** + * for in app search we show the progress spinner until the cursor is returned with + * the results. + */ + Cursor cursor = null; + if (mSearchView.getVisibility() != View.VISIBLE + || mSearchView.getWindowVisibility() != View.VISIBLE) { + return null; + } + //mSearchView.getWindow().getDecorView().post(mStartSpinnerRunnable); // TODO: + try { + cursor = getSuggestions(query, QUERY_LIMIT); + // trigger fill window so the spinner stays up until the results are copied over and + // closer to being ready + if (cursor != null) { + cursor.getCount(); + return cursor; + } + } catch (RuntimeException e) { + Log.w(LOG_TAG, "Search suggestions query threw an exception.", e); + } + // If cursor is null or an exception was thrown, stop the spinner and return null. + // changeCursor doesn't get called if cursor is null + // mSearchView.getWindow().getDecorView().post(mStopSpinnerRunnable); // TODO: + return null; + } + + public Cursor getSuggestions(String query, int limit) { + Uri.Builder uriBuilder = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .query("") // TODO: Remove, workaround for a bug in Uri.writeToParcel() + .fragment(""); // TODO: Remove, workaround for a bug in Uri.writeToParcel() + + // append standard suggestion query path + uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY); + + // inject query, either as selection args or inline + uriBuilder.appendPath(query); + + if (limit > 0) { + uriBuilder.appendQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT, String.valueOf(limit)); + } + + Uri uri = uriBuilder.build(); + + // finally, make the query + return mContext.getContentResolver().query(uri, null, null, null, null); + } + + public void close() { + if (DBG) Log.d(LOG_TAG, "close()"); + changeCursor(null); + mClosed = true; + } + + @Override + public void notifyDataSetChanged() { + if (DBG) Log.d(LOG_TAG, "notifyDataSetChanged"); + super.notifyDataSetChanged(); + + // mSearchView.onDataSetChanged(); // TODO: + + updateSpinnerState(getCursor()); + } + + @Override + public void notifyDataSetInvalidated() { + if (DBG) Log.d(LOG_TAG, "notifyDataSetInvalidated"); + super.notifyDataSetInvalidated(); + + updateSpinnerState(getCursor()); + } + + private void updateSpinnerState(Cursor cursor) { + Bundle extras = cursor != null ? cursor.getExtras() : null; + if (DBG) { + Log.d(LOG_TAG, "updateSpinnerState - extra = " + + (extras != null + ? extras.getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS) + : null)); + } + // Check if the Cursor indicates that the query is not complete and show the spinner + if (extras != null + && extras.getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS)) { + // mSearchView.getWindow().getDecorView().post(mStartSpinnerRunnable); // TODO: + return; + } + // If cursor is null or is done, stop the spinner + // mSearchView.getWindow().getDecorView().post(mStopSpinnerRunnable); // TODO: + } + + /** + * Cache columns. + */ + @Override + public void changeCursor(Cursor c) { + if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")"); + + if (mClosed) { + Log.w(LOG_TAG, "Tried to change cursor after adapter was closed."); + if (c != null) c.close(); + return; + } + + try { + super.changeCursor(c); + + if (c != null) { + mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1); + mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2); + mText2UrlCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2_URL); + mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1); + mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2); + mFlagsCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FLAGS); + } + } catch (Exception e) { + Log.e(LOG_TAG, "error changing cursor and caching columns", e); + } + } + + /** + * Tags the view with cached child view look-ups. + */ + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + View v = super.newView(context, cursor, parent); + v.setTag(new ChildViewCache(v)); + return v; + } + + /** + * Cache of the child views of drop-drown list items, to avoid looking up the children + * each time the contents of a list item are changed. + */ + private final static class ChildViewCache { + public final TextView mText1; + public final TextView mText2; + public final ImageView mIcon1; + public final ImageView mIcon2; + public final ImageView mIconRefine; + + public ChildViewCache(View v) { + mText1 = (TextView) v.findViewById(android.R.id.text1); + mText2 = (TextView) v.findViewById(android.R.id.text2); + mIcon1 = (ImageView) v.findViewById(android.R.id.icon1); + mIcon2 = (ImageView) v.findViewById(android.R.id.icon2); + mIconRefine = (ImageView) v.findViewById(R.id.edit_query); + } + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + ChildViewCache views = (ChildViewCache) view.getTag(); + + int flags = 0; + if (mFlagsCol != INVALID_INDEX) { + flags = cursor.getInt(mFlagsCol); + } + if (views.mText1 != null) { + String text1 = getStringOrNull(cursor, mText1Col); + setViewText(views.mText1, text1); + } + if (views.mText2 != null) { + // First check TEXT_2_URL + CharSequence text2 = getStringOrNull(cursor, mText2UrlCol); + if (text2 != null) { + text2 = formatUrl(text2); + } else { + text2 = getStringOrNull(cursor, mText2Col); + } + + // If no second line of text is indicated, allow the first line of text + // to be up to two lines if it wants to be. + if (TextUtils.isEmpty(text2)) { + if (views.mText1 != null) { + views.mText1.setSingleLine(false); + views.mText1.setMaxLines(2); + } + } else { + if (views.mText1 != null) { + views.mText1.setSingleLine(true); + views.mText1.setMaxLines(1); + } + } + setViewText(views.mText2, text2); + } + + if (views.mIcon1 != null) { + setViewDrawable(views.mIcon1, getIcon1(cursor), View.INVISIBLE); + } + if (views.mIcon2 != null) { + setViewDrawable(views.mIcon2, getIcon2(cursor), View.GONE); + } + if (mQueryRefinement == REFINE_ALL + || (mQueryRefinement == REFINE_BY_ENTRY + && (flags & SearchManager.FLAG_QUERY_REFINEMENT) != 0)) { + views.mIconRefine.setVisibility(View.VISIBLE); + views.mIconRefine.setTag(views.mText1.getText()); + views.mIconRefine.setOnClickListener(this); + } else { + views.mIconRefine.setVisibility(View.GONE); + } + } + + public void onClick(View v) { + Object tag = v.getTag(); + if (tag instanceof CharSequence) { + mSearchView.onQueryRefine((CharSequence) tag); + } + } + + private CharSequence formatUrl(CharSequence url) { + if (mUrlColor == null) { + // Lazily get the URL color from the current theme. + TypedValue colorValue = new TypedValue(); + mContext.getTheme().resolveAttribute(R.attr.textColorSearchUrl, colorValue, true); + mUrlColor = mContext.getResources().getColorStateList(colorValue.resourceId); + } + + SpannableString text = new SpannableString(url); + text.setSpan(new TextAppearanceSpan(null, 0, 0, mUrlColor, null), + 0, url.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + return text; + } + + private void setViewText(TextView v, CharSequence text) { + // Set the text even if it's null, since we need to clear any previous text. + v.setText(text); + + if (TextUtils.isEmpty(text)) { + v.setVisibility(View.GONE); + } else { + v.setVisibility(View.VISIBLE); + } + } + + private Drawable getIcon1(Cursor cursor) { + if (mIconName1Col == INVALID_INDEX) { + return null; + } + String value = cursor.getString(mIconName1Col); + Drawable drawable = getDrawableFromResourceValue(value); + if (drawable != null) { + return drawable; + } + return getDefaultIcon1(cursor); + } + + private Drawable getIcon2(Cursor cursor) { + if (mIconName2Col == INVALID_INDEX) { + return null; + } + String value = cursor.getString(mIconName2Col); + return getDrawableFromResourceValue(value); + } + + /** + * Sets the drawable in an image view, makes sure the view is only visible if there + * is a drawable. + */ + private void setViewDrawable(ImageView v, Drawable drawable, int nullVisibility) { + // Set the icon even if the drawable is null, since we need to clear any + // previous icon. + v.setImageDrawable(drawable); + + if (drawable == null) { + v.setVisibility(nullVisibility); + } else { + v.setVisibility(View.VISIBLE); + + // This is a hack to get any animated drawables (like a 'working' spinner) + // to animate. You have to setVisible true on an AnimationDrawable to get + // it to start animating, but it must first have been false or else the + // call to setVisible will be ineffective. We need to clear up the story + // about animated drawables in the future, see http://b/1878430. + drawable.setVisible(false, false); + drawable.setVisible(true, false); + } + } + + /** + * Gets the text to show in the query field when a suggestion is selected. + * + * @param cursor The Cursor to read the suggestion data from. The Cursor should already + * be moved to the suggestion that is to be read from. + * @return The text to show, or null if the query should not be + * changed when selecting this suggestion. + */ + @Override + public CharSequence convertToString(Cursor cursor) { + if (cursor == null) { + return null; + } + + String query = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_QUERY); + if (query != null) { + return query; + } + + return null; + } + + /** + * This method is overridden purely to provide a bit of protection against + * flaky content providers. + * + * @see android.widget.ListAdapter#getView(int, View, ViewGroup) + */ + @Override + public View getView(int position, View convertView, ViewGroup parent) { + try { + return super.getView(position, convertView, parent); + } catch (RuntimeException e) { + Log.w(LOG_TAG, "Search suggestions cursor threw exception.", e); + // Put exception string in item title + View v = newView(mContext, mCursor, parent); + if (v != null) { + ChildViewCache views = (ChildViewCache) v.getTag(); + TextView tv = views.mText1; + tv.setText(e.toString()); + } + return v; + } + } + + /** + * Gets a drawable given a value provided by a suggestion provider. + * + * This value could be just the string value of a resource id + * (e.g., "2130837524"), in which case we will try to retrieve a drawable from + * the provider's resources. If the value is not an integer, it is + * treated as a Uri and opened with + * {@link ContentResolver#openOutputStream(android.net.Uri, String)}. + * + * All resources and URIs are read using the suggestion provider's context. + * + * If the string is not formatted as expected, or no drawable can be found for + * the provided value, this method returns null. + * + * @param drawableId a string like "2130837524", + * "android.resource://com.android.alarmclock/2130837524", + * or "content://contacts/photos/253". + * @return a Drawable, or null if none found + */ + private Drawable getDrawableFromResourceValue(String drawableId) { + if (drawableId == null || drawableId.length() == 0 || "0".equals(drawableId)) { + return null; + } + try { + // First, see if it's just an integer + int resourceId = Integer.parseInt(drawableId); + // It's an int, look for it in the cache + String drawableUri = ContentResolver.SCHEME_ANDROID_RESOURCE + + "://" + mProviderContext.getPackageName() + "/" + resourceId; + // Must use URI as cache key, since ints are app-specific + Drawable drawable = checkIconCache(drawableUri); + if (drawable != null) { + return drawable; + } + // Not cached, find it by resource ID + drawable = mProviderContext.getResources().getDrawable(resourceId); + // Stick it in the cache, using the URI as key + storeInIconCache(drawableUri, drawable); + return drawable; + } catch (NumberFormatException nfe) { + // It's not an integer, use it as a URI + Drawable drawable = checkIconCache(drawableId); + if (drawable != null) { + return drawable; + } + Uri uri = Uri.parse(drawableId); + drawable = getDrawable(uri); + storeInIconCache(drawableId, drawable); + return drawable; + } catch (Resources.NotFoundException nfe) { + // It was an integer, but it couldn't be found, bail out + Log.w(LOG_TAG, "Icon resource not found: " + drawableId); + return null; + } + } + + /** + * Gets a drawable by URI, without using the cache. + * + * @return A drawable, or {@code null} if the drawable could not be loaded. + */ + private Drawable getDrawable(Uri uri) { + try { + String scheme = uri.getScheme(); + if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) { + // Load drawables through Resources, to get the source density information + try { + return getTheDrawable(uri); + } catch (Resources.NotFoundException ex) { + throw new FileNotFoundException("Resource does not exist: " + uri); + } + } else { + // Let the ContentResolver handle content and file URIs. + InputStream stream = mProviderContext.getContentResolver().openInputStream(uri); + if (stream == null) { + throw new FileNotFoundException("Failed to open " + uri); + } + try { + return Drawable.createFromStream(stream, null); + } finally { + try { + stream.close(); + } catch (IOException ex) { + Log.e(LOG_TAG, "Error closing icon stream for " + uri, ex); + } + } + } + } catch (FileNotFoundException fnfe) { + Log.w(LOG_TAG, "Icon not found: " + uri + ", " + fnfe.getMessage()); + return null; + } + } + + public Drawable getTheDrawable(Uri uri) throws FileNotFoundException { + String authority = uri.getAuthority(); + Resources r; + if (TextUtils.isEmpty(authority)) { + throw new FileNotFoundException("No authority: " + uri); + } else { + try { + r = mContext.getPackageManager().getResourcesForApplication(authority); + } catch (NameNotFoundException ex) { + throw new FileNotFoundException("No package found for authority: " + uri); + } + } + List path = uri.getPathSegments(); + if (path == null) { + throw new FileNotFoundException("No path: " + uri); + } + int len = path.size(); + int id; + if (len == 1) { + try { + id = Integer.parseInt(path.get(0)); + } catch (NumberFormatException e) { + throw new FileNotFoundException("Single path segment is not a resource ID: " + uri); + } + } else if (len == 2) { + id = r.getIdentifier(path.get(1), path.get(0), authority); + } else { + throw new FileNotFoundException("More than two path segments: " + uri); + } + if (id == 0) { + throw new FileNotFoundException("No resource found for: " + uri); + } + return r.getDrawable(id); + } + + private Drawable checkIconCache(String resourceUri) { + Drawable.ConstantState cached = mOutsideDrawablesCache.get(resourceUri); + if (cached == null) { + return null; + } + if (DBG) Log.d(LOG_TAG, "Found icon in cache: " + resourceUri); + return cached.newDrawable(); + } + + private void storeInIconCache(String resourceUri, Drawable drawable) { + if (drawable != null) { + mOutsideDrawablesCache.put(resourceUri, drawable.getConstantState()); + } + } + + /** + * Gets the left-hand side icon that will be used for the current suggestion + * if the suggestion contains an icon column but no icon or a broken icon. + * + * @param cursor A cursor positioned at the current suggestion. + * @return A non-null drawable. + */ + private Drawable getDefaultIcon1(Cursor cursor) { + // Fall back to a default icon + return mContext.getPackageManager().getDefaultActivityIcon(); + } + + /** + * Gets the activity or application icon for an activity. + * Uses the local icon cache for fast repeated lookups. + * + * @param component Name of an activity. + * @return A drawable, or {@code null} if neither the activity nor the application + * has an icon set. + */ + private Drawable getActivityIconWithCache(ComponentName component) { + // First check the icon cache + String componentIconKey = component.flattenToShortString(); + // Using containsKey() since we also store null values. + if (mOutsideDrawablesCache.containsKey(componentIconKey)) { + Drawable.ConstantState cached = mOutsideDrawablesCache.get(componentIconKey); + return cached == null ? null : cached.newDrawable(mProviderContext.getResources()); + } + // Then try the activity or application icon + Drawable drawable = getActivityIcon(component); + // Stick it in the cache so we don't do this lookup again. + Drawable.ConstantState toCache = drawable == null ? null : drawable.getConstantState(); + mOutsideDrawablesCache.put(componentIconKey, toCache); + return drawable; + } + + /** + * Gets the activity or application icon for an activity. + * + * @param component Name of an activity. + * @return A drawable, or {@code null} if neither the acitivy or the application + * have an icon set. + */ + private Drawable getActivityIcon(ComponentName component) { + PackageManager pm = mContext.getPackageManager(); + final ActivityInfo activityInfo; + try { + activityInfo = pm.getActivityInfo(component, PackageManager.GET_META_DATA); + } catch (NameNotFoundException ex) { + Log.w(LOG_TAG, ex.toString()); + return null; + } + int iconId = activityInfo.getIconResource(); + if (iconId == 0) return null; + String pkg = component.getPackageName(); + Drawable drawable = pm.getDrawable(pkg, iconId, activityInfo.applicationInfo); + if (drawable == null) { + Log.w(LOG_TAG, "Invalid icon resource " + iconId + " for " + + component.flattenToShortString()); + return null; + } + return drawable; + } + + /** + * Gets the value of a string column by name. + * + * @param cursor Cursor to read the value from. + * @param columnName The name of the column to read. + * @return The value of the given column, or null + * if the cursor does not contain the given column. + */ + public static String getColumnString(Cursor cursor, String columnName) { + int col = cursor.getColumnIndex(columnName); + return getStringOrNull(cursor, col); + } + + private static String getStringOrNull(Cursor cursor, int col) { + if (col == INVALID_INDEX) { + return null; + } + try { + return cursor.getString(col); + } catch (Exception e) { + Log.e(LOG_TAG, + "unexpected error retrieving valid column from cursor, " + + "did the remote process die?", e); + return null; + } + } +} diff --git a/external/JakeWharton-ActionBarSherlock/library/test/com/actionbarsherlock/internal/ManifestParsingTest.java b/external/JakeWharton-ActionBarSherlock/library/test/com/actionbarsherlock/internal/ManifestParsingTest.java new file mode 100644 index 00000000..47475c57 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/test/com/actionbarsherlock/internal/ManifestParsingTest.java @@ -0,0 +1,37 @@ +package com.actionbarsherlock.internal; + +import org.junit.Test; + +import static com.actionbarsherlock.internal.ActionBarSherlockCompat.cleanActivityName; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +public class ManifestParsingTest { + @Test + public void testFullyQualifiedClassName() { + String expected = "com.other.package.SomeClass"; + String actual = cleanActivityName("com.jakewharton.test", "com.other.package.SomeClass"); + assertThat(expected, equalTo(actual)); + } + + @Test + public void testFullyQualifiedClassNameSamePackage() { + String expected = "com.jakewharton.test.SomeClass"; + String actual = cleanActivityName("com.jakewharton.test", "com.jakewharton.test.SomeClass"); + assertThat(expected, equalTo(actual)); + } + + @Test + public void testUnqualifiedClassName() { + String expected = "com.jakewharton.test.SomeClass"; + String actual = cleanActivityName("com.jakewharton.test", "SomeClass"); + assertThat(expected, equalTo(actual)); + } + + @Test + public void testRelativeClassName() { + String expected = "com.jakewharton.test.ui.SomeClass"; + String actual = cleanActivityName("com.jakewharton.test", ".ui.SomeClass"); + assertThat(expected, equalTo(actual)); + } +} \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/pom.xml b/external/JakeWharton-ActionBarSherlock/pom.xml index ee3d1521..371c34e3 100644 --- a/external/JakeWharton-ActionBarSherlock/pom.xml +++ b/external/JakeWharton-ActionBarSherlock/pom.xml @@ -3,29 +3,33 @@ 4.0.0 + + org.sonatype.oss + oss-parent + 7 + + com.actionbarsherlock parent pom - 3.3.0 + 4.2.0 ActionBarSherlock (Parent) - Android library for implementing the action bar design pattern using the native ActionBar on 3.0+ and a custom implementation on pre-3.0 all through the same API. - https://github.com/JakeWharton/ActionBarSherlock + Android library for implementing the action bar design pattern using the backported sources of Ice Cream Sandwich. + http://actionbarsherlock.com 2011 library - plugins samples - test - http://github.com/JakeWharton/ActionBarSherlock/ + https://github.com/JakeWharton/ActionBarSherlock/ scm:git:git://github.com/JakeWharton/ActionBarSherlock.git scm:git:git@github.com:JakeWharton/ActionBarSherlock.git - + Jake Wharton @@ -38,7 +42,7 @@ - + Apache License Version 2.0 @@ -47,34 +51,6 @@ - - - personal-repository - JakeWharton.com Maven Repository - scp://r.jakewharton.com/home/jakewharton_repository/r.jakewharton.com/maven/release/ - - - personal-repository - JakeWharton.com Maven Repository - scp://r.jakewharton.com/home/jakewharton_repository/r.jakewharton.com/maven/snapshot/ - - - github-project-site - GitHub Project Pages - gitsite:git@github.com/JakeWharton/ActionBarSherlock - - - - Jake Wharton http://jakewharton.com @@ -89,26 +65,44 @@ UTF-8 UTF-8 - actionbarsherlock - 1.6 - 3.2_r1 - 13 - 13_r1 + 4.0.1.2 + 14 + r7 + + 3.3.2 + 4.10 + + JakeWharton + ActionBarSherlock - android + com.google.android android ${android.version} - - com.google.android.maps - maps - ${android.maps.version} + com.google.android + support-v4 + ${android-support.version} + + + com.nineoldandroids + library + 2.4.0 + + + com.github.rtyley + roboguice-sherlock + 1.4 + + + junit + junit + ${junit.version} @@ -119,40 +113,47 @@ org.apache.maven.plugins maven-compiler-plugin - 2.3.2 + 2.5 ${java.version} ${java.version} - - org.apache.maven.plugins - maven-javadoc-plugin - 2.8 - - com.jayway.maven.plugins.android.generation2 - maven-android-plugin - 2.9.0-beta-5 + android-maven-plugin + 3.3.2 ${android.platform} - true - true + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.8 org.apache.maven.plugins maven-checkstyle-plugin - 2.6 + 2.9.1 true + + + org.apache.maven.plugins + maven-site-plugin + 3.0 + + true + + @@ -160,54 +161,29 @@ org.apache.maven.plugins maven-release-plugin - 2.1 + 2.2.2 true - org.apache.maven.plugins - maven-site-plugin - 2.2 - false + com.github.github + site-maven-plugin + 0.5 + + + site + + site + + + - false - false - ${basedir}/website + Creating site for ${project.version}. + website - - - org.apache.maven.plugins - maven-deploy-plugin - 2.6 - - - org.apache.maven.wagon - wagon-ssh - 1.0-beta-7 - - - - - - - org.apache.maven.scm - maven-scm-provider-gitexe - 1.4 - - - org.apache.maven.scm - maven-scm-manager-plexus - 1.4 - - - org.kathrynhuxtable.maven.wagon - wagon-gitsite - 0.3.1 - - diff --git a/external/JakeWharton-ActionBarSherlock/update-version.py b/external/JakeWharton-ActionBarSherlock/update-version.py deleted file mode 100755 index a80af157..00000000 --- a/external/JakeWharton-ActionBarSherlock/update-version.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python - -import os -import re -from datetime import date - -repo = os.path.dirname(os.path.realpath(__file__)) -changelog = os.path.join(repo, 'CHANGELOG.md') - -code = 'android:versionCode="%s"' -name = 'android:versionName="%s"' -in_code = code % r'(\d+)' -in_name = name % r'([^"]+)' -new_code = None -new_name = None - -# Update manifest files -for dirpath, dirnames, filenames in os.walk(repo): - for filename in filenames: - if filename == 'AndroidManifest.xml': - filepath = os.path.join(dirpath, filename) - with open(filepath) as f: - contents = f.read() - if new_code is None: - print('Current version code: ' + re.search(in_code, contents).group(1)) - new_code = raw_input('New version code: ') - print('Current version name: ' + re.search(in_name, contents).group(1)) - new_name = raw_input('New version name: ') - contents = re.sub(in_code, code % new_code, contents) - contents = re.sub(in_name, name % new_name, contents) - with open(filepath, 'w') as f: - f.write(contents) - -# Update change log -with open(changelog) as f: - contents = f.read() -if 'In Development' in contents: - contents = contents.replace('In Development', date.today().strftime('%Y-%m-%d')) - with open(changelog, 'w') as f: - f.write(contents)

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 X9Df(GyQW>hf43jgw9-?^liL3Qe0D 4.0.0 - com.actionbarsherlock - library + actionbarsherlock ActionBarSherlock apklib com.actionbarsherlock parent - 3.3.0 + 4.2.0 ../pom.xml - + - android + com.google.android android provided + + com.google.android + support-v4 + + + + junit + junit + test + src + test com.jayway.maven.plugins.android.generation2 - maven-android-plugin + android-maven-plugin true + + ignored + @@ -41,11 +54,33 @@ + + com.google.code.maven-replacer-plugin + maven-replacer-plugin + 1.4.0 + + + process-sources + + replace + + + + + false + target/generated-sources/r/com/actionbarsherlock/R.java + target/generated-sources/r/com/actionbarsherlock/R.java + false + static final int + static int + + + org.apache.maven.plugins maven-checkstyle-plugin - ${project.basedir}/checkstyle.xml + ../checkstyle.xml @@ -79,5 +114,35 @@ + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + com.google.code.maven-replacer-plugin + maven-replacer-plugin + [1.4.0,) + + replace + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/project.properties b/external/JakeWharton-ActionBarSherlock/library/project.properties index 05e464d6..616f300c 100644 --- a/external/JakeWharton-ActionBarSherlock/library/project.properties +++ b/external/JakeWharton-ActionBarSherlock/library/project.properties @@ -9,4 +9,4 @@ android.library=true # Project target. -target=android-13 +target=android-16 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/color/abs__item_bg.xml b/external/JakeWharton-ActionBarSherlock/library/res/color/abs__item_bg.xml deleted file mode 100644 index 1a5e2ed2..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/color/abs__item_bg.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_disable_only_holo_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_disable_only_holo_dark.xml new file mode 100644 index 00000000..ea7459aa --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_disable_only_holo_dark.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_disable_only_holo_light.xml b/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_disable_only_holo_light.xml new file mode 100644 index 00000000..0edb33b4 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_disable_only_holo_light.xml @@ -0,0 +1,21 @@ + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_holo_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_holo_dark.xml new file mode 100644 index 00000000..2bcfd0b6 --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_holo_dark.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_holo_light.xml b/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_holo_light.xml new file mode 100644 index 00000000..198384fe --- /dev/null +++ b/external/JakeWharton-ActionBarSherlock/library/res/color/abs__primary_text_holo_light.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + diff --git a/external/JakeWharton-ActionBarSherlock/library/res/color/abs__tab_text_color_dark.xml b/external/JakeWharton-ActionBarSherlock/library/res/color/abs__tab_text_color_dark.xml deleted file mode 100644 index ef120df8..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/color/abs__tab_text_color_dark.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/res/color/abs__tab_text_color_light.xml b/external/JakeWharton-ActionBarSherlock/library/res/color/abs__tab_text_color_light.xml deleted file mode 100644 index 4174d184..00000000 --- a/external/JakeWharton-ActionBarSherlock/library/res/color/abs__tab_text_color_light.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_solid_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_solid_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..769463b369a5185ba2d2fdf26abf058086ebcd08 GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^S!aZFaLn02py|Iz^fCC51!MDwC ze!c%VXGhEQ)_dJsezHtpNMD|7Dac@a*_ZJyulFV2w{5C|YCbaz5)ZX-3ak0tIJ#lm tp_aeGY*)k&iW*FhzahTiJD1r}=BlLiI{(TJ=>e@^@O1TaS?83{1OUpzopr0A6)2vH$=8 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_solid_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_solid_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..73050476e77aa798919b829a5566973e231f9d49 GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^S!aZFaLn02py|Iz^fCC51!MFRR zxpqaJ>-4UOe6iPKwm$=BLD{Wo!i)yScSSDT-Jo*!N?wFe;-MB!VKtu_20%tEPqwzt q4f{lgTEQ5`;-9UxjMeKCf^DQ_uhd?;-Btm#g2B_(&t;ucLK6V6dokDm literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_transparent_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_transparent_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..712a551ece87b2544433ac982382a087e7f1731d GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^S{5)M8Ln02py}Xf^L4oIp!}}xu zHrx6hVG;aws8xB@i!KMDZA_cCWy>wsRQS4KRST!En$HY_#6vK~{lt8cLjun}a%VT6 c)z9eScC>M27UGHi05qAw)78&qol`;+0QSr+Bme*a literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_transparent_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_bottom_transparent_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..bf3b9438b16543294498ba27e51d4e878c8ead5a GIT binary patch literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^Sd_7$pLn02py}Xh4fCCS+;oB*H z(}QQZt5vXQMa=PTZk@YrXXvE3+ofW5$)(cU#3WF_jrSY!c@8l>`*HAE!gKCvr?`99 W=bm|#aNiDSFoUP7pUXO@geCw#94y)Z literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..81b87b86c959a98c478177270c979763831ebf66 GIT binary patch literal 2863 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 N002ovPDHLkV1kHdRS^IH literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..8fc83e22efde5509c563c97a836d869d05ff5dc6 GIT binary patch literal 2859 zcmV+`3)J+9P)Oz@Z0f2-7z;ux~O9+4z06=<WDR*FRcSTFz- zW=q650N5=6FiBTtNC2?60Km==3$g$R3;-}uh=nNt1bYBr$Ri_o0EC$U6h`t_Jn<{8 z5a%iY0C<_QJh>z}MS)ugEpZ1|S1ukX&Pf+56gFW3VVXcL!g-k)GJ!M?;PcD?0HBc- z5#WRK{dmp}uFlRjj{U%*%WZ25jX z{P*?XzTzZ-GF^d31o+^>%=Ap99M6&ogks$0k4OBs3;+Bb(;~!4V!2o<6ys46agIcq zjPo+3B8fthDa9qy|77CdEc*jK-!%ZRYCZvbku9iQV*~a}ClFY4z~c7+0P?$U!PF=S z1Au6Q;m>#f??3%Vpd|o+W=WE9003S@Bra6Svp>fO002awfhw>;8}z{#EWidF!3EsG z3;bXU&9EIRU@z1_9W=mEXoiz;4lcq~xDGvV5BgyU zp1~-*fe8db$Osc*A=-!mVv1NJjtCc-h4>-CNCXm#Bp}I%6j35eku^v$Qi@a{RY)E3 zJ#qp$hg?Rwkvqr$GJ^buyhkyVfwECO)C{#lxu`c9ghrwZ&}4KmnvWKso6vH!8a<3Q zq36)6Xb;+tK10Vaz~~qUGsJ8#F2=(`u{bOVlVi)VBCHIn#u~6ztOL7=^<&SmcLWlF zMZgI*1b0FpVIDz9SWH+>*hr`#93(Um+6gxa1B6k+CnA%mOSC4s5&6UzVlpv@SV$}* z))J2sFA#f(L&P^E5{W}HC%KRUNwK6<(h|}}(r!{C=`5+6G)NjFlgZj-YqAG9lq?`C z$c5yc>d>VnA`E_*3F2Qp##d8RZb=H01_mm@+|Cqnc9PsG(F5HIG_C zt)aG3uTh7n6Et<2In9F>NlT@zqLtGcXcuVrX|L#Xx)I%#9!{6gSJKPrN9dR61N3(c z4Tcqi$B1Vr8Jidf7-t!G7_XR2rWwr)$3XQ?}=hpK0&Z&W{| zep&sA23f;Q!%st`QJ}G3cbou<7-yIK2z4nfCCCtN2-XOGSWo##{8Q{ATurxr~;I`ytDs%xbip}RzP zziy}Qn4Z2~fSycmr`~zJ=lUFdFa1>gZThG6M+{g7vkW8#+YHVaJjFF}Z#*3@$J_By zLtVo_L#1JrVVB{Ak-5=4qt!-@Mh}c>#$4kh<88)m#-k<%CLtzEP3leVno>={htGUuD;o7bD)w_sX$S}eAxwzy?UvgBH(S?;#HZiQMoS*2K2 zT3xe7t(~nU*1N5{rxB;QPLocnp4Ml>u<^FZwyC!nu;thW+pe~4wtZn|Vi#w(#jeBd zlf9FDx_yoPJqHbk*$%56S{;6Kv~mM9!g3B(KJ}#RZ#@)!hR|78Dq|Iq-afF%KE1Brn_fm;Im z_u$xr8UFki1L{Ox>G0o)(&RAZ;=|I=wN2l97;cLaHH6leTB-XXa*h%dBOEvi`+x zi?=Txl?TadvyiL>SuF~-LZ;|cS}4~l2eM~nS7yJ>iOM;atDY;(?aZ^v+mJV$@1Ote z62cPUlD4IWOIIx&SmwQ~YB{nzae3Pc;}r!fhE@iwJh+OsDs9zItL;~pu715HdQEGA zUct(O!LkCy1<%NCg+}G`0PgpNm-?d@-hMgNe6^V+j6x$b<6@S<$+<4_1hi}Ti zncS4LsjI}fWY1>OX6feMEuLErma3QLmkw?X+1j)X-&VBk_4Y;EFPF_I+q;9dL%E~B zJh;4Nr^(LEJ3myURP{Rblsw%57T)g973R8o)DE9*xN#~;4_o$q%o z4K@u`jhx2fBXC4{U8Qn{*%*B$Ge=nny$HAYq{=vy|sI0 z_vss+H_qMky?OB#|JK!>IX&II^LlUh#rO5!7TtbwC;iULyV-Xq?ybB}ykGP{?LpZ? z-G|jbTmIbG@7#ZCz;~eY(cDM(28Dyq{*m>M4?_iynUBkc4TkHUI6gT!;y-fz>HMcd z&t%Ugo)`Y2{>!cx7B7DI)$7;J(U{Spm-3gBzioV_{p!H$8L!*M!p0uH$#^p{Ui4P` z?ZJ24cOCDe-w#jZd?0@)|7iKK^;6KN`;!@ylm7$*nDhK&GcDTy000JJOGiWi{{a60 z|De66lK=n!32;bRa{vGf6951U69E94oEQKA00(qQO+^RX1_J~v33EADYybcNT}ebi zR9M69*TD^dAP@k-!&n%l+Zk4%XvhVkGhZ~Uxd#&QUQ2!+fJ~*cUX%Afu1<@6;N?-b zAHA(QN@2o;2@{qW)>aKGMk!2~FkwFmdvZ&v0l;_k{`cFg{ZH922Xd1D?Op%?002ov JPDHLkV1neRPs;!R literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_solid_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_solid_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..cbbaec588ec98bbc8a518a9ab5a9c469482341ba GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^SB0XIkLn02py}Xe3KmgB?fcJu8 z^Zp*+-L#E6MBZg;W9F9wttxZ4PHc?!oG~+pYe(tbxxSpjYCbaz5)ZY&8G8*Bq7ylO npZ&2~Yqrog$!|3Wm+fFU5UE)t_U_Fapd}2Ru6{1-oD!M-^V;Vpy{TG>rs2jRbt|WpWjh#Ji#?9Gi^wblTEgJz>gTe~DWM4fZg4bX literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_stacked_transparent_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_stacked_transparent_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1e39572224b24a81ed4d73923280ba2724dbaf6e GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^Sf;?RuLn02py|Iy(L4oIp!})_Q zZ}wlfoYKNk`|wbZR*CB+2cd0Do4#G+S+1#YsD)El&1Z%|BAjt`!_S2)TNKYc{m-!5 f_v_(jT(cfAPEEXE)c4^Y$T|j3S3j3^P6 literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_stacked_transparent_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_stacked_transparent_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..a16db853e94af78c0739d9b89b578e2a8021c856 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^Sd^}woLn02py|j?`fP(zopr08IHUH2?qr literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_transparent_dark_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_transparent_dark_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0eff695d82911a73874d871f3a7b23b71dd8ab44 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^Sl001;Ln02py?l}LfC5j;!{`N< zEvnsL$t-6rWU%$psDGg1|4DLDj`q~RzPqNgR|nl=*Rt6dx_ol~p-I||JQ4;82O1ce y*`SQyBHQ|!3>bf({j~je;Zla%ZD->HG+$+yO5M3zoXrBXjlt8^&t;ucLK6T4R5w)s literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_transparent_light_holo.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__ab_transparent_light_holo.9.png new file mode 100644 index 0000000000000000000000000000000000000000..219b170fa67aa2ef8e0b11ebff90c1629ba7e97a GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^SB0OCjLn02py?l|AL4l*?;q8?- zrB_<6lUu~-<@8GYocm9fskyGHQx2!G9uAwU_k&&MlS%_4GaHYDLBatTBRp}nY76HL mkjg^D5fnx&0glSHJj>3%>1Jqp^q#PeS;bnL@oAJ;NJ=s*Cb_P#ZKbLh* G2~7YBfgFPX literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..66adffed632f0f6267afe6dc2f518adb6a83ca4a GIT binary patch literal 110 zcmeAS@N?(olHy`uVBq!ia0vp^EI_Qo!3HFq_#{<Lb literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_bottom_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_bottom_holo_dark.9.png new file mode 100644 index 0000000000000000000000000000000000000000..1d836f65a1fffea301e9cf36770b21b48b3b8132 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^SVmw_OLn02py|R(B!9jra;>r_8 z?%b*io|Yn;UGT9};ZTu}!9}%xc^%IgtXD4oJ@0X-F7B%4f|j+c$=0hv54CU#tNF|@ sNQ5wMgi8eI0r?xYZ}@0_Yf6jsMX$B_pXOhT0oudh>FVdQ&MBb@0DzD;x&QzG literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_bottom_holo_light.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_bottom_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..5818666d4e64b93da73bc3d6dc2764bcb500359c GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^SB0OCjLn02py|R(>fCCT9!M7)Q zv literal 0 HcmV?d00001 diff --git a/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_holo_dark.9.png b/external/JakeWharton-ActionBarSherlock/library/res/drawable-hdpi/abs__cab_background_holo_dark.9.png deleted file mode 100644 index 1a916b3fa658aefb8e1c0b5364a96d1ca4e0ff70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3307 zcmV