aboutsummaryrefslogtreecommitdiffstats
path: root/com_actionbarsherlock
diff options
context:
space:
mode:
authorDominik <dominik@dominikschuermann.de>2012-04-20 12:14:21 +0200
committerDominik <dominik@dominikschuermann.de>2012-06-13 19:28:23 +0300
commitda96aacf55d113c9a91b8e760b3ffef88b11f786 (patch)
treeb7e5a7780af54fdb677a147a40e7218ee5bbc123 /com_actionbarsherlock
parent784c3156dfaac289ddf5a65567385c3561426401 (diff)
downloadopen-keychain-da96aacf55d113c9a91b8e760b3ffef88b11f786.tar.gz
open-keychain-da96aacf55d113c9a91b8e760b3ffef88b11f786.tar.bz2
open-keychain-da96aacf55d113c9a91b8e760b3ffef88b11f786.zip
ActionBarSherlock 4.0.2
Diffstat (limited to 'com_actionbarsherlock')
-rw-r--r--com_actionbarsherlock/AndroidManifest.xml11
-rw-r--r--com_actionbarsherlock/README.md4
-rw-r--r--com_actionbarsherlock/libs/android-support-v4.jarbin247894 -> 271754 bytes
-rw-r--r--com_actionbarsherlock/pom.xml2
-rw-r--r--com_actionbarsherlock/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.pngbin0 -> 2866 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.pngbin0 -> 2862 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-hdpi/abs__ic_menu_share_holo_dark.pngbin0 -> 467 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-hdpi/abs__ic_menu_share_holo_light.pngbin0 -> 505 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-hdpi/abs__list_activated_holo.9.pngbin0 -> 154 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.pngbin0 -> 2851 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.pngbin0 -> 122 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-mdpi/abs__dialog_full_holo_dark.9.pngbin0 -> 882 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-mdpi/abs__dialog_full_holo_light.9.pngbin0 -> 1003 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-mdpi/abs__ic_menu_share_holo_dark.pngbin0 -> 332 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-mdpi/abs__ic_menu_share_holo_light.pngbin0 -> 355 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-mdpi/abs__list_activated_holo.9.pngbin0 -> 151 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.pngbin0 -> 2875 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.pngbin0 -> 2869 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.pngbin0 -> 2159 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-xhdpi/abs__dialog_full_holo_light.9.pngbin0 -> 2302 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.pngbin0 -> 699 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_light.pngbin0 -> 935 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-xhdpi/abs__list_activated_holo.9.pngbin0 -> 158 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-xhdpi/abs__spinner_48_inner_holo.pngbin0 -> 2769 bytes
-rw-r--r--com_actionbarsherlock/res/drawable-xhdpi/abs__spinner_48_outer_holo.pngbin0 -> 2432 bytes
-rw-r--r--com_actionbarsherlock/res/drawable/abs__activated_background_holo_dark.xml20
-rw-r--r--com_actionbarsherlock/res/drawable/abs__activated_background_holo_light.xml20
-rw-r--r--com_actionbarsherlock/res/drawable/abs__btn_cab_done_holo_dark.xml3
-rw-r--r--com_actionbarsherlock/res/drawable/abs__btn_cab_done_holo_light.xml3
-rw-r--r--com_actionbarsherlock/res/drawable/abs__item_background_holo_dark.xml3
-rw-r--r--com_actionbarsherlock/res/drawable/abs__item_background_holo_light.xml3
-rw-r--r--com_actionbarsherlock/res/drawable/abs__list_selector_holo_dark.xml3
-rw-r--r--com_actionbarsherlock/res/drawable/abs__list_selector_holo_light.xml3
-rw-r--r--com_actionbarsherlock/res/layout/abs__action_menu_layout.xml6
-rw-r--r--com_actionbarsherlock/res/layout/abs__activity_chooser_view.xml70
-rw-r--r--com_actionbarsherlock/res/layout/abs__activity_chooser_view_list_item.xml53
-rw-r--r--com_actionbarsherlock/res/layout/abs__screen_action_bar.xml12
-rw-r--r--com_actionbarsherlock/res/layout/abs__screen_action_bar_overlay.xml23
-rw-r--r--com_actionbarsherlock/res/layout/abs__screen_simple_overlay_action_mode.xml2
-rw-r--r--com_actionbarsherlock/res/values-v14/abs__themes.xml6
-rw-r--r--com_actionbarsherlock/res/values/abs__attrs.xml69
-rw-r--r--com_actionbarsherlock/res/values/abs__strings.xml15
-rw-r--r--com_actionbarsherlock/res/values/abs__styles.xml78
-rw-r--r--com_actionbarsherlock/res/values/abs__themes.xml24
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/ActionBarSherlock.java1
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockDialogFragment.java8
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockFragment.java8
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockFragmentActivity.java39
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockListFragment.java8
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java35
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java10
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java6
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java2
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java6
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java2
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.java41
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java10
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java4
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java41
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/MenuMule.java1
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/ActionBarView.java8
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java4
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java154
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java4
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsSpinner.java4
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java4
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/widget/ActivityChooserModel.java1131
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/widget/ActivityChooserView.java818
-rw-r--r--com_actionbarsherlock/src/com/actionbarsherlock/widget/ShareActionProvider.java316
69 files changed, 2920 insertions, 178 deletions
diff --git a/com_actionbarsherlock/AndroidManifest.xml b/com_actionbarsherlock/AndroidManifest.xml
index a1f0e16ee..36ad79440 100644
--- a/com_actionbarsherlock/AndroidManifest.xml
+++ b/com_actionbarsherlock/AndroidManifest.xml
@@ -1,13 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.actionbarsherlock"
- android:versionCode="50"
- android:versionName="4.0.0">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="60" android:versionName="4.0.2" package="com.actionbarsherlock">
- <uses-sdk
- android:minSdkVersion="7"
- android:targetSdkVersion="15" />
+ <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15"/>
</manifest>
diff --git a/com_actionbarsherlock/README.md b/com_actionbarsherlock/README.md
index 4b22e6fe2..e8a2c080e 100644
--- a/com_actionbarsherlock/README.md
+++ b/com_actionbarsherlock/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/com_actionbarsherlock/libs/android-support-v4.jar b/com_actionbarsherlock/libs/android-support-v4.jar
index d006198e6..99e063b33 100644
--- a/com_actionbarsherlock/libs/android-support-v4.jar
+++ b/com_actionbarsherlock/libs/android-support-v4.jar
Binary files differ
diff --git a/com_actionbarsherlock/pom.xml b/com_actionbarsherlock/pom.xml
index 52a7207c9..ba4d427d0 100644
--- a/com_actionbarsherlock/pom.xml
+++ b/com_actionbarsherlock/pom.xml
@@ -11,7 +11,7 @@
<parent>
<groupId>com.actionbarsherlock</groupId>
<artifactId>parent</artifactId>
- <version>4.0.0</version>
+ <version>4.0.2</version>
<relativePath>../pom.xml</relativePath>
</parent>
diff --git a/com_actionbarsherlock/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png b/com_actionbarsherlock/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png
new file mode 100644
index 000000000..6c1415772
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png b/com_actionbarsherlock/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png
new file mode 100644
index 000000000..f4ff16be7
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png b/com_actionbarsherlock/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png
new file mode 100644
index 000000000..6f747c8f0
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-hdpi/abs__ic_menu_share_holo_light.png b/com_actionbarsherlock/res/drawable-hdpi/abs__ic_menu_share_holo_light.png
new file mode 100644
index 000000000..682b2fdec
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-hdpi/abs__ic_menu_share_holo_light.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-hdpi/abs__list_activated_holo.9.png b/com_actionbarsherlock/res/drawable-hdpi/abs__list_activated_holo.9.png
new file mode 100644
index 000000000..4ea7afa00
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-hdpi/abs__list_activated_holo.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png b/com_actionbarsherlock/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png
new file mode 100644
index 000000000..ed4ba34ec
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png b/com_actionbarsherlock/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png
new file mode 100644
index 000000000..8f10bd522
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png b/com_actionbarsherlock/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png
new file mode 100644
index 000000000..fb3660eab
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-mdpi/abs__dialog_full_holo_light.9.png b/com_actionbarsherlock/res/drawable-mdpi/abs__dialog_full_holo_light.9.png
new file mode 100644
index 000000000..f18050ea5
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-mdpi/abs__dialog_full_holo_light.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png b/com_actionbarsherlock/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png
new file mode 100644
index 000000000..6bf21e307
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-mdpi/abs__ic_menu_share_holo_light.png b/com_actionbarsherlock/res/drawable-mdpi/abs__ic_menu_share_holo_light.png
new file mode 100644
index 000000000..70fe31aa2
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-mdpi/abs__ic_menu_share_holo_light.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-mdpi/abs__list_activated_holo.9.png b/com_actionbarsherlock/res/drawable-mdpi/abs__list_activated_holo.9.png
new file mode 100644
index 000000000..3bf8e0362
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-mdpi/abs__list_activated_holo.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png b/com_actionbarsherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png
new file mode 100644
index 000000000..55099d49d
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png b/com_actionbarsherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png
new file mode 100644
index 000000000..3c4701fc2
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png b/com_actionbarsherlock/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png
new file mode 100644
index 000000000..f4970ad1c
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png b/com_actionbarsherlock/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png
new file mode 100644
index 000000000..172fc3b5e
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png b/com_actionbarsherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png
new file mode 100644
index 000000000..45a0f1da0
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png b/com_actionbarsherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png
new file mode 100644
index 000000000..528e554ab
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-xhdpi/abs__list_activated_holo.9.png b/com_actionbarsherlock/res/drawable-xhdpi/abs__list_activated_holo.9.png
new file mode 100644
index 000000000..eda10e612
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-xhdpi/abs__list_activated_holo.9.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-xhdpi/abs__spinner_48_inner_holo.png b/com_actionbarsherlock/res/drawable-xhdpi/abs__spinner_48_inner_holo.png
new file mode 100644
index 000000000..19517c4b0
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-xhdpi/abs__spinner_48_inner_holo.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable-xhdpi/abs__spinner_48_outer_holo.png b/com_actionbarsherlock/res/drawable-xhdpi/abs__spinner_48_outer_holo.png
new file mode 100644
index 000000000..14143c51c
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable-xhdpi/abs__spinner_48_outer_holo.png
Binary files differ
diff --git a/com_actionbarsherlock/res/drawable/abs__activated_background_holo_dark.xml b/com_actionbarsherlock/res/drawable/abs__activated_background_holo_dark.xml
new file mode 100644
index 000000000..85c2c0212
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable/abs__activated_background_holo_dark.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_activated="true" android:drawable="@drawable/abs__list_activated_holo" />
+ <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/com_actionbarsherlock/res/drawable/abs__activated_background_holo_light.xml b/com_actionbarsherlock/res/drawable/abs__activated_background_holo_light.xml
new file mode 100644
index 000000000..85c2c0212
--- /dev/null
+++ b/com_actionbarsherlock/res/drawable/abs__activated_background_holo_light.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_activated="true" android:drawable="@drawable/abs__list_activated_holo" />
+ <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/com_actionbarsherlock/res/drawable/abs__btn_cab_done_holo_dark.xml b/com_actionbarsherlock/res/drawable/abs__btn_cab_done_holo_dark.xml
index d470e9859..cab896283 100644
--- a/com_actionbarsherlock/res/drawable/abs__btn_cab_done_holo_dark.xml
+++ b/com_actionbarsherlock/res/drawable/abs__btn_cab_done_holo_dark.xml
@@ -14,8 +14,7 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/abs__btn_cab_done_pressed_holo_dark" />
<item android:state_focused="true" android:state_enabled="true"
diff --git a/com_actionbarsherlock/res/drawable/abs__btn_cab_done_holo_light.xml b/com_actionbarsherlock/res/drawable/abs__btn_cab_done_holo_light.xml
index b2984f2e7..42ba8a0df 100644
--- a/com_actionbarsherlock/res/drawable/abs__btn_cab_done_holo_light.xml
+++ b/com_actionbarsherlock/res/drawable/abs__btn_cab_done_holo_light.xml
@@ -14,8 +14,7 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/abs__btn_cab_done_pressed_holo_light" />
<item android:state_focused="true" android:state_enabled="true"
diff --git a/com_actionbarsherlock/res/drawable/abs__item_background_holo_dark.xml b/com_actionbarsherlock/res/drawable/abs__item_background_holo_dark.xml
index a4c625cc5..d99b7a426 100644
--- a/com_actionbarsherlock/res/drawable/abs__item_background_holo_dark.xml
+++ b/com_actionbarsherlock/res/drawable/abs__item_background_holo_dark.xml
@@ -14,8 +14,7 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
<item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abs__list_selector_disabled_holo_dark" />
diff --git a/com_actionbarsherlock/res/drawable/abs__item_background_holo_light.xml b/com_actionbarsherlock/res/drawable/abs__item_background_holo_light.xml
index f989197ad..da5fb2e86 100644
--- a/com_actionbarsherlock/res/drawable/abs__item_background_holo_light.xml
+++ b/com_actionbarsherlock/res/drawable/abs__item_background_holo_light.xml
@@ -14,8 +14,7 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
<item android:state_focused="true" android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abs__list_selector_disabled_holo_light" />
diff --git a/com_actionbarsherlock/res/drawable/abs__list_selector_holo_dark.xml b/com_actionbarsherlock/res/drawable/abs__list_selector_holo_dark.xml
index ee497a239..08b8b12f3 100644
--- a/com_actionbarsherlock/res/drawable/abs__list_selector_holo_dark.xml
+++ b/com_actionbarsherlock/res/drawable/abs__list_selector_holo_dark.xml
@@ -14,8 +14,7 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:drawable="@android:color/transparent" />
diff --git a/com_actionbarsherlock/res/drawable/abs__list_selector_holo_light.xml b/com_actionbarsherlock/res/drawable/abs__list_selector_holo_light.xml
index e1522ee43..ada490bf9 100644
--- a/com_actionbarsherlock/res/drawable/abs__list_selector_holo_light.xml
+++ b/com_actionbarsherlock/res/drawable/abs__list_selector_holo_light.xml
@@ -14,8 +14,7 @@
limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
- android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:drawable="@android:color/transparent" />
diff --git a/com_actionbarsherlock/res/layout/abs__action_menu_layout.xml b/com_actionbarsherlock/res/layout/abs__action_menu_layout.xml
index 7010bcce9..a6f8e53f8 100644
--- a/com_actionbarsherlock/res/layout/abs__action_menu_layout.xml
+++ b/com_actionbarsherlock/res/layout/abs__action_menu_layout.xml
@@ -4,9 +4,9 @@
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.
@@ -18,6 +18,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:divider="?attr/dividerVertical"
+ android:divider="?attr/actionBarDivider"
android:dividerPadding="12dip"
android:gravity="center_vertical" />
diff --git a/com_actionbarsherlock/res/layout/abs__activity_chooser_view.xml b/com_actionbarsherlock/res/layout/abs__activity_chooser_view.xml
new file mode 100644
index 000000000..019d14ef4
--- /dev/null
+++ b/com_actionbarsherlock/res/layout/abs__activity_chooser_view.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+<com.actionbarsherlock.internal.widget.IcsLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/abs__activity_chooser_view_content"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:layout_gravity="center"
+ style="?attr/activityChooserViewStyle">
+
+ <FrameLayout
+ android:id="@+id/abs__expand_activities_button"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:layout_gravity="center"
+ android:focusable="true"
+ android:addStatesFromChildren="true"
+ android:background="?attr/actionBarItemBackground">
+
+ <ImageView android:id="@+id/abs__image"
+ android:layout_width="56dip"
+ android:layout_height="36dip"
+ android:layout_gravity="center"
+ android:paddingTop="2dip"
+ android:paddingBottom="2dip"
+ android:paddingLeft="12dip"
+ android:paddingRight="12dip"
+ android:scaleType="fitCenter"
+ android:adjustViewBounds="true" />
+
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/abs__default_activity_button"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:layout_gravity="center"
+ android:focusable="true"
+ android:addStatesFromChildren="true"
+ android:background="?attr/actionBarItemBackground">
+
+ <ImageView android:id="@+id/abs__image"
+ android:layout_width="56dip"
+ android:layout_height="36dip"
+ android:layout_gravity="center"
+ android:paddingTop="2dip"
+ android:paddingBottom="2dip"
+ android:paddingLeft="12dip"
+ android:paddingRight="12dip"
+ android:scaleType="fitCenter"
+ android:adjustViewBounds="true" />
+
+ </FrameLayout>
+
+</com.actionbarsherlock.internal.widget.IcsLinearLayout>
diff --git a/com_actionbarsherlock/res/layout/abs__activity_chooser_view_list_item.xml b/com_actionbarsherlock/res/layout/abs__activity_chooser_view_list_item.xml
new file mode 100644
index 000000000..b430032a1
--- /dev/null
+++ b/com_actionbarsherlock/res/layout/abs__activity_chooser_view_list_item.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/abs__list_item"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/dropdownListPreferredItemHeight"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:minWidth="196dip"
+ android:background="?attr/activatedBackgroundIndicator"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:duplicateParentState="true" >
+
+ <ImageView
+ android:id="@+id/abs__icon"
+ android:layout_width="32dip"
+ android:layout_height="32dip"
+ android:layout_gravity="center_vertical"
+ android:layout_marginRight="8dip"
+ android:duplicateParentState="true" />
+
+ <TextView
+ android:id="@+id/abs__title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:textAppearance="?attr/textAppearanceLargePopupMenu"
+ android:duplicateParentState="true"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/com_actionbarsherlock/res/layout/abs__screen_action_bar.xml b/com_actionbarsherlock/res/layout/abs__screen_action_bar.xml
index 17fd16c22..1fb82fe9a 100644
--- a/com_actionbarsherlock/res/layout/abs__screen_action_bar.xml
+++ b/com_actionbarsherlock/res/layout/abs__screen_action_bar.xml
@@ -4,9 +4,9 @@
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.
@@ -19,10 +19,10 @@ This is an optimized layout for a screen with the Action Bar enabled.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:orientation="vertical"
- android:fitsSystemWindows="true"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
+ android:fitsSystemWindows="true">
<com.actionbarsherlock.internal.widget.ActionBarContainer
android:id="@+id/abs__action_bar_container"
android:layout_width="fill_parent"
@@ -42,7 +42,7 @@ This is an optimized layout for a screen with the Action Bar enabled.
</com.actionbarsherlock.internal.widget.ActionBarContainer>
<com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout
android:id="@+id/abs__content"
- android:layout_width="fill_parent"
+ android:layout_width="fill_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
diff --git a/com_actionbarsherlock/res/layout/abs__screen_action_bar_overlay.xml b/com_actionbarsherlock/res/layout/abs__screen_action_bar_overlay.xml
index 657aeb794..0961ef561 100644
--- a/com_actionbarsherlock/res/layout/abs__screen_action_bar_overlay.xml
+++ b/com_actionbarsherlock/res/layout/abs__screen_action_bar_overlay.xml
@@ -19,38 +19,41 @@ This is an optimized layout for a screen with
the Action Bar enabled overlaying application content.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout android:id="@+id/abs__content"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent" />
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
<com.actionbarsherlock.internal.widget.ActionBarContainer android:id="@+id/abs__action_bar_container"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
style="?attr/actionBarStyle"
android:gravity="top">
<com.actionbarsherlock.internal.widget.ActionBarView
android:id="@+id/abs__action_bar"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?attr/actionBarStyle" />
<com.actionbarsherlock.internal.widget.ActionBarContextView
android:id="@+id/abs__action_context_bar"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
style="?attr/actionModeStyle" />
</com.actionbarsherlock.internal.widget.ActionBarContainer>
<ImageView android:src="?attr/windowContentOverlay"
android:scaleType="fitXY"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/abs__action_bar_container" />
<com.actionbarsherlock.internal.widget.ActionBarContainer android:id="@+id/abs__split_action_bar"
- android:layout_width="fill_parent"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
+ android:layout_gravity="bottom"
style="?attr/actionBarSplitStyle"
android:visibility="gone"
android:gravity="center"/>
-</RelativeLayout>
+</FrameLayout>
diff --git a/com_actionbarsherlock/res/layout/abs__screen_simple_overlay_action_mode.xml b/com_actionbarsherlock/res/layout/abs__screen_simple_overlay_action_mode.xml
index 58bafaf1e..f8b9fb185 100644
--- a/com_actionbarsherlock/res/layout/abs__screen_simple_overlay_action_mode.xml
+++ b/com_actionbarsherlock/res/layout/abs__screen_simple_overlay_action_mode.xml
@@ -21,6 +21,8 @@ enabled.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:fitsSystemWindows="true">
<com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout
android:id="@+id/abs__content"
diff --git a/com_actionbarsherlock/res/values-v14/abs__themes.xml b/com_actionbarsherlock/res/values-v14/abs__themes.xml
index f8844ad25..ceb960737 100644
--- a/com_actionbarsherlock/res/values-v14/abs__themes.xml
+++ b/com_actionbarsherlock/res/values-v14/abs__themes.xml
@@ -10,6 +10,10 @@
<item name="actionBarSize">?android:attr/actionBarSize</item>
<!-- Needed for our bug-fix dropdown list navigation layout. :( -->
<item name="dropdownListPreferredItemHeight">48dp</item>
+ <!-- Needed for our ShareActionProvider implementation. -->
+ <item name="android:actionBarWidgetTheme">@style/Theme.Sherlock</item>
+ <!-- For crazy people who use IcsSpinner. -->
+ <item name="dropDownListViewStyle">?android:attr/dropDownListViewStyle</item>
</style>
<style name="Theme.Sherlock.NoActionBar">
@@ -20,7 +24,7 @@
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
</style>
-
+
<style name="Theme.Sherlock.Dialog" parent="android:Theme.Holo.Dialog">
</style>
<style name="Theme.Sherlock.Light.Dialog" parent="android:Theme.Holo.Light.Dialog">
diff --git a/com_actionbarsherlock/res/values/abs__attrs.xml b/com_actionbarsherlock/res/values/abs__attrs.xml
index af022dc9c..81c347108 100644
--- a/com_actionbarsherlock/res/values/abs__attrs.xml
+++ b/com_actionbarsherlock/res/values/abs__attrs.xml
@@ -7,7 +7,7 @@
<attr name="backgroundSplit" format="reference|color" />
<attr name="height" format="dimension" />
<attr name="divider" format="reference" />
-
+
<declare-styleable name="SherlockTheme">
<!-- =================== -->
<!-- Action bar styles -->
@@ -60,6 +60,8 @@
<attr name="actionModeSplitBackground" format="reference" />
<!-- Drawable to use for the close action mode button -->
<attr name="actionModeCloseDrawable" format="reference" />
+ <!-- Drawable to use for the Share action button in WebView selection action modes -->
+ <attr name="actionModeShareDrawable" format="reference" />
<!-- PopupWindow style to use for action modes when showing as a window overlay. -->
<attr name="actionModePopupWindowStyle" format="reference" />
@@ -71,9 +73,9 @@
<!-- Small Button style. -->
<attr name="buttonStyleSmall" format="reference" />
-
-
-
+
+
+
<!-- This Drawable is overlaid over the foreground of the Window's content area, usually
to place a shadow below the title. -->
<attr name="windowContentOverlay" format="reference" />
@@ -83,15 +85,15 @@
<!-- Text color, typeface, size, and style for small text inside of a popup menu. -->
<attr name="textAppearanceSmallPopupMenu" format="reference" />
-
-
+
+
<!-- Text color, typeface, size, and style for "small" text. Defaults to secondary text color. -->
<attr name="textAppearanceSmall" format="reference" />
-
+
<attr name="textColorPrimary" format="color" />
<attr name="textColorPrimaryDisableOnly" format="color" />
<attr name="textColorPrimaryInverse" format="color" />
-
+
<attr name="spinnerItemStyle" format="reference" />
<attr name="spinnerDropDownItemStyle" format="reference" />
@@ -99,7 +101,7 @@
<!-- List styles -->
<!-- =========== -->
<eat-comment />
-
+
<!-- A smaller, sleeker list item height. -->
<attr name="listPreferredItemHeightSmall" format="dimension" />
@@ -107,19 +109,19 @@
<attr name="listPreferredItemPaddingLeft" format="dimension" />
<!-- The preferred padding along the right edge of list items. -->
<attr name="listPreferredItemPaddingRight" format="dimension" />
-
+
<!-- The preferred TextAppearance for the primary text of small list items. -->
<attr name="textAppearanceListItemSmall" format="reference" />
-
-
+
+
<attr name="windowMinWidthMajor" format="dimension" />
<attr name="windowMinWidthMinor" format="dimension" />
-
-
+
+
<!-- Drawable to use for generic vertical dividers. -->
<attr name="dividerVertical" format="reference" />
-
+
<attr name="actionDropDownStyle" format="reference" />
<attr name="actionButtonStyle" format="reference" />
<attr name="homeAsUpIndicator" format="reference" />
@@ -132,13 +134,22 @@
<attr name="windowActionBarOverlay" format="boolean"/>
<attr name="windowActionModeOverlay" format="boolean"/>
<attr name="windowSplitActionBar" format="boolean" />
-
+
+
+ <attr name="listPopupWindowStyle" format="reference" />
+
+
+ <!-- Default ActivityChooserView style. -->
+ <attr name="activityChooserViewStyle" format="reference" />
+ <!-- Drawable used as a background for activated items. -->
+ <attr name="activatedBackgroundIndicator" format="reference" />
+
<!-- Specified if we are forcing an action item overflow menu. -->
<attr name="absForceOverflow" format="boolean" />
-
+
<attr name="android:windowIsFloating" />
</declare-styleable>
-
+
<!-- Attributes used to style the Action Bar. -->
<declare-styleable name="SherlockActionBar">
@@ -196,7 +207,7 @@
system-provided items in the bar. -->
<attr name="itemPadding" format="dimension" />
</declare-styleable>
-
+
<declare-styleable name="SherlockActionMode">
<!-- Specifies a style to use for title text. -->
@@ -210,7 +221,7 @@
<!-- Specifies a fixed height for the action mode bar. -->
<attr name="height" />
</declare-styleable>
-
+
<declare-styleable name="SherlockMenuView">
<!-- Default appearance of menu item text. -->
<attr name="itemTextAppearance" format="reference" />
@@ -229,11 +240,25 @@
<!-- Whether space should be reserved in layout when an icon is missing. -->
<attr name="preserveIconSpacing" format="boolean" />
</declare-styleable>
-
+
<declare-styleable name="SherlockActionMenuItemView">
<attr name="android:minWidth" />
</declare-styleable>
+ <declare-styleable name="SherlockActivityChooserView">
+ <!-- The maximal number of items initially shown in the activity list. -->
+ <attr name="initialActivityCount" format="string" />
+ <!-- The drawable to show in the button for expanding the activities overflow popup.
+ <strong>Note:</strong> Clients would like to set this drawable
+ as a clue about the action the chosen activity will perform. For
+ example, if share activity is to be chosen the drawable should
+ give a clue that sharing is to be performed.
+ -->
+ <attr name="expandActivityOverflowButtonDrawable" format="reference" />
+
+ <attr name="android:background" />
+ </declare-styleable>
+
<!-- Base attributes that are available to all groups. -->
<declare-styleable name="SherlockMenuGroup">
@@ -329,7 +354,7 @@
<attr name="android:actionProviderClass" />
</declare-styleable>
-
+
<declare-styleable name="SherlockSpinner">
<!-- The prompt to display when the spinner's dialog is shown. -->
<attr name="android:prompt" />
diff --git a/com_actionbarsherlock/res/values/abs__strings.xml b/com_actionbarsherlock/res/values/abs__strings.xml
index c228281e7..1e1c7022c 100644
--- a/com_actionbarsherlock/res/values/abs__strings.xml
+++ b/com_actionbarsherlock/res/values/abs__strings.xml
@@ -16,7 +16,7 @@
** limitations under the License.
*/
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Content description for the action bar "home" affordance. [CHAR LIMIT=NONE] -->
<string name="abs__action_bar_home_description">Navigate home</string>
<!-- Content description for the action bar "up" affordance. [CHAR LIMIT=NONE] -->
@@ -26,4 +26,17 @@
<!-- Label for the "Done" button on the far left of action mode toolbars. -->
<string name="abs__action_mode_done">Done</string>
+
+ <!-- Title for a button to expand the list of activities in ActivityChooserView [CHAR LIMIT=25] -->
+ <string name="abs__activity_chooser_view_see_all">See all...</string>
+ <!-- Title default for a dialog showing possible activities in ActivityChooserView [CHAR LIMIT=25] -->
+ <string name="abs__activity_chooser_view_dialog_title_default">Select activity</string>
+ <!-- Title for a dialog showing possible activities for sharing in ShareActionProvider [CHAR LIMIT=25] -->
+ <string name="abs__share_action_provider_share_with">Share with...</string>
+ <!-- Description of the shwoing of a popup window with activities to choose from. [CHAR LIMIT=NONE] -->
+ <string name="abs__activitychooserview_choose_application">Choose an application</string>
+ <!-- Description of the choose target button in a ShareActionProvider (share UI). [CHAR LIMIT=NONE] -->
+ <string name="abs__shareactionprovider_share_with">Share with</string>
+ <!-- Description of a share target (both in the list of such or the default share button) in a ShareActionProvider (share UI). [CHAR LIMIT=NONE] -->
+ <string name="abs__shareactionprovider_share_with_application">Share with <xliff:g id="application_name" example="Bluetooth">%s</xliff:g></string>
</resources>
diff --git a/com_actionbarsherlock/res/values/abs__styles.xml b/com_actionbarsherlock/res/values/abs__styles.xml
index 1d563c64f..8cbd36484 100644
--- a/com_actionbarsherlock/res/values/abs__styles.xml
+++ b/com_actionbarsherlock/res/values/abs__styles.xml
@@ -3,7 +3,7 @@
<resources>
<style name="Widget">
</style>
-
+
<style name="Sherlock.__Widget.ActionBar" parent="Widget">
<item name="displayOptions">useLogo|showHome|showTitle</item>
<item name="height">?attr/actionBarSize</item>
@@ -71,10 +71,10 @@
<item name="progressBarPadding">32dip</item>
<item name="itemPadding">8dip</item>
</style>
-
+
<style name="Widget.Sherlock.ActionBar.TabView" parent="Widget">
<item name="android:gravity">center_horizontal</item>
- <item name="android:background">@drawable/abs__tab_indicator_holo</item>
+ <item name="android:background">@drawable/abs__tab_indicator_ab_holo</item>
<item name="android:paddingLeft">16dip</item>
<item name="android:paddingRight">16dip</item>
</style>
@@ -82,7 +82,7 @@
</style>
<style name="Widget.Sherlock.Light.ActionBar.TabView.Inverse">
</style>
-
+
<style name="Widget.Sherlock.ActionBar.TabBar" parent="Widget">
<item name="android:divider">?attr/actionBarDivider</item>
<item name="android:showDividers">middle</item>
@@ -92,7 +92,7 @@
</style>
<style name="Widget.Sherlock.Light.ActionBar.TabBar.Inverse">
</style>
-
+
<style name="Widget.Sherlock.ActionBar.TabText" parent="Widget">
<item name="android:textAppearance">@null</item>
<item name="android:textColor">?attr/textColorPrimary</item>
@@ -111,8 +111,8 @@
<style name="Widget.Sherlock.ActionButton" parent="Widget">
<item name="android:background">?attr/actionBarItemBackground</item>
<item name="android:minHeight">?attr/actionBarSize</item>
-
- <item name="android:minWidth">56dip</item>
+
+ <item name="android:minWidth">@dimen/abs__action_button_min_width</item>
<item name="android:gravity">center</item>
<item name="android:paddingLeft">12dip</item>
<item name="android:paddingRight">12dip</item>
@@ -120,14 +120,14 @@
</style>
<style name="Widget.Sherlock.Light.ActionButton" parent="Widget.Sherlock.ActionButton">
</style>
-
+
<style name="Widget.Sherlock.ActionButton.CloseMode">
<item name="android:background">@drawable/abs__btn_cab_done_holo_dark</item>
</style>
<style name="Widget.Sherlock.Light.ActionButton.CloseMode">
<item name="android:background">@drawable/abs__btn_cab_done_holo_light</item>
</style>
-
+
<style name="Widget.Sherlock.ActionButton.Overflow">
<item name="android:src">@drawable/abs__ic_menu_moreoverflow_holo_dark</item>
<item name="android:background">?attr/actionBarItemBackground</item>
@@ -136,7 +136,7 @@
<style name="Widget.Sherlock.Light.ActionButton.Overflow">
<item name="android:src">@drawable/abs__ic_menu_moreoverflow_holo_light</item>
</style>
-
+
<style name="Sherlock.__Widget.ActionMode" parent="Widget">
<item name="background">?attr/actionModeBackground</item>
<item name="backgroundSplit">?attr/actionModeSplitBackground</item>
@@ -154,22 +154,53 @@
<item name="titleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionMode.Title.Inverse</item>
<item name="subtitleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionMode.Subtitle.Inverse</item>
</style>
-
-
- <style name="Widget.Sherlock.PopupMenu" parent="Widget">
+
+
+ <style name="Widget.Sherlock.ListPopupWindow" parent="Widget">
<item name="android:dropDownSelector">@drawable/abs__list_selector_holo_dark</item>
<item name="android:popupBackground">@drawable/abs__menu_dropdown_panel_holo_dark</item>
<item name="android:dropDownVerticalOffset">0dip</item>
<item name="android:dropDownHorizontalOffset">0dip</item>
<item name="android:dropDownWidth">wrap_content</item>
</style>
- <style name="Widget.Sherlock.Light.PopupMenu" parent="Widget">
+ <style name="Widget.Sherlock.Light.ListPopupWindow" parent="Widget">
<item name="android:dropDownSelector">@drawable/abs__list_selector_holo_light</item>
<item name="android:popupBackground">@drawable/abs__menu_dropdown_panel_holo_light</item>
<item name="android:dropDownVerticalOffset">0dip</item>
<item name="android:dropDownHorizontalOffset">0dip</item>
<item name="android:dropDownWidth">wrap_content</item>
</style>
+ <style name="Widget.Sherlock.PopupMenu" parent="Widget.Sherlock.ListPopupWindow">
+ </style>
+ <style name="Widget.Sherlock.Light.PopupMenu" parent="Widget.Sherlock.Light.ListPopupWindow">
+ </style>
+
+
+ <style name="Sherlock.__Widget.ActivityChooserView" parent="Widget">
+ <item name="android:gravity">center</item>
+ <item name="android:background">@drawable/abs__ab_share_pack_holo_dark</item>
+ <item name="android:divider">?attr/dividerVertical</item>
+ <item name="android:showDividers">middle</item>
+ <item name="android:dividerPadding">6dip</item>
+ </style>
+ <style name="Widget.Sherlock.ActivityChooserView" parent="Sherlock.__Widget.ActivityChooserView">
+ </style>
+ <style name="Widget.Sherlock.Light.ActivityChooserView" parent="Widget.Sherlock.ActivityChooserView">
+ <item name="android:background">@drawable/abs__ab_share_pack_holo_light</item>
+ </style>
+
+ <style name="Widget.Sherlock.Button.Small" parent="Widget">
+ <item name="android:textAppearance">?attr/textAppearanceSmall</item>
+ <item name="android:textColor">@color/abs__primary_text_holo_dark</item>
+ <item name="android:minHeight">48dip</item>
+ <item name="android:minWidth">48dip</item>
+ </style>
+ <style name="Widget.Sherlock.Light.Button.Small" parent="Widget">
+ <item name="android:textAppearance">?attr/textAppearanceSmall</item>
+ <item name="android:textColor">@color/abs__primary_text_holo_light</item>
+ <item name="android:minHeight">48dip</item>
+ <item name="android:minWidth">48dip</item>
+ </style>
<style name="Sherlock.__Widget.Holo.Spinner" parent="Widget">
@@ -190,7 +221,7 @@
<item name="android:dropDownSelector">@drawable/abs__list_selector_holo_light</item>
<item name="android:popupBackground">@drawable/abs__menu_dropdown_panel_holo_light</item>
</style>
-
+
<style name="Sherlock.__Widget.Holo.ListView" parent="android:Widget.ListView">
<item name="android:divider">@drawable/abs__list_divider_holo_dark</item>
<item name="android:listSelector">@drawable/abs__list_selector_holo_dark</item>
@@ -306,7 +337,7 @@
<item name="android:textSize">@dimen/abs__action_bar_subtitle_text_size</item>
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
</style>
-
+
<style name="TextAppearance.Sherlock.Widget.PopupMenu" parent="Widget">
<item name="android:textColor">?attr/textColorPrimary</item>
</style>
@@ -320,19 +351,19 @@
</style>
<style name="TextAppearance.Sherlock.Light.Widget.PopupMenu.Small" parent="TextAppearance.Sherlock.Widget.PopupMenu.Small">
</style>
-
+
<style name="TextAppearance.Sherlock.Widget.TextView.SpinnerItem" parent="Widget">
<item name="android:textColor">?textColorPrimary</item>
<item name="android:textSize">16sp</item>
<item name="android:textStyle">normal</item>
</style>
-
+
<style name="TextAppearance.Sherlock.Widget.DropDownItem" parent="Widget">
<item name="android:textColor">?textColorPrimaryDisableOnly</item>
<item name="android:textSize">16sp</item>
<item name="android:textStyle">normal</item>
</style>
-
+
<style name="TextAppearance.Sherlock.DialogWindowTitle" parent="Widget">
<item name="android:textSize">22sp</item>
<item name="android:textColor">@color/abs__holo_blue_light</item>
@@ -341,4 +372,13 @@
<item name="android:textSize">22sp</item>
<item name="android:textColor">@color/abs__holo_blue_light</item>
</style>
+
+ <style name="Sherlock.__TextAppearance.Small" parent="Widget">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+ <style name="TextAppearance.Sherlock.Small" parent="Sherlock.__TextAppearance.Small">
+ </style>
+ <style name="TextAppearance.Sherlock.Light.Small" parent="TextAppearance.Sherlock.Small">
+ </style>
</resources>
diff --git a/com_actionbarsherlock/res/values/abs__themes.xml b/com_actionbarsherlock/res/values/abs__themes.xml
index a7234ac8f..5300dedd6 100644
--- a/com_actionbarsherlock/res/values/abs__themes.xml
+++ b/com_actionbarsherlock/res/values/abs__themes.xml
@@ -36,6 +36,12 @@
<item name="actionMenuTextColor">?attr/textColorPrimary</item>
<item name="actionBarDivider">?attr/dividerVertical</item>
<item name="actionBarItemBackground">@drawable/abs__item_background_holo_dark</item>
+
+ <item name="buttonStyleSmall">@style/Widget.Sherlock.Button.Small</item>
+
+ <item name="activatedBackgroundIndicator">@drawable/abs__activated_background_holo_dark</item>
+ <item name="actionModeShareDrawable">@drawable/abs__ic_menu_share_holo_dark</item>
+ <item name="activityChooserViewStyle">@style/Widget.Sherlock.ActivityChooserView</item>
<item name="homeAsUpIndicator">@drawable/abs__ic_ab_back_holo_dark</item>
@@ -50,11 +56,13 @@
<!-- Internal --><item name="dropdownListPreferredItemHeight">48dip</item>
<item name="dropDownListViewStyle">@style/Widget.Sherlock.ListView.DropDown</item>
-
+
+ <item name="textAppearanceSmall">@style/TextAppearance.Sherlock.Small</item>
<item name="textAppearanceLargePopupMenu">@style/TextAppearance.Sherlock.Widget.PopupMenu.Large</item>
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Sherlock.Widget.PopupMenu.Small</item>
<item name="popupMenuStyle">@style/Widget.Sherlock.PopupMenu</item>
+ <!-- Internal --><item name="listPopupWindowStyle">@style/Widget.Sherlock.ListPopupWindow</item>
<item name="windowActionBar">true</item>
<item name="windowActionModeOverlay">false</item>
@@ -84,6 +92,12 @@
<item name="actionMenuTextColor">?attr/textColorPrimary</item>
<item name="actionBarDivider">?attr/dividerVertical</item>
<item name="actionBarItemBackground">@drawable/abs__item_background_holo_light</item>
+
+ <item name="buttonStyleSmall">@style/Widget.Sherlock.Light.Button.Small</item>
+
+ <item name="activatedBackgroundIndicator">@drawable/abs__activated_background_holo_light</item>
+ <item name="actionModeShareDrawable">@drawable/abs__ic_menu_share_holo_light</item>
+ <item name="activityChooserViewStyle">@style/Widget.Sherlock.Light.ActivityChooserView</item>
<item name="homeAsUpIndicator">@drawable/abs__ic_ab_back_holo_light</item>
@@ -98,11 +112,13 @@
<!-- Internal --><item name="dropdownListPreferredItemHeight">48dip</item>
<item name="dropDownListViewStyle">@style/Widget.Sherlock.Light.ListView.DropDown</item>
-
+
+ <item name="textAppearanceSmall">@style/TextAppearance.Sherlock.Light.Small</item>
<item name="textAppearanceLargePopupMenu">@style/TextAppearance.Sherlock.Light.Widget.PopupMenu.Large</item>
<item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Sherlock.Light.Widget.PopupMenu.Small</item>
<item name="popupMenuStyle">@style/Widget.Sherlock.Light.PopupMenu</item>
+ <!-- Internal --><item name="listPopupWindowStyle">@style/Widget.Sherlock.Light.ListPopupWindow</item>
<item name="windowActionBar">true</item>
<item name="windowActionModeOverlay">false</item>
@@ -125,10 +141,12 @@
<item name="actionBarTabTextStyle">@style/Widget.Sherlock.Light.ActionBar.TabText.Inverse</item>
<item name="actionBarDivider">@drawable/abs__list_divider_holo_dark</item>
<item name="actionBarItemBackground">@drawable/abs__item_background_holo_dark</item>
- <item name="actionMenuTextColor">?android:attr/textColorPrimaryInverse</item>
+ <item name="actionMenuTextColor">?attr/textColorPrimaryInverse</item>
<item name="actionModeStyle">@style/Widget.Sherlock.Light.ActionMode.Inverse</item>
<item name="actionModeCloseButtonStyle">@style/Widget.Sherlock.ActionButton.CloseMode</item>
<item name="actionModePopupWindowStyle">@style/Widget.Sherlock.PopupWindow.ActionMode</item>
+
+ <item name="actionModeShareDrawable">@drawable/abs__ic_menu_share_holo_dark</item>
</style>
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/ActionBarSherlock.java b/com_actionbarsherlock/src/com/actionbarsherlock/ActionBarSherlock.java
index 3dc3fd39e..a7cc25d3e 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/ActionBarSherlock.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/ActionBarSherlock.java
@@ -37,7 +37,6 @@ import com.actionbarsherlock.view.MenuItem;
* counterpart and you should refer to its documentation for instruction.</p>
*
* @author Jake Wharton <jakewharton@gmail.com>
- * @version 4.0.0
*/
public abstract class ActionBarSherlock {
protected static final String TAG = "ActionBarSherlock";
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockDialogFragment.java b/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockDialogFragment.java
index 0ec5833c3..4172888cc 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockDialogFragment.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockDialogFragment.java
@@ -34,7 +34,9 @@ public class SherlockDialogFragment extends DialogFragment {
if (DEBUG) Log.d(TAG, "[onCreateOptionsMenu] menu: " + menu + ", inflater: " + inflater);
if (menu instanceof MenuMule) {
- onCreateOptionsMenu(((MenuMule)menu).unwrap(), mActivity.getSupportMenuInflater());
+ MenuMule mule = (MenuMule)menu;
+ mule.mDispatchShow = true;
+ onCreateOptionsMenu(mule.unwrap(), mActivity.getSupportMenuInflater());
}
}
@@ -47,7 +49,9 @@ public class SherlockDialogFragment extends DialogFragment {
if (DEBUG) Log.d(TAG, "[onPrepareOptionsMenu] menu: " + menu);
if (menu instanceof MenuMule) {
- onPrepareOptionsMenu(((MenuMule)menu).unwrap());
+ MenuMule mule = (MenuMule)menu;
+ mule.mDispatchShow = true;
+ onPrepareOptionsMenu(mule.unwrap());
}
}
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockFragment.java b/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockFragment.java
index f02f5e433..10d673f9f 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockFragment.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockFragment.java
@@ -34,7 +34,9 @@ public class SherlockFragment extends Fragment {
if (DEBUG) Log.d(TAG, "[onCreateOptionsMenu] menu: " + menu + ", inflater: " + inflater);
if (menu instanceof MenuMule) {
- onCreateOptionsMenu(((MenuMule)menu).unwrap(), mActivity.getSupportMenuInflater());
+ MenuMule mule = (MenuMule)menu;
+ mule.mDispatchShow = true;
+ onCreateOptionsMenu(mule.unwrap(), mActivity.getSupportMenuInflater());
}
}
@@ -47,7 +49,9 @@ public class SherlockFragment extends Fragment {
if (DEBUG) Log.d(TAG, "[onPrepareOptionsMenu] menu: " + menu);
if (menu instanceof MenuMule) {
- onPrepareOptionsMenu(((MenuMule)menu).unwrap());
+ MenuMule mule = (MenuMule)menu;
+ mule.mDispatchShow = true;
+ onPrepareOptionsMenu(mule.unwrap());
}
}
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockFragmentActivity.java b/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockFragmentActivity.java
index 479235713..49a5c6ca9 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockFragmentActivity.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockFragmentActivity.java
@@ -1,7 +1,6 @@
package com.actionbarsherlock.app;
import android.content.res.Configuration;
-import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
@@ -30,7 +29,6 @@ public abstract class SherlockFragmentActivity extends FragmentActivity implemen
private boolean mIgnoreNativeCreate = false;
private boolean mIgnoreNativePrepare = false;
private boolean mIgnoreNativeSelected = false;
- private Boolean mOverrideNativeCreate = null;
protected final ActionBarSherlock getSherlock() {
if (mSherlock == null) {
@@ -138,7 +136,7 @@ public abstract class SherlockFragmentActivity extends FragmentActivity implemen
getSherlock().dispatchInvalidateOptionsMenu();
}
- protected void supportInvalidateOptionsMenu() {
+ public void supportInvalidateOptionsMenu() {
if (DEBUG) Log.d(TAG, "[supportInvalidateOptionsMenu]");
invalidateOptionsMenu();
@@ -161,7 +159,7 @@ public abstract class SherlockFragmentActivity extends FragmentActivity implemen
@Override
public final boolean onCreateOptionsMenu(android.view.Menu menu) {
- return (mOverrideNativeCreate != null) ? mOverrideNativeCreate.booleanValue() : true;
+ return true;
}
@Override
@@ -229,19 +227,17 @@ public abstract class SherlockFragmentActivity extends FragmentActivity implemen
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
boolean result = onCreateOptionsMenu(menu);
+ if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] activity create result: " + result);
//Dispatch to parent panel creation for fragment dispatching
if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] dispatching to native with mule");
- mOverrideNativeCreate = result;
- boolean fragResult = super.onCreatePanelMenu(featureId, new MenuMule(menu));
- mOverrideNativeCreate = null;
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
- result |= menu.hasVisibleItems();
- } else {
- result |= fragResult;
- }
+ MenuMule mule = new MenuMule(menu);
+ super.onCreatePanelMenu(featureId, mule);
+
+ if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] fragments create result: " + mule.mDispatchShow);
+ result |= mule.mDispatchShow;
+ if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] returning " + result);
return result;
}
return false;
@@ -257,11 +253,18 @@ public abstract class SherlockFragmentActivity extends FragmentActivity implemen
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
boolean result = onPrepareOptionsMenu(menu);
+ if (DEBUG) Log.d(TAG, "[onPreparePanel] activity prepare result: " + result);
//Dispatch to parent panel preparation for fragment dispatching
if (DEBUG) Log.d(TAG, "[onPreparePanel] dispatching to native with mule");
- super.onPreparePanel(featureId, view, new MenuMule(menu));
+ MenuMule mule = new MenuMule(menu);
+ super.onPreparePanel(featureId, view, mule);
+
+ if (DEBUG) Log.d(TAG, "[onPreparePanel] fragments prepare result: " + mule.mDispatchShow);
+ result |= mule.mDispatchShow;
+ result &= menu.hasVisibleItems();
+ if (DEBUG) Log.d(TAG, "[onPreparePanel] returning " + result);
return result;
}
return false;
@@ -276,13 +279,13 @@ public abstract class SherlockFragmentActivity extends FragmentActivity implemen
if (DEBUG) Log.d(TAG, "[onMenuItemSelected] featureId: " + featureId + ", item: " + item);
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
- boolean result = onOptionsItemSelected(item);
+ if (onOptionsItemSelected(item)) {
+ return true;
+ }
//Dispatch to parent panel selection for fragment dispatching
if (DEBUG) Log.d(TAG, "[onMenuItemSelected] dispatching to native with mule");
- result |= super.onMenuItemSelected(featureId, new MenuItemMule(item));
-
- return result;
+ return super.onMenuItemSelected(featureId, new MenuItemMule(item));
}
return false;
}
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockListFragment.java b/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockListFragment.java
index 4f6891e1b..03a312b35 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockListFragment.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/app/SherlockListFragment.java
@@ -34,7 +34,9 @@ public class SherlockListFragment extends ListFragment {
if (DEBUG) Log.d(TAG, "[onCreateOptionsMenu] menu: " + menu + ", inflater: " + inflater);
if (menu instanceof MenuMule) {
- onCreateOptionsMenu(((MenuMule)menu).unwrap(), mActivity.getSupportMenuInflater());
+ MenuMule mule = (MenuMule)menu;
+ mule.mDispatchShow = true;
+ onCreateOptionsMenu(mule.unwrap(), mActivity.getSupportMenuInflater());
}
}
@@ -47,7 +49,9 @@ public class SherlockListFragment extends ListFragment {
if (DEBUG) Log.d(TAG, "[onPrepareOptionsMenu] menu: " + menu);
if (menu instanceof MenuMule) {
- onPrepareOptionsMenu(((MenuMule)menu).unwrap());
+ MenuMule mule = (MenuMule)menu;
+ mule.mDispatchShow = true;
+ onPrepareOptionsMenu(mule.unwrap());
}
}
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java
index eab4d2153..f080bfe95 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java
@@ -71,6 +71,8 @@ public class ActionBarSherlockCompat extends ActionBarSherlock implements MenuBu
private MenuBuilder mMenu;
/** Map between native options items and sherlock items. */
protected HashMap<android.view.MenuItem, MenuItemImpl> mNativeItemMap;
+ /** Indication of a long-press on the hardware menu key. */
+ private boolean mMenuKeyIsLongPress = false;
/** Parent view of the window decoration (action bar, mode, etc.). */
private ViewGroup mDecor;
@@ -318,6 +320,10 @@ public class ActionBarSherlockCompat extends ActionBarSherlock implements MenuBu
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;
@@ -416,20 +422,27 @@ public class ActionBarSherlockCompat extends ActionBarSherlock implements MenuBu
}
}
- if (keyCode == KeyEvent.KEYCODE_MENU && event.getAction() == KeyEvent.ACTION_UP && isReservingOverflow()) {
- if (mActionMode == null) {
- if (wActionBar.isOverflowMenuShowing()) {
- wActionBar.hideOverflowMenu();
- } else {
- wActionBar.showOverflowMenu();
+ boolean result = false;
+ if (keyCode == KeyEvent.KEYCODE_MENU && isReservingOverflow()) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN && event.isLongPress()) {
+ mMenuKeyIsLongPress = true;
+ } else if (event.getAction() == KeyEvent.ACTION_UP) {
+ if (!mMenuKeyIsLongPress) {
+ if (mActionMode == null) {
+ if (wActionBar.isOverflowMenuShowing()) {
+ wActionBar.hideOverflowMenu();
+ } else {
+ wActionBar.showOverflowMenu();
+ }
+ }
+ result = true;
}
+ mMenuKeyIsLongPress = false;
}
- if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning true");
- return true;
}
- if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning false");
- return false;
+ if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning " + result);
+ return result;
}
@@ -964,7 +977,7 @@ public class ActionBarSherlockCompat extends ActionBarSherlock implements MenuBu
@Override
public void run() {
//Invalidate if the panel menu hasn't been created before this.
- if (mMenu == null) {
+ if (!mActivity.isFinishing() && mMenu == null) {
dispatchInvalidateOptionsMenu();
}
}
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java
index 74831a79e..9afca185a 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java
@@ -314,5 +314,15 @@ public class ActionBarSherlockNative extends ActionBarSherlock {
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/com_actionbarsherlock/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java
index 1fdb9278c..1bd0eaccb 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java
@@ -335,6 +335,12 @@ public class ActionBarWrapper extends ActionBar implements android.app.ActionBar
@Override
public void onTabSelected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) {
if (mListener != null) {
+
+ if (mFragmentTransaction == null && mActivity instanceof SherlockFragmentActivity) {
+ mFragmentTransaction = ((SherlockFragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
+ .disallowAddToBackStack();
+ }
+
mListener.onTabSelected(this, mFragmentTransaction);
if (mFragmentTransaction != null) {
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java
index 7de2352d4..3231080c4 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java
@@ -947,7 +947,7 @@ public final class AnimatorSet extends Animator {
public Node clone() {
try {
Node node = (Node) super.clone();
- node.animation = (Animator) animation.clone();
+ node.animation = animation.clone();
return node;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java
index 3a5659506..84f7504ab 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java
@@ -256,7 +256,7 @@ public class PropertyValuesHolder implements Cloneable {
else {
PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
pvh.mKeyframeSet = keyframeSet;
- pvh.mValueType = ((Keyframe)values[0]).getType();
+ pvh.mValueType = values[0].getType();
return pvh;
}
}
@@ -336,9 +336,9 @@ public class PropertyValuesHolder implements Cloneable {
public void setKeyframes(Keyframe... values) {
int numKeyframes = values.length;
Keyframe keyframes[] = new Keyframe[Math.max(numKeyframes,2)];
- mValueType = ((Keyframe)values[0]).getType();
+ mValueType = values[0].getType();
for (int i = 0; i < numKeyframes; ++i) {
- keyframes[i] = (Keyframe)values[i];
+ keyframes[i] = values[i];
}
mKeyframeSet = new KeyframeSet(keyframes);
}
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java
index 333d49e18..d8a12c688 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java
@@ -458,7 +458,7 @@ public class ValueAnimator extends Animator {
mValues = values;
mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
for (int i = 0; i < numValues; ++i) {
- PropertyValuesHolder valuesHolder = (PropertyValuesHolder) values[i];
+ PropertyValuesHolder valuesHolder = values[i];
mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
}
// New property/values/target should cause re-initialization prior to starting
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.java
new file mode 100644
index 000000000..129b5aaaa
--- /dev/null
+++ b/com_actionbarsherlock/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/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java
index 020b41d32..6f568c698 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java
@@ -130,7 +130,13 @@ public class ActionMenuPresenter extends BaseMenuPresenter
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB);
} else {
- return !ViewConfiguration.get(context).hasPermanentMenuKey();
+ return !HasPermanentMenuKey.get(context);
+ }
+ }
+
+ private static class HasPermanentMenuKey {
+ public static boolean get(Context context) {
+ return ViewConfiguration.get(context).hasPermanentMenuKey();
}
}
@@ -299,7 +305,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter
*/
public boolean showOverflowMenu() {
if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null &&
- mPostedOpenRunnable == 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.
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java
index 40ab73c50..e090677a1 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java
@@ -417,9 +417,9 @@ public class ActionMenuView extends IcsLinearLayout implements MenuBuilder.ItemI
final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
//UNUSED nonOverflowWidth += size;
widthRemaining -= size;
- if (hasDividerBeforeChildAt(i)) {
+ //if (hasDividerBeforeChildAt(i)) {
//UNUSED nonOverflowWidth += dividerWidth;
- }
+ //}
nonOverflowCount++;
}
}
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java
index d923c4ef8..907a7aa04 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java
@@ -9,11 +9,12 @@ import com.actionbarsherlock.view.ActionProvider;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.SubMenu;
-public class MenuItemWrapper implements MenuItem, android.view.MenuItem.OnMenuItemClickListener, android.view.MenuItem.OnActionExpandListener {
+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) {
@@ -262,24 +263,30 @@ public class MenuItemWrapper implements MenuItem, android.view.MenuItem.OnMenuIt
@Override
public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
mActionExpandListener = listener;
- //Register ourselves as the listener to proxy
- mNativeItem.setOnActionExpandListener(this);
- return this;
- }
- @Override
- public boolean onMenuItemActionCollapse(android.view.MenuItem item) {
- if (mActionExpandListener != null) {
- return mActionExpandListener.onMenuItemActionCollapse(this);
+ 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 false;
- }
- @Override
- public boolean onMenuItemActionExpand(android.view.MenuItem item) {
- if (mActionExpandListener != null) {
- return mActionExpandListener.onMenuItemActionExpand(this);
- }
- return false;
+ return this;
}
}
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/MenuMule.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/MenuMule.java
index 183e87a56..b2385b904 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/MenuMule.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/view/menu/MenuMule.java
@@ -15,6 +15,7 @@ public class MenuMule implements Menu {
private final com.actionbarsherlock.view.Menu mMenu;
+ public boolean mDispatchShow = false;
public MenuMule(com.actionbarsherlock.view.Menu menu) {
mMenu = menu;
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/ActionBarView.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/ActionBarView.java
index ae6035892..4636de17f 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/ActionBarView.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/ActionBarView.java
@@ -132,7 +132,7 @@ public class ActionBarView extends AbsActionBarView {
private SpinnerAdapter mSpinnerAdapter;
private OnNavigationListener mCallback;
- private Runnable mTabSelector;
+ //UNUSED private Runnable mTabSelector;
private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
View mExpandedActionView;
@@ -250,7 +250,7 @@ public class ActionBarView extends AbsActionBarView {
final int customNavId = a.getResourceId(R.styleable.SherlockActionBar_customNavigationLayout, 0);
if (customNavId != 0) {
- mCustomNavView = (View) inflater.inflate(customNavId, this, false);
+ mCustomNavView = inflater.inflate(customNavId, this, false);
mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD;
setDisplayOptions(mDisplayOptions | ActionBar.DISPLAY_SHOW_CUSTOM);
}
@@ -383,7 +383,7 @@ public class ActionBarView extends AbsActionBarView {
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
- removeCallbacks(mTabSelector);
+ //UNUSED removeCallbacks(mTabSelector);
if (mActionMenuPresenter != null) {
mActionMenuPresenter.hideOverflowMenu();
mActionMenuPresenter.hideSubMenus();
@@ -825,7 +825,7 @@ public class ActionBarView extends AbsActionBarView {
this, false);
mTitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_title);
mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_subtitle);
- mTitleUpView = (View) mTitleLayout.findViewById(R.id.abs__up);
+ mTitleUpView = mTitleLayout.findViewById(R.id.abs__up);
mTitleLayout.setOnClickListener(mUpClickListener);
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java
index 1067b4191..673ec554f 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java
@@ -18,6 +18,10 @@ public class CapitalizingTextView extends TextView {
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);
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java
index 2edda7264..1b4463a59 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java
@@ -10,7 +10,10 @@ import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
/**
* A simple extension of a regular linear layout that supports the divider API
- * of Android 4.0+.
+ * 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[] LinearLayout = new int[] {
@@ -42,6 +45,7 @@ public class IcsLinearLayout extends NineLinearLayout {
private Drawable mDivider;
private int mDividerWidth;
+ private int mDividerHeight;
private int mShowDividers;
private int mDividerPadding;
@@ -59,6 +63,29 @@ public class IcsLinearLayout extends NineLinearLayout {
}
/**
+ * 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)
@@ -70,14 +97,40 @@ public class IcsLinearLayout extends NineLinearLayout {
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.
@@ -89,9 +142,27 @@ public class IcsLinearLayout extends NineLinearLayout {
@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)) {
- //Account for the divider by pushing everything left
- ((LayoutParams)child.getLayoutParams()).leftMargin = mDividerWidth;
+ 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);
}
@@ -99,32 +170,73 @@ public class IcsLinearLayout extends NineLinearLayout {
@Override
protected void onDraw(Canvas canvas) {
if (mDivider != null) {
- 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;
- drawVerticalDivider(canvas, left);
- }
+ 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);
+ }
+ }
- if (hasDividerBeforeChildAt(count)) {
- final View child = getChildAt(count - 1);
- int right = 0;
- if (child == null) {
- right = getWidth() - getPaddingRight() - mDividerWidth;
- } else {
+ 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();
- right = child.getRight() + lp.rightMargin;
+ final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;
+ drawVerticalDivider(canvas, left);
}
- drawVerticalDivider(canvas, right);
}
}
- super.onDraw(canvas);
+ 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) {
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java
index e06bcb1c4..d13c6cea9 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java
@@ -74,6 +74,10 @@ public class IcsListPopupWindow {
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);
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsSpinner.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsSpinner.java
index 319c9ab83..038d1e031 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsSpinner.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/IcsSpinner.java
@@ -78,6 +78,10 @@ public class IcsSpinner extends IcsAbsSpinner implements OnClickListener {
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.
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java
index 82b72d8e2..1a532e06c 100644
--- a/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java
@@ -29,7 +29,6 @@ import android.view.ViewParent;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.BaseAdapter;
-import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
@@ -37,12 +36,13 @@ 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 HorizontalScrollView
+public class ScrollingTabContainerView extends NineHorizontalScrollView
implements IcsAdapterView.OnItemSelectedListener {
//UNUSED private static final String TAG = "ScrollingTabContainerView";
Runnable mTabSelector;
diff --git a/com_actionbarsherlock/src/com/actionbarsherlock/widget/ActivityChooserModel.java b/com_actionbarsherlock/src/com/actionbarsherlock/widget/ActivityChooserModel.java
new file mode 100644
index 000000000..379207471
--- /dev/null
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/widget/ActivityChooserModel.java
@@ -0,0 +1,1131 @@
+/*
+ * 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.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+
+/**
+ * <p>
+ * 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.
+ * <p>
+ * </p>
+ * 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.
+ * </p>
+ * <p>
+ * The way clients interact with this class is as follows:
+ * </p>
+ * <p>
+ * <pre>
+ * <code>
+ * // 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);
+ * <pre>
+ * <code>
+ * </p>
+ * <p>
+ * <strong>Note:</strong> This class is thread safe.
+ * </p>
+ *
+ * @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 <code>activities</code> 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<ActivityResolveInfo> activities,
+ List<HistoricalRecord> 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.
+ * <p>
+ * <strong>Note:</strong> Modifying the intent is not permitted and
+ * any changes to the latter will be ignored.
+ * </p>
+ *
+ * @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<String, ActivityChooserModel> sDataModelRegistry =
+ new HashMap<String, ActivityChooserModel>();
+
+ /**
+ * Lock for synchronizing on this instance.
+ */
+ private final Object mInstanceLock = new Object();
+
+ /**
+ * List of activities that can handle the current intent.
+ */
+ private final List<ActivityResolveInfo> mActivites = new ArrayList<ActivityResolveInfo>();
+
+ /**
+ * List with historical choice records.
+ */
+ private final List<HistoricalRecord> mHistoricalRecords = new ArrayList<HistoricalRecord>();
+
+ /**
+ * 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.
+ * <p>
+ * <strong>Note:</strong> 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 <code>null</code> for the file name. In such
+ * case a new model is returned for each invocation.
+ * </p>
+ *
+ * <p>
+ * <strong>Always use difference historical data files for semantically different actions.
+ * For example, sharing is different from importing.</strong>
+ * </p>
+ *
+ * @param context Context for loading resources.
+ * @param historyFileName File name with choice history, <code>null</code>
+ * 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.
+ * <p>
+ * <strong>Note:</strong> Clients must set only semantically similar
+ * intents for each data model.
+ * <p>
+ *
+ * @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<ActivityResolveInfo> 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.
+ * <p>
+ * <strong>Note:</strong> 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.
+ * </p>
+ *
+ * @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, <code>null</code> 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.
+ * <p>
+ * <strong>Note:</strong> 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.
+ * <p>
+ */
+ 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 SerialExecutor SERIAL_EXECUTOR = new SerialExecutor();
+
+ private static class SerialExecutor implements Executor {
+ final LinkedList<Runnable> mTasks = new LinkedList<Runnable>();
+ Runnable mActive;
+
+ public synchronized void execute(final Runnable r) {
+ mTasks.offer(new Runnable() {
+ public void run() {
+ try {
+ r.run();
+ } finally {
+ scheduleNext();
+ }
+ }
+ });
+ if (mActive == null) {
+ scheduleNext();
+ }
+ }
+
+ protected synchronized void scheduleNext() {
+ if ((mActive = mTasks.poll()) != null) {
+ mActive.run();
+ }
+ }
+ }
+
+ /**
+ * 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}
+ * <p>
+ * <strong>Note:</strong> 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.
+ * </p>
+ *
+ * @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<HistoricalRecord> 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<ResolveInfo> 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<ActivityResolveInfo> {
+
+ /**
+ * 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<String, ActivityResolveInfo> mPackageNameToActivityMap =
+ new HashMap<String, ActivityResolveInfo>();
+
+ public void sort(Intent intent, List<ActivityResolveInfo> activities,
+ List<HistoricalRecord> historicalRecords) {
+ Map<String, ActivityResolveInfo> 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<HistoricalRecord> readRecords = new ArrayList<HistoricalRecord>();
+
+ 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<HistoricalRecord> uniqueShareRecords =
+ new LinkedHashSet<HistoricalRecord>(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<HistoricalRecord> 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<HistoricalRecord> records = null;
+
+ synchronized (mInstanceLock) {
+ records = new ArrayList<HistoricalRecord>(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/com_actionbarsherlock/src/com/actionbarsherlock/widget/ActivityChooserView.java b/com_actionbarsherlock/src/com/actionbarsherlock/widget/ActivityChooserView.java
new file mode 100644
index 000000000..da13bc99f
--- /dev/null
+++ b/com_actionbarsherlock/src/com/actionbarsherlock/widget/ActivityChooserView.java
@@ -0,0 +1,818 @@
+/*
+ * 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}.
+ * <p>
+ * The view is composed of two adjacent buttons:
+ * <ul>
+ * <li>
+ * 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.
+ * </li>
+ * <li>
+ * 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.
+ * </li>
+ * </ul>
+ * </p>
+ *
+ * @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.
+ *
+ * <strong>Note:</strong> 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) {
+ dataModel.unregisterObserver(mModelDataSetOberver);
+ }
+ 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);
+ }
+ }
+
+ /**
+ * 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()) {
+ oldDataModel.unregisterObserver(mModelDataSetOberver);
+ }
+ 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/com_actionbarsherlock/src/com/actionbarsherlock/widget/ShareActionProvider.java b/com_actionbarsherlock/src/com/actionbarsherlock/widget/ShareActionProvider.java
new file mode 100644
index 000000000..83e9f0ca9
--- /dev/null
+++ b/com_actionbarsherlock/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.
+ * <p>
+ * Here is how to use the action provider with custom backing file in a {@link MenuItem}:
+ * </p>
+ * <p>
+ * <pre>
+ * <code>
+ * // 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);
+ * }
+ * </pre>
+ * </code>
+ * </p>
+ * <p>
+ * <strong>Note:</strong> 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.
+ * </p>
+ *
+ * @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.
+ * <p>
+ * <strong>Note:</strong> Modifying the intent is not permitted and
+ * any changes to the latter will be ignored.
+ * </p>
+ *
+ * @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.
+ * <p>
+ * <strong>Note:</strong> If you choose the backing share history file
+ * you will still be notified in this callback.
+ * </p>
+ * @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 <code>null</code>
+ * if share history should not be persisted between sessions.
+ * <p>
+ * <strong>Note:</strong> 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.
+ * <p>
+ *
+ * @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:
+ * <p>
+ * <pre>
+ * <code>
+ * 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());
+ * </pre>
+ * </code>
+ * </p>
+ *
+ * @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;
+ }
+ }
+}